89
89
class Merger(object):
90
def __init__(self, this_branch, other_tree=None, base_tree=None,
91
this_tree=None, pb=DummyProgress(), change_reporter=None):
90
def __init__(self, this_branch, other_tree=None, base_tree=None,
91
this_tree=None, pb=DummyProgress(), change_reporter=None,
92
93
object.__init__(self)
93
94
assert this_tree is not None, "this_tree is required"
94
95
self.this_branch = this_branch
98
99
self.this_revision_tree = None
99
100
self.this_basis_tree = None
100
101
self.other_tree = other_tree
102
self.other_branch = None
101
103
self.base_tree = base_tree
102
104
self.ignore_zero = False
103
105
self.backup_files = False
104
106
self.interesting_ids = None
105
107
self.show_base = False
106
108
self.reprocess = False
111
self.recurse = recurse
109
112
self.change_reporter = change_reporter
111
114
def revision_tree(self, revision_id):
170
173
interesting_ids = set()
171
174
for path in file_list:
176
# TODO: jam 20070226 The trees are not locked at this time,
177
# wouldn't it make merge faster if it locks everything in the
178
# beginning? It locks at do_merge time, but this happens
173
180
for tree in (self.this_tree, self.base_tree, self.other_tree):
174
file_id = tree.inventory.path2id(path)
181
file_id = tree.path2id(path)
175
182
if file_id is not None:
176
183
interesting_ids.add(file_id)
197
204
:param other_revision: The [path, revision] list to merge from.
199
other_branch, self.other_tree = _get_tree(other_revision,
206
self.other_branch, self.other_tree = _get_tree(other_revision,
200
207
self.this_branch)
201
208
if other_revision[1] == -1:
202
self.other_rev_id = other_branch.last_revision()
209
self.other_rev_id = self.other_branch.last_revision()
203
210
if self.other_rev_id is None:
204
raise NoCommits(other_branch)
211
raise NoCommits(self.other_branch)
205
212
self.other_basis = self.other_rev_id
206
213
elif other_revision[1] is not None:
207
self.other_rev_id = other_branch.get_rev_id(other_revision[1])
214
self.other_rev_id = self.other_branch.get_rev_id(other_revision[1])
208
215
self.other_basis = self.other_rev_id
210
217
self.other_rev_id = None
211
self.other_basis = other_branch.last_revision()
218
self.other_basis = self.other_branch.last_revision()
212
219
if self.other_basis is None:
213
raise NoCommits(other_branch)
214
if other_branch.base != self.this_branch.base:
215
self.this_branch.fetch(other_branch, last_revision=self.other_basis)
220
raise NoCommits(self.other_branch)
221
if self.other_branch.base != self.this_branch.base:
222
self.this_branch.fetch(self.other_branch,
223
last_revision=self.other_basis)
225
def set_other_revision(self, revision_id, other_branch):
226
"""Set 'other' based on a branch and revision id
228
:param revision_id: The revision to use for a tree
229
:param other_branch: The branch containing this tree
231
self.other_rev_id = revision_id
232
self.other_branch = other_branch
233
self.this_branch.fetch(other_branch, self.other_rev_id)
234
self.other_tree = self.revision_tree(revision_id)
235
self.other_basis = revision_id
217
237
def find_base(self):
218
238
self.set_base([None, None])
253
273
self.this_branch)
255
275
def do_merge(self):
256
kwargs = {'working_tree':self.this_tree, 'this_tree': self.this_tree,
257
'other_tree': self.other_tree,
276
kwargs = {'working_tree':self.this_tree, 'this_tree': self.this_tree,
277
'other_tree': self.other_tree,
258
278
'interesting_ids': self.interesting_ids,
260
280
if self.merge_type.requires_base:
269
289
elif self.show_base:
270
290
raise BzrError("Showing base is not supported for this"
271
291
" merge type. %s" % self.merge_type)
272
merge = self.merge_type(pb=self._pb,
273
change_reporter=self.change_reporter,
292
self.this_tree.lock_tree_write()
293
if self.base_tree is not None:
294
self.base_tree.lock_read()
295
if self.other_tree is not None:
296
self.other_tree.lock_read()
298
merge = self.merge_type(pb=self._pb,
299
change_reporter=self.change_reporter,
301
if self.recurse == 'down':
302
for path, file_id in self.this_tree.iter_references():
303
sub_tree = self.this_tree.get_nested_tree(file_id, path)
304
other_revision = self.other_tree.get_reference_revision(
306
if other_revision == sub_tree.last_revision():
308
sub_merge = Merger(sub_tree.branch, this_tree=sub_tree)
309
sub_merge.merge_type = self.merge_type
310
relpath = self.this_tree.relpath(path)
311
other_branch = self.other_branch.reference_parent(file_id, relpath)
312
sub_merge.set_other_revision(other_revision, other_branch)
313
base_revision = self.base_tree.get_reference_revision(file_id)
314
sub_merge.base_tree = \
315
sub_tree.branch.repository.revision_tree(base_revision)
319
if self.other_tree is not None:
320
self.other_tree.unlock()
321
if self.base_tree is not None:
322
self.base_tree.unlock()
323
self.this_tree.unlock()
275
324
if len(merge.cooked_conflicts) == 0:
276
325
if not self.ignore_zero:
277
326
note("All changes applied successfully.")
363
412
"""Initialize the merger object and perform the merge."""
364
413
object.__init__(self)
365
414
self.this_tree = working_tree
415
self.this_tree.lock_tree_write()
366
416
self.base_tree = base_tree
417
self.base_tree.lock_read()
367
418
self.other_tree = other_tree
419
self.other_tree.lock_read()
368
420
self._raw_conflicts = []
369
421
self.cooked_conflicts = []
370
422
self.reprocess = reprocess
954
1007
DeprecationWarning,
956
1009
this_tree = this_branch.bzrdir.open_workingtree()
957
merger = Merger(this_branch, other_tree, base_tree, this_tree=this_tree,
1010
merger = Merger(this_branch, other_tree, base_tree, this_tree=this_tree,
958
1011
pb=pb, change_reporter=change_reporter)
959
1012
merger.backup_files = backup_files
960
1013
merger.merge_type = merge_type