~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/merge.py

[merge] update from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
# TODO: build_working_dir can be built on something simpler than merge()
17
18
 
18
19
import os
19
 
import shutil
20
20
import errno
21
21
 
22
 
import bzrlib.osutils
23
 
import bzrlib.revision
24
 
from bzrlib.merge_core import merge_flex, ApplyMerge3, BackupBeforeChange
25
 
from bzrlib.merge_core import WeaveMerge
26
 
from bzrlib.changeset import generate_changeset, ExceptionConflictHandler
27
 
from bzrlib.changeset import Inventory, Diff3Merge, ReplaceContents
 
22
import bzrlib
 
23
from bzrlib._changeset import generate_changeset, ExceptionConflictHandler
 
24
from bzrlib._changeset import Inventory, Diff3Merge, ReplaceContents
 
25
from bzrlib._merge_core import WeaveMerge
 
26
from bzrlib._merge_core import merge_flex, ApplyMerge3, BackupBeforeChange
28
27
from bzrlib.branch import Branch
 
28
from bzrlib.delta import compare_trees
29
29
from bzrlib.errors import (BzrCommandError,
30
 
                           UnrelatedBranches,
 
30
                           BzrError,
31
31
                           NoCommonAncestor,
32
32
                           NoCommits,
33
 
                           WorkingTreeNotRevision,
 
33
                           NoSuchRevision,
34
34
                           NotBranchError,
35
35
                           NotVersionedError,
36
 
                           BzrError)
37
 
from bzrlib.delta import compare_trees
38
 
from bzrlib.trace import mutter, warning, note
 
36
                           UnrelatedBranches,
 
37
                           WorkingTreeNotRevision,
 
38
                           )
39
39
from bzrlib.fetch import greedy_fetch, fetch
40
 
from bzrlib.revision import is_ancestor, NULL_REVISION
 
40
import bzrlib.osutils
41
41
from bzrlib.osutils import rename, pathjoin
42
 
from bzrlib.revision import common_ancestor, MultipleRevisionSources
43
 
from bzrlib.errors import NoSuchRevision
 
42
from bzrlib.revision import common_ancestor, is_ancestor, NULL_REVISION
 
43
from bzrlib.trace import mutter, warning, note
 
44
from bzrlib.workingtree import WorkingTree
44
45
 
45
46
# TODO: Report back as changes are merged in
46
47
 
47
 
# TODO: build_working_dir can be built on something simpler than merge()
48
 
 
49
 
# FIXME: merge() parameters seem oriented towards the command line
50
 
# NOTABUG: merge is a helper for commandline functions.  merge_inner is the
51
 
#          the core functionality.
52
 
 
53
48
# comments from abentley on irc: merge happens in two stages, each
54
49
# of which generates a changeset object
55
50
 
56
51
# stage 1: generate OLD->OTHER,
57
52
# stage 2: use MINE and OLD->OTHER to generate MINE -> RESULT
58
53
 
59
 
class MergeConflictHandler(ExceptionConflictHandler):
 
54
class _MergeConflictHandler(ExceptionConflictHandler):
60
55
    """Handle conflicts encountered while merging.
61
56
 
62
57
    This subclasses ExceptionConflictHandler, so that any types of
203
198
 
204
199
    def create(self, file_id, path, tree):
205
200
        """Uses tree data to create a filesystem object for the file_id"""
206
 
        from changeset import get_contents
 
201
        from bzrlib._changeset import get_contents
207
202
        get_contents(tree, file_id)(path, self)
208
203
 
209
204
    def missing_for_merge(self, file_id, other_path):
225
220
                note("All changes applied successfully.")
226
221
        else:
227
222
            note("%d conflicts encountered." % self.conflicts)
228
 
            
229
 
def get_tree(treespec, local_branch=None):
 
223
 
 
224
def _get_tree(treespec, local_branch=None):
230
225
    location, revno = treespec
231
226
    branch = Branch.open_containing(location)[0]
232
227
    if revno is None:
237
232
        revision = branch.get_rev_id(revno)
238
233
        if revision is None:
239
234
            revision = NULL_REVISION
240
 
    return branch, get_revid_tree(branch, revision, local_branch)
241
 
 
242
 
def get_revid_tree(branch, revision, local_branch):
 
235
    return branch, _get_revid_tree(branch, revision, local_branch)
 
236
 
 
237
 
 
238
def _get_revid_tree(branch, revision, local_branch):
243
239
    if revision is None:
244
240
        base_tree = branch.working_tree()
245
241
    else:
246
242
        if local_branch is not None:
247
 
            greedy_fetch(local_branch, branch, revision)
248
 
            base_tree = local_branch.revision_tree(revision)
 
243
            if local_branch.base != branch.base:
 
244
                greedy_fetch(local_branch, branch, revision)
 
245
            base_tree = local_branch.repository.revision_tree(revision)
249
246
        else:
250
 
            base_tree = branch.revision_tree(revision)
 
247
            base_tree = branch.repository.revision_tree(revision)
251
248
    return base_tree
252
249
 
253
250
 
254
 
def file_exists(tree, file_id):
255
 
    return tree.has_filename(tree.id2path(file_id))
256
 
    
257
 
 
258
251
def build_working_dir(to_dir):
259
252
    """Build a working directory in an empty directory.
260
253
 
276
269
                interesting_ids=interesting_ids)
277
270
 
278
271
 
279
 
def merge(other_revision, base_revision,
280
 
          check_clean=True, ignore_zero=False,
281
 
          this_dir=None, backup_files=False, merge_type=ApplyMerge3,
282
 
          file_list=None, show_base=False, reprocess=False):
283
 
    """Merge changes into a tree.
284
 
 
285
 
    base_revision
286
 
        list(path, revno) Base for three-way merge.  
287
 
        If [None, None] then a base will be automatically determined.
288
 
    other_revision
289
 
        list(path, revno) Other revision for three-way merge.
290
 
    this_dir
291
 
        Directory to merge changes into; '.' by default.
292
 
    check_clean
293
 
        If true, this_dir must have no uncommitted changes before the
294
 
        merge begins.
295
 
    ignore_zero - If true, suppress the "zero conflicts" message when 
296
 
        there are no conflicts; should be set when doing something we expect
297
 
        to complete perfectly.
298
 
    file_list - If supplied, merge only changes to selected files.
299
 
 
300
 
    All available ancestors of other_revision and base_revision are
301
 
    automatically pulled into the branch.
302
 
 
303
 
    The revno may be -1 to indicate the last revision on the branch, which is
304
 
    the typical case.
305
 
 
306
 
    This function is intended for use from the command line; programmatic
307
 
    clients might prefer to call merge_inner(), which has less magic behavior.
308
 
    """
309
 
    if this_dir is None:
310
 
        this_dir = u'.'
311
 
    this_branch = Branch.open_containing(this_dir)[0]
312
 
    if show_base and not merge_type is ApplyMerge3:
313
 
        raise BzrCommandError("Show-base is not supported for this merge"
314
 
                              " type. %s" % merge_type)
315
 
    if reprocess and not merge_type is ApplyMerge3:
316
 
        raise BzrCommandError("Reprocess is not supported for this merge"
317
 
                              " type. %s" % merge_type)
318
 
    if reprocess and show_base:
319
 
        raise BzrCommandError("Cannot reprocess and show base.")
320
 
    merger = Merger(this_branch)
321
 
    merger.check_basis(check_clean)
322
 
    merger.set_other(other_revision)
323
 
    merger.set_base(base_revision)
324
 
    if merger.base_rev_id == merger.other_rev_id:
325
 
        note('Nothing to do.')
326
 
        return 0
327
 
    merger.backup_files = backup_files
328
 
    merger.merge_type = merge_type 
329
 
    merger.set_interesting_files(file_list)
330
 
    merger.show_base = show_base 
331
 
    merger.reprocess = reprocess
332
 
    merger.conflict_handler = MergeConflictHandler(merger.this_tree, 
333
 
                                                   merger.base_tree, 
334
 
                                                   merger.other_tree,
335
 
                                                   ignore_zero=ignore_zero)
336
 
    conflicts = merger.do_merge()
337
 
    merger.set_pending()
338
 
    return conflicts
339
 
 
340
272
def merge_inner(this_branch, other_tree, base_tree, ignore_zero=False,
341
273
                backup_files=False, 
342
274
                merge_type=ApplyMerge3, 
344
276
                show_base=False, 
345
277
                reprocess=False, 
346
278
                other_rev_id=None,
347
 
                interesting_files=None):
 
279
                interesting_files=None,
 
280
                this_tree=None):
348
281
    """Primary interface for merging. 
349
282
 
350
283
        typical use is probably 
351
284
        'merge_inner(branch, branch.get_revision_tree(other_revision),
352
285
                     branch.get_revision_tree(base_revision))'
353
286
        """
354
 
    merger = Merger(this_branch, other_tree, base_tree)
 
287
    if this_tree is None:
 
288
        this_tree = this_branch.working_tree()
 
289
    merger = Merger(this_branch, other_tree, base_tree, this_tree=this_tree)
355
290
    merger.backup_files = backup_files
356
291
    merger.merge_type = merge_type
357
292
    merger.interesting_ids = interesting_ids
361
296
        merger._set_interesting_files(interesting_files)
362
297
    merger.show_base = show_base 
363
298
    merger.reprocess = reprocess
364
 
    merger.conflict_handler = MergeConflictHandler(merger.this_tree, base_tree, 
365
 
                                                   other_tree,
366
 
                                                   ignore_zero=ignore_zero)
 
299
    merger.conflict_handler = _MergeConflictHandler(merger.this_tree, 
 
300
                                                    base_tree, other_tree,
 
301
                                                    ignore_zero=ignore_zero)
367
302
    merger.other_rev_id = other_rev_id
368
303
    merger.other_basis = other_rev_id
369
304
    return merger.do_merge()
370
305
 
371
306
 
372
307
class Merger(object):
373
 
    def __init__(self, this_branch, other_tree=None, base_tree=None):
 
308
    def __init__(self, this_branch, other_tree=None, base_tree=None, this_tree=None):
374
309
        object.__init__(self)
 
310
        assert this_tree is not None, "this_tree is required"
375
311
        self.this_branch = this_branch
376
312
        self.this_basis = this_branch.last_revision()
377
313
        self.this_rev_id = None
378
 
        self.this_tree = this_branch.working_tree()
 
314
        self.this_tree = this_tree
379
315
        self.this_revision_tree = None
380
316
        self.this_basis_tree = None
381
317
        self.other_tree = other_tree
385
321
        self.interesting_ids = None
386
322
        self.show_base = False
387
323
        self.reprocess = False
388
 
        self.conflict_handler = MergeConflictHandler(self.this_tree, base_tree, 
389
 
                                                     other_tree)
 
324
        self.conflict_handler = _MergeConflictHandler(self.this_tree, 
 
325
                                                      base_tree, other_tree)
390
326
 
391
327
    def revision_tree(self, revision_id):
392
 
        return self.this_branch.revision_tree(revision_id)
 
328
        return self.this_branch.repository.revision_tree(revision_id)
393
329
 
394
330
    def ensure_revision_trees(self):
395
331
        if self.this_revision_tree is None:
396
 
            self.this_basis_tree = self.this_branch.revision_tree(
 
332
            self.this_basis_tree = self.this_branch.repository.revision_tree(
397
333
                self.this_basis)
398
334
            if self.this_basis == self.this_rev_id:
399
335
                self.this_revision_tree = self.this_basis_tree
400
336
 
401
 
 
402
337
        if self.other_rev_id is None:
403
338
            other_basis_tree = self.revision_tree(self.other_basis)
404
339
            changes = compare_trees(self.other_tree, other_basis_tree)
407
342
            other_rev_id = other_basis
408
343
            self.other_tree = other_basis_tree
409
344
 
410
 
 
411
345
    def file_revisions(self, file_id):
412
346
        self.ensure_revision_trees()
413
347
        def get_id(tree, file_id):
421
355
 
422
356
        trees = (self.this_basis_tree, self.other_tree)
423
357
        return [get_id(tree, file_id) for tree in trees]
424
 
            
425
358
 
426
359
    def merge_factory(self, file_id, base, other):
427
360
        if self.merge_type.history_based:
453
386
                raise BzrCommandError("Working tree has uncommitted changes.")
454
387
 
455
388
    def compare_basis(self):
456
 
        changes = compare_trees(self.this_branch.working_tree(), 
 
389
        changes = compare_trees(self.this_tree, 
457
390
                                self.this_branch.basis_tree(), False)
458
391
        if not changes.has_changed():
459
392
            self.this_rev_id = self.this_basis
472
405
            return
473
406
 
474
407
        interesting_ids = set()
475
 
        for fname in file_list:
476
 
            path = self.this_tree.relpath(fname)
 
408
        for path in file_list:
477
409
            found_id = False
478
410
            for tree in (self.this_tree, self.base_tree, self.other_tree):
479
411
                file_id = tree.inventory.path2id(path)
481
413
                    interesting_ids.add(file_id)
482
414
                    found_id = True
483
415
            if not found_id:
484
 
                raise NotVersionedError(path=fname)
 
416
                raise NotVersionedError(path=path)
485
417
        self.interesting_ids = interesting_ids
486
418
 
487
419
    def set_pending(self):
489
421
            return
490
422
        if self.other_rev_id is None:
491
423
            return
492
 
        if self.other_rev_id in self.this_branch.get_ancestry(self.this_basis):
 
424
        ancestry = self.this_branch.repository.get_ancestry(self.this_basis)
 
425
        if self.other_rev_id in ancestry:
493
426
            return
494
 
        self.this_branch.working_tree().add_pending_merge(self.other_rev_id)
 
427
        self.this_tree.add_pending_merge(self.other_rev_id)
495
428
 
496
429
    def set_other(self, other_revision):
497
 
        other_branch, self.other_tree = get_tree(other_revision, 
498
 
                                                 self.this_branch)
 
430
        other_branch, self.other_tree = _get_tree(other_revision, 
 
431
                                                  self.this_branch)
499
432
        if other_revision[1] == -1:
500
433
            self.other_rev_id = other_branch.last_revision()
501
434
            if self.other_rev_id is None:
509
442
            self.other_basis = other_branch.last_revision()
510
443
            if self.other_basis is None:
511
444
                raise NoCommits(other_branch)
512
 
        fetch(from_branch=other_branch, to_branch=self.this_branch, 
513
 
              last_revision=self.other_basis)
 
445
        if other_branch.base != self.this_branch.base:
 
446
            fetch(from_branch=other_branch, to_branch=self.this_branch, 
 
447
                  last_revision=self.other_basis)
514
448
 
515
449
    def set_base(self, base_revision):
516
450
        mutter("doing merge() with no base_revision specified")
518
452
            try:
519
453
                self.base_rev_id = common_ancestor(self.this_basis, 
520
454
                                                   self.other_basis, 
521
 
                                                   self.this_branch)
 
455
                                                   self.this_branch.repository)
522
456
            except NoCommonAncestor:
523
457
                raise UnrelatedBranches()
524
 
            self.base_tree = get_revid_tree(self.this_branch, self.base_rev_id,
 
458
            self.base_tree = _get_revid_tree(self.this_branch, self.base_rev_id,
525
459
                                            None)
526
460
            self.base_is_ancestor = True
527
461
        else:
528
 
            base_branch, self.base_tree = get_tree(base_revision)
 
462
            base_branch, self.base_tree = _get_tree(base_revision)
529
463
            if base_revision[1] == -1:
530
464
                self.base_rev_id = base_branch.last_revision()
531
465
            elif base_revision[1] is None:
558
492
                path = path[2:]
559
493
            adjust_ids.append((path, id))
560
494
        if len(adjust_ids) > 0:
561
 
            self.this_branch.working_tree().set_inventory(self.regen_inventory(adjust_ids))
 
495
            self.this_tree.set_inventory(self.regen_inventory(adjust_ids))
562
496
        conflicts = self.conflict_handler.conflicts
563
497
        self.conflict_handler.finalize()
564
498
        return conflicts
565
499
 
566
500
    def regen_inventory(self, new_entries):
567
 
        old_entries = self.this_branch.working_tree().read_working_inventory()
 
501
        old_entries = self.this_tree.read_working_inventory()
568
502
        new_inventory = {}
569
503
        by_path = {}
570
504
        new_entries_map = {} 
623
557
        new_inventory_list.sort()
624
558
        return new_inventory_list
625
559
 
 
560
 
626
561
merge_types = {     "merge3": (ApplyMerge3, "Native diff3-style merge"), 
627
562
                     "diff3": (Diff3Merge,  "Merge using external diff3"),
628
563
                     'weave': (WeaveMerge, "Weave-based merge")
629
564
              }
630