15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
from fetch import greedy_fetch
24
23
import bzrlib.osutils
25
24
import bzrlib.revision
26
25
from bzrlib.merge_core import merge_flex, ApplyMerge3, BackupBeforeChange
27
26
from bzrlib.changeset import generate_changeset, ExceptionConflictHandler
28
from bzrlib.changeset import Inventory, Diff3Merge
29
from bzrlib.branch import find_branch
30
from bzrlib.errors import BzrCommandError, UnrelatedBranches
27
from bzrlib.changeset import Inventory, Diff3Merge, ReplaceContents
28
from bzrlib.branch import Branch
29
from bzrlib.errors import BzrCommandError, UnrelatedBranches, NoCommonAncestor
30
from bzrlib.errors import NoCommits
31
31
from bzrlib.delta import compare_trees
32
32
from bzrlib.trace import mutter, warning
33
from bzrlib.fetch import greedy_fetch
33
from bzrlib.fetch import greedy_fetch, fetch
34
34
from bzrlib.revision import is_ancestor
35
from bzrlib.osutils import rename
36
from bzrlib.revision import common_ancestor, MultipleRevisionSources
37
from bzrlib.errors import NoSuchRevision
36
40
# comments from abentley on irc: merge happens in two stages, each
37
41
# of which generates a changeset object
46
50
conflict that are not explicitly handled cause an exception and
47
51
terminate the merge.
49
def __init__(self, dir, ignore_zero=False):
50
ExceptionConflictHandler.__init__(self, dir)
53
def __init__(self, ignore_zero=False):
54
ExceptionConflictHandler.__init__(self)
52
56
self.ignore_zero = ignore_zero
107
111
self.add_suffix(this_path, ".THIS")
108
112
self.dump(base_lines, this_path+".BASE")
109
113
self.dump(other_lines, this_path+".OTHER")
110
os.rename(new_file, this_path)
114
rename(new_file, this_path)
111
115
self.conflict("Diff3 conflict encountered in %s" % this_path)
113
117
def new_contents_conflict(self, filename, other_contents):
134
def rem_contents_conflict(self, filename, this_contents, base_contents):
135
base_contents(filename+".BASE", self, False)
136
this_contents(filename+".THIS", self, False)
137
return ReplaceContents(this_contents, None)
130
139
def finalize(self):
131
140
if not self.ignore_zero:
132
141
print "%d conflicts encountered.\n" % self.conflicts
134
143
def get_tree(treespec, temp_root, label, local_branch=None):
135
144
location, revno = treespec
136
branch = find_branch(location)
145
branch = Branch.open_containing(location)
137
146
if revno is None:
139
148
elif revno == -1:
140
revision = branch.last_patch()
149
revision = branch.last_revision()
142
revision = branch.lookup_revision(revno)
151
revision = branch.get_rev_id(revno)
143
152
return branch, get_revid_tree(branch, revision, temp_root, label,
235
244
If true, this_dir must have no uncommitted changes before the
237
all available ancestors of other_revision and base_revision are
247
All available ancestors of other_revision and base_revision are
238
248
automatically pulled into the branch.
240
from bzrlib.revision import common_ancestor, MultipleRevisionSources
241
from bzrlib.errors import NoSuchRevision
242
250
tempdir = tempfile.mkdtemp(prefix="bzr-")
244
252
if this_dir is None:
246
this_branch = find_branch(this_dir)
247
this_rev_id = this_branch.last_patch()
254
this_branch = Branch.open_containing(this_dir)
255
this_rev_id = this_branch.last_revision()
248
256
if this_rev_id is None:
249
257
raise BzrCommandError("This branch has no commits")
255
263
other_branch, other_tree = get_tree(other_revision, tempdir, "other",
257
265
if other_revision[1] == -1:
258
other_rev_id = other_branch.last_patch()
266
other_rev_id = other_branch.last_revision()
267
if other_rev_id is None:
268
raise NoCommits(other_branch)
259
269
other_basis = other_rev_id
260
270
elif other_revision[1] is not None:
261
other_rev_id = other_branch.lookup_revision(other_revision[1])
271
other_rev_id = other_branch.get_rev_id(other_revision[1])
262
272
other_basis = other_rev_id
264
274
other_rev_id = None
265
other_basis = other_branch.last_patch()
275
other_basis = other_branch.last_revision()
276
if other_basis is None:
277
raise NoCommits(other_branch)
266
278
if base_revision == [None, None]:
267
base_rev_id = common_ancestor(this_rev_id, other_basis,
269
if base_rev_id is None:
280
base_rev_id = common_ancestor(this_rev_id, other_basis,
282
except NoCommonAncestor:
270
283
raise UnrelatedBranches()
271
284
base_tree = get_revid_tree(this_branch, base_rev_id, tempdir,
275
288
base_branch, base_tree = get_tree(base_revision, tempdir, "base")
276
289
if base_revision[1] == -1:
277
base_rev_id = base_branch.last_patch()
290
base_rev_id = base_branch.last_revision()
278
291
elif base_revision[1] is None:
279
292
base_rev_id = None
281
base_rev_id = base_branch.lookup_revision(base_revision[1])
282
if base_rev_id is not None:
283
base_is_ancestor = is_ancestor(this_rev_id, base_rev_id,
284
MultipleRevisionSources(this_branch,
287
base_is_ancestor = False
294
base_rev_id = base_branch.get_rev_id(base_revision[1])
295
fetch(from_branch=base_branch, to_branch=this_branch)
296
base_is_ancestor = is_ancestor(this_rev_id, base_rev_id,
288
298
if file_list is None:
289
299
interesting_ids = None
347
357
inv_changes = merge_flex(this_tree, base_tree, other_tree,
348
358
generate_cset_optimized, get_inventory,
349
MergeConflictHandler(base_tree.root,
350
ignore_zero=ignore_zero),
359
MergeConflictHandler(ignore_zero=ignore_zero),
351
360
merge_factory=merge_factory,
352
361
interesting_ids=interesting_ids)
360
assert path.startswith('./'), "path is %s" % path
369
assert path.startswith('.' + os.sep), "path is %s" % path
362
371
adjust_ids.append((path, id))
363
372
if len(adjust_ids) > 0: