59
60
return tree.branch, tree
60
61
branch = Branch.open_containing(location)[0]
62
revision = branch.last_revision()
63
revision_id = branch.last_revision()
64
revision = branch.get_rev_id(revno)
66
revision = NULL_REVISION
67
return branch, _get_revid_tree(branch, revision, local_branch)
70
def _get_revid_tree(branch, revision, local_branch):
65
revision_id = branch.get_rev_id(revno)
66
if revision_id is None:
67
revision_id = NULL_REVISION
68
return branch, _get_revid_tree(branch, revision_id, local_branch)
71
def _get_revid_tree(branch, revision_id, local_branch):
72
if revision_id is None:
72
73
base_tree = branch.bzrdir.open_workingtree()
74
75
if local_branch is not None:
75
76
if local_branch.base != branch.base:
76
local_branch.fetch(branch, revision)
77
base_tree = local_branch.repository.revision_tree(revision)
77
local_branch.fetch(branch, revision_id)
78
base_tree = local_branch.repository.revision_tree(revision_id)
79
base_tree = branch.repository.revision_tree(revision)
80
base_tree = branch.repository.revision_tree(revision_id)
84
def _get_revid_tree_from_tree(tree, revision_id, local_branch):
85
if revision_id is None:
87
if local_branch is not None:
88
if local_branch.base != tree.branch.base:
89
local_branch.fetch(tree.branch, revision_id)
90
return local_branch.repository.revision_tree(revision_id)
91
return tree.branch.repository.revision_tree(revision_id)
83
94
def transform_tree(from_tree, to_tree, interesting_ids=None):
84
95
merge_inner(from_tree.branch, to_tree, from_tree, ignore_zero=True,
85
96
interesting_ids=interesting_ids, this_tree=from_tree)
88
99
class Merger(object):
89
def __init__(self, this_branch, other_tree=None, base_tree=None,
90
this_tree=None, pb=DummyProgress()):
100
def __init__(self, this_branch, other_tree=None, base_tree=None,
101
this_tree=None, pb=DummyProgress(), change_reporter=None,
91
103
object.__init__(self)
92
104
assert this_tree is not None, "this_tree is required"
93
105
self.this_branch = this_branch
97
109
self.this_revision_tree = None
98
110
self.this_basis_tree = None
99
111
self.other_tree = other_tree
112
self.other_branch = None
100
113
self.base_tree = base_tree
101
114
self.ignore_zero = False
102
115
self.backup_files = False
103
116
self.interesting_ids = None
104
117
self.show_base = False
105
118
self.reprocess = False
121
self.recurse = recurse
122
self.change_reporter = change_reporter
110
124
def revision_tree(self, revision_id):
111
125
return self.this_branch.repository.revision_tree(revision_id)
142
156
def check_basis(self, check_clean, require_commits=True):
143
157
if self.this_basis is None and require_commits is True:
144
raise BzrCommandError("This branch has no commits")
158
raise BzrCommandError("This branch has no commits."
159
" (perhaps you would prefer 'bzr pull')")
146
161
self.compare_basis()
147
162
if self.this_basis != self.this_rev_id:
168
183
interesting_ids = set()
169
184
for path in file_list:
186
# TODO: jam 20070226 The trees are not locked at this time,
187
# wouldn't it make merge faster if it locks everything in the
188
# beginning? It locks at do_merge time, but this happens
171
190
for tree in (self.this_tree, self.base_tree, self.other_tree):
172
file_id = tree.inventory.path2id(path)
191
file_id = tree.path2id(path)
173
192
if file_id is not None:
174
193
interesting_ids.add(file_id)
195
214
:param other_revision: The [path, revision] list to merge from.
197
other_branch, self.other_tree = _get_tree(other_revision,
216
self.other_branch, self.other_tree = _get_tree(other_revision,
198
217
self.this_branch)
199
218
if other_revision[1] == -1:
200
self.other_rev_id = other_branch.last_revision()
219
self.other_rev_id = self.other_branch.last_revision()
201
220
if self.other_rev_id is None:
202
raise NoCommits(other_branch)
221
raise NoCommits(self.other_branch)
203
222
self.other_basis = self.other_rev_id
204
223
elif other_revision[1] is not None:
205
self.other_rev_id = other_branch.get_rev_id(other_revision[1])
224
self.other_rev_id = self.other_branch.get_rev_id(other_revision[1])
206
225
self.other_basis = self.other_rev_id
208
227
self.other_rev_id = None
209
self.other_basis = other_branch.last_revision()
228
self.other_basis = self.other_branch.last_revision()
210
229
if self.other_basis is None:
211
raise NoCommits(other_branch)
212
if other_branch.base != self.this_branch.base:
213
self.this_branch.fetch(other_branch, last_revision=self.other_basis)
230
raise NoCommits(self.other_branch)
231
if self.other_branch.base != self.this_branch.base:
232
self.this_branch.fetch(self.other_branch,
233
last_revision=self.other_basis)
235
def set_other_revision(self, revision_id, other_branch):
236
"""Set 'other' based on a branch and revision id
238
:param revision_id: The revision to use for a tree
239
:param other_branch: The branch containing this tree
241
self.other_rev_id = revision_id
242
self.other_branch = other_branch
243
self.this_branch.fetch(other_branch, self.other_rev_id)
244
self.other_tree = self.revision_tree(revision_id)
245
self.other_basis = revision_id
215
247
def find_base(self):
216
248
self.set_base([None, None])
234
266
except NoCommonAncestor:
235
267
raise UnrelatedBranches()
236
self.base_tree = _get_revid_tree(self.this_branch, self.base_rev_id,
268
self.base_tree = _get_revid_tree_from_tree(self.this_tree,
238
271
self.base_is_ancestor = True
240
273
base_branch, self.base_tree = _get_tree(base_revision)
251
284
self.this_branch)
253
286
def do_merge(self):
254
kwargs = {'working_tree':self.this_tree, 'this_tree': self.this_tree,
255
'other_tree': self.other_tree,
287
kwargs = {'working_tree':self.this_tree, 'this_tree': self.this_tree,
288
'other_tree': self.other_tree,
256
289
'interesting_ids': self.interesting_ids,
258
291
if self.merge_type.requires_base:
267
300
elif self.show_base:
268
301
raise BzrError("Showing base is not supported for this"
269
302
" merge type. %s" % self.merge_type)
270
merge = self.merge_type(pb=self._pb, **kwargs)
303
self.this_tree.lock_tree_write()
304
if self.base_tree is not None:
305
self.base_tree.lock_read()
306
if self.other_tree is not None:
307
self.other_tree.lock_read()
309
merge = self.merge_type(pb=self._pb,
310
change_reporter=self.change_reporter,
312
if self.recurse == 'down':
313
for path, file_id in self.this_tree.iter_references():
314
sub_tree = self.this_tree.get_nested_tree(file_id, path)
315
other_revision = self.other_tree.get_reference_revision(
317
if other_revision == sub_tree.last_revision():
319
sub_merge = Merger(sub_tree.branch, this_tree=sub_tree)
320
sub_merge.merge_type = self.merge_type
321
relpath = self.this_tree.relpath(path)
322
other_branch = self.other_branch.reference_parent(file_id, relpath)
323
sub_merge.set_other_revision(other_revision, other_branch)
324
base_revision = self.base_tree.get_reference_revision(file_id)
325
sub_merge.base_tree = \
326
sub_tree.branch.repository.revision_tree(base_revision)
330
if self.other_tree is not None:
331
self.other_tree.unlock()
332
if self.base_tree is not None:
333
self.base_tree.unlock()
334
self.this_tree.unlock()
271
335
if len(merge.cooked_conflicts) == 0:
272
336
if not self.ignore_zero:
273
337
note("All changes applied successfully.")
356
420
def __init__(self, working_tree, this_tree, base_tree, other_tree,
357
421
interesting_ids=None, reprocess=False, show_base=False,
358
pb=DummyProgress(), pp=None):
422
pb=DummyProgress(), pp=None, change_reporter=None):
359
423
"""Initialize the merger object and perform the merge."""
360
424
object.__init__(self)
361
425
self.this_tree = working_tree
426
self.this_tree.lock_tree_write()
362
427
self.base_tree = base_tree
428
self.base_tree.lock_read()
363
429
self.other_tree = other_tree
430
self.other_tree.lock_read()
364
431
self._raw_conflicts = []
365
432
self.cooked_conflicts = []
366
433
self.reprocess = reprocess
367
434
self.show_base = show_base
437
self.change_reporter = change_reporter
370
438
if self.pp is None:
371
439
self.pp = ProgressPhase("Merge phase", 3, self.pb)
572
644
parent_id = self.tt.final_parent(trans_id)
573
645
if file_id in self.this_tree.inventory:
574
646
self.tt.unversion_file(trans_id)
575
self.tt.delete_contents(trans_id)
647
if file_id in self.this_tree:
648
self.tt.delete_contents(trans_id)
576
649
file_group = self._dump_conflicts(name, parent_id, file_id,
577
650
set_version=True)
578
651
self._raw_conflicts.append(('contents conflict', file_group))
818
891
def __init__(self, working_tree, this_tree, base_tree, other_tree,
819
892
interesting_ids=None, pb=DummyProgress(), pp=None,
893
reprocess=False, change_reporter=None):
821
894
self.this_revision_tree = self._get_revision_tree(this_tree)
822
895
self.other_revision_tree = self._get_revision_tree(other_tree)
823
896
super(WeaveMerger, self).__init__(working_tree, this_tree,
824
897
base_tree, other_tree,
825
898
interesting_ids=interesting_ids,
826
pb=pb, pp=pp, reprocess=reprocess)
899
pb=pb, pp=pp, reprocess=reprocess,
900
change_reporter=change_reporter)
828
902
def _get_revision_tree(self, tree):
829
903
"""Return a revision tree related to this tree.
938
1013
branch.get_revision_tree(base_revision))'
940
1015
if this_tree is None:
941
warnings.warn("bzrlib.merge.merge_inner requires a this_tree parameter as of "
942
"bzrlib version 0.8.",
945
this_tree = this_branch.bzrdir.open_workingtree()
946
merger = Merger(this_branch, other_tree, base_tree, this_tree=this_tree,
1016
raise BzrError("bzrlib.merge.merge_inner requires a this_tree "
1017
"parameter as of bzrlib version 0.8.")
1018
merger = Merger(this_branch, other_tree, base_tree, this_tree=this_tree,
1019
pb=pb, change_reporter=change_reporter)
948
1020
merger.backup_files = backup_files
949
1021
merger.merge_type = merge_type
950
1022
merger.interesting_ids = interesting_ids
959
1031
merger.other_basis = other_rev_id
960
1032
return merger.do_merge()
963
merge_types = { "merge3": (Merge3Merger, "Native diff3-style merge"),
964
"diff3": (Diff3Merger, "Merge using external diff3"),
965
'weave': (WeaveMerger, "Weave-based merge")
969
def merge_type_help():
970
templ = '%s%%7s: %%s' % (' '*12)
971
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
972
return '\n'.join(lines)
1034
def get_merge_type_registry():
1035
"""Merge type registry is in bzrlib.option to avoid circular imports.
1037
This method provides a sanctioned way to retrieve it.
1039
from bzrlib import option
1040
return option._merge_type_registry