~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/merge.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-03-07 10:45:44 UTC
  • mfrom: (2321.1.2 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20070307104544-59e3e6358e4bdb29
(robertc) Merge dirstate and subtrees. (Robert Collins, Martin Pool, Aaaron Bentley, John A Meinel, James Westby)

Show diffs side-by-side

added added

removed removed

Lines of Context:
87
87
 
88
88
 
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
                 recurse='down'):
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
107
 
        self._pb = pb 
 
109
        self._pb = pb
108
110
        self.pp = None
 
111
        self.recurse = recurse
109
112
        self.change_reporter = change_reporter
110
113
 
111
114
    def revision_tree(self, revision_id):
170
173
        interesting_ids = set()
171
174
        for path in file_list:
172
175
            found_id = False
 
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
 
179
            #       before that.
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)
177
184
                    found_id = True
196
203
 
197
204
        :param other_revision: The [path, revision] list to merge from.
198
205
        """
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
209
216
        else:
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)
 
224
 
 
225
    def set_other_revision(self, revision_id, other_branch):
 
226
        """Set 'other' based on a branch and revision id
 
227
 
 
228
        :param revision_id: The revision to use for a tree
 
229
        :param other_branch: The branch containing this tree
 
230
        """
 
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
216
236
 
217
237
    def find_base(self):
218
238
        self.set_base([None, None])
253
273
                                                self.this_branch)
254
274
 
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,
259
279
                  'pp': self.pp}
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,
274
 
                                **kwargs)
 
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()
 
297
        try:
 
298
            merge = self.merge_type(pb=self._pb,
 
299
                                    change_reporter=self.change_reporter,
 
300
                                    **kwargs)
 
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(
 
305
                        file_id, path)
 
306
                    if  other_revision == sub_tree.last_revision():
 
307
                        continue
 
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)
 
316
                    sub_merge.do_merge()
 
317
 
 
318
        finally:
 
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
380
432
        else:
381
433
            all_ids = set(base_tree)
382
434
            all_ids.update(other_tree)
383
 
        working_tree.lock_tree_write()
384
435
        self.tt = TreeTransform(working_tree, self.pb)
385
436
        try:
386
437
            self.pp.next_phase()
415
466
                pass
416
467
        finally:
417
468
            self.tt.finalize()
418
 
            working_tree.unlock()
 
469
            self.other_tree.unlock()
 
470
            self.base_tree.unlock()
 
471
            self.this_tree.unlock()
419
472
            self.pb.clear()
420
473
 
421
474
    def fix_root(self):
932
985
 
933
986
 
934
987
def merge_inner(this_branch, other_tree, base_tree, ignore_zero=False,
935
 
                backup_files=False, 
936
 
                merge_type=Merge3Merger, 
937
 
                interesting_ids=None, 
938
 
                show_base=False, 
939
 
                reprocess=False, 
 
988
                backup_files=False,
 
989
                merge_type=Merge3Merger,
 
990
                interesting_ids=None,
 
991
                show_base=False,
 
992
                reprocess=False,
940
993
                other_rev_id=None,
941
994
                interesting_files=None,
942
995
                this_tree=None,
954
1007
             DeprecationWarning,
955
1008
             stacklevel=2)
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