Rev 3279: (jam) Implement Cherrypick support for Merge3 in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Sat Mar 15 01:07:24 GMT 2008


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 3279
revision-id:pqm at pqm.ubuntu.com-20080315010714-k7pnu991eg5f0k0q
parent: pqm at pqm.ubuntu.com-20080314225929-4y11nn6gml5qfzz1
parent: john at arbash-meinel.com-20080314162755-e6cwmpv188h2ns5i
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Sat 2008-03-15 01:07:14 +0000
message:
  (jam) Implement Cherrypick support for Merge3
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
  bzrlib/merge3.py               merge3.py-20050704130834-bf0597094828a2e1
  bzrlib/tests/test_merge.py     testmerge.py-20050905070950-c1b5aa49ff911024
  bzrlib/tests/test_merge3.py    merge3.py-20050704130834-556689114c89e6f2
    ------------------------------------------------------------
    revno: 3249.3.4
    revision-id:john at arbash-meinel.com-20080314162755-e6cwmpv188h2ns5i
    parent: john at arbash-meinel.com-20080314162328-9uc5ut91w0at3otd
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: cherrypick_merge
    timestamp: Fri 2008-03-14 16:27:55 +0000
    message:
      NEWS for fixing bug #151731
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
    ------------------------------------------------------------
    revno: 3249.3.3
    revision-id:john at arbash-meinel.com-20080314162328-9uc5ut91w0at3otd
    parent: john at arbash-meinel.com-20080314161325-3cxcyg5nerrbimt2
    parent: pqm at pqm.ubuntu.com-20080314152947-u92b6klpfcnigv4e
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: cherrypick_merge
    timestamp: Fri 2008-03-14 16:23:28 +0000
    message:
      [merge] bzr.dev 3276
    added:
      bzrlib/directory_service.py    directory_service.py-20080305221044-vr2mkvlsk8jypa2y-1
      bzrlib/tests/test_directory_service.py test_directory_servi-20080305221044-vr2mkvlsk8jypa2y-2
      doc/en/admin-guide/            docenadminguide-20080305135054-y7y2c986yf94zljn-1
      doc/en/admin-guide/index.txt   index.txt-20080305140741-ecw0lap8dxkxc05g-1
    renamed:
      bzrlib/plugins/launchpad/lp_indirect.py => bzrlib/plugins/launchpad/lp_directory.py lp_indirect.py-20070126012204-de5rugwlt22c7u7e-1
      bzrlib/plugins/launchpad/test_lp_indirect.py => bzrlib/plugins/launchpad/test_lp_directory.py test_lp_indirect.py-20070126002743-oyle362tzv9cd8mi-1
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/debug.py                debug.py-20061102062349-vdhrw9qdpck8cl35-1
      bzrlib/delta.py                delta.py-20050729221636-54cf14ef94783d0a
      bzrlib/deprecated_graph.py     graph.py-20050905070950-b47dce53236c5e48
      bzrlib/diff.py                 diff.py-20050309040759-26944fbbf2ebbf36
      bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/help_topics/__init__.py help_topics.py-20060920210027-rnim90q9e0bwxvy4-1
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/mail_client.py          mail_client.py-20070809192806-vuxt3t19srtpjpdn-1
      bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
      bzrlib/merge_directive.py      merge_directive.py-20070228184838-ja62280spt1g7f4x-1
      bzrlib/missing.py              missing.py-20050812153334-097f7097e2a8bcd1
      bzrlib/plugins/launchpad/__init__.py __init__.py-20060315182712-2d5feebd2a1032dc
      bzrlib/plugins/launchpad/lp_registration.py lp_registration.py-20060315190948-daa617eafe3a8d48
      bzrlib/registry.py             lazy_factory.py-20060809213415-2gfvqadtvdn0phtg-1
      bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/status.py               status.py-20050505062338-431bfa63ec9b19e6
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/test_merge.py test_merge.py-20060323225809-9bc0459c19917f41
      bzrlib/tests/blackbox/test_push.py test_push.py-20060329002750-929af230d5d22663
      bzrlib/tests/blackbox/test_send.py test_bundle.py-20060616222707-c21c8b7ea5ef57b1
      bzrlib/tests/branch_implementations/test_branch.py testbranch.py-20050711070244-121d632bc37d7253
      bzrlib/tests/branch_implementations/test_revision_history.py test_revision_histor-20070326062311-v7co92liyuchb80w-1
      bzrlib/tests/intertree_implementations/test_compare.py test_compare.py-20060724101752-09ysswo1a92uqyoz-2
      bzrlib/tests/test_errors.py    test_errors.py-20060210110251-41aba2deddf936a8
      bzrlib/tests/test_mail_client.py test_mail_client.py-20070809192806-vuxt3t19srtpjpdn-2
      bzrlib/tests/test_merge.py     testmerge.py-20050905070950-c1b5aa49ff911024
      bzrlib/tests/test_merge_directive.py test_merge_directive-20070228184838-ja62280spt1g7f4x-2
      bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
      bzrlib/tests/test_registry.py  test_lazy_factory.py-20060809213415-2gfvqadtvdn0phtg-2
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
      bzrlib/tests/test_tsort.py     testtsort.py-20051025073946-27da871c394d5be4
      bzrlib/tests/test_upgrade.py   test_upgrade.py-20051004040251-555fe1d2bae1bc71
      bzrlib/tests/test_urlutils.py  test_urlutils.py-20060502192900-46b1f9579987cf9c
      bzrlib/tests/test_workingtree_4.py test_workingtree_4.p-20070223025758-531n3tznl3zacv2o-1
      bzrlib/tests/workingtree_implementations/test_merge_from_branch.py test_merge_from_bran-20060904034200-12jxyk2zlhpufxe1-1
      bzrlib/tests/workingtree_implementations/test_parents.py test_set_parents.py-20060807231740-yicmnlci1mj8smu1-1
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
      bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
      bzrlib/tsort.py                tsort.py-20051025073946-7808f6aaf7d07208
      bzrlib/urlutils.py             urlutils.py-20060502195429-e8a161ecf8fac004
      bzrlib/util/configobj/configobj.py configobj.py-20051018184548-06992a2246425e3e
      bzrlib/util/configobj/docs/configobj.txt configobj.txt-20051018184548-4949b5f17e6a19c7
      bzrlib/util/configobj/docs/validate.txt validate.txt-20051018184548-9e0e5ad913e258f5
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
      doc/developers/lca-merge.txt   lcamerge.txt-20080103061803-9isydn4ivgwrvorw-1
      doc/en/mini-tutorial/index.txt index.txt-20070813141352-2u64ooqzo0or4hss-2
      doc/en/user-guide/resolving_conflicts.txt resolving_conflicts.-20071122141511-0knao2lklsdsvb1q-5
      doc/en/user-guide/version_info.txt version_info.txt-20060921215543-gju6o5xdic8w25np-1
      setup.py                       setup.py-20050314065409-02f8a0a6e3f9bc70
      bzrlib/plugins/launchpad/lp_directory.py lp_indirect.py-20070126012204-de5rugwlt22c7u7e-1
      bzrlib/plugins/launchpad/test_lp_directory.py test_lp_indirect.py-20070126002743-oyle362tzv9cd8mi-1
    ------------------------------------------------------------
    revno: 3249.3.2
    revision-id:john at arbash-meinel.com-20080314161325-3cxcyg5nerrbimt2
    parent: john at arbash-meinel.com-20080304142546-zuwwy0o9roo14928
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: cherrypick_merge
    timestamp: Fri 2008-03-14 16:13:25 +0000
    message:
      review feedback from Robert
      Use clearer variable names
      profile the 'assert' section, which seemed to cost about 20% of the
      time spent in find_sync_regions. (which is about 50% of merge_lines).
      It seems the big overhead is actually iter_merge3(). So for now,
      leave the asserts in, -O will remove them anyway.
    modified:
      bzrlib/merge3.py               merge3.py-20050704130834-bf0597094828a2e1
    ------------------------------------------------------------
    revno: 3249.3.1
    revision-id:john at arbash-meinel.com-20080304142546-zuwwy0o9roo14928
    parent: pqm at pqm.ubuntu.com-20080304003709-35vh1eqa8tuuq548
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: cherrypick_merge
    timestamp: Tue 2008-03-04 14:25:46 +0000
    message:
      Implement cherrypick support for Merge3
      When merging a cherrypick, use a slightly different resolve logic.
      When encountering a conflict, the new logic does not include lines that
      were present in BASE that are conflicting with OTHER.
      This is done since a cherrypick is (by definition) avoiding changes that
      are present in the base.
      (related to bug #151731)
    modified:
      bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
      bzrlib/merge3.py               merge3.py-20050704130834-bf0597094828a2e1
      bzrlib/tests/test_merge.py     testmerge.py-20050905070950-c1b5aa49ff911024
      bzrlib/tests/test_merge3.py    merge3.py-20050704130834-556689114c89e6f2
=== modified file 'NEWS'
--- a/NEWS	2008-03-14 19:44:24 +0000
+++ b/NEWS	2008-03-15 01:07:14 +0000
@@ -65,6 +65,9 @@
 
   BUGFIXES:
 
+    * Cherrypicking when using ``--format=merge3`` now explictly excludes
+      BASE lines. (John Arbash Meinel, #151731)
+
     * Disable plink's interactive prompt for password.
       (#107593, Dmitry Vasiliev)
 

=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py	2008-03-07 14:15:10 +0000
+++ b/bzrlib/merge.py	2008-03-14 16:23:28 +0000
@@ -116,7 +116,9 @@
 
     def _get_base_is_other_ancestor(self):
         if self._base_is_other_ancestor is None:
-            self.base_is_other_ancestor = self.revision_graph.is_ancestor(
+            if self.other_basis is None:
+                return True
+            self._base_is_other_ancestor = self.revision_graph.is_ancestor(
                 self.base_rev_id, self.other_basis)
         return self._base_is_other_ancestor
 
@@ -162,7 +164,7 @@
         return merger, verified
 
     @staticmethod
-    def from_revision_ids(pb, this, other, base=None, other_branch=None,
+    def from_revision_ids(pb, tree, other, base=None, other_branch=None,
                           base_branch=None, revision_graph=None):
         """Return a Merger for revision-ids.
 
@@ -171,15 +173,17 @@
         :param base: The revision-id to use as BASE.  If not specified, will
             be auto-selected.
         :param other_branch: A branch containing the other revision-id.  If
-            not supplied, this.branch is used.
+            not supplied, tree.branch is used.
         :param base_branch: A branch containing the base revision-id.  If
-            not supplied, other_branch or this.branch will be used.
+            not supplied, other_branch or tree.branch will be used.
+        :param revision_graph: If you have a revision_graph precomputed, pass
+            it in, otherwise it will be created for you.
         :param pb: A progress indicator
         """
-        merger = Merger(this.branch, this_tree=this, pb=pb,
+        merger = Merger(tree.branch, this_tree=tree, pb=pb,
                         revision_graph=revision_graph)
         if other_branch is None:
-            other_branch = this.branch
+            other_branch = tree.branch
         merger.set_other_revision(other, other_branch)
         if base is None:
             merger.find_base()
@@ -399,7 +403,7 @@
         if (not getattr(self.merge_type, 'supports_reverse_cherrypick', True)
             and not self.base_is_other_ancestor):
             raise errors.CannotReverseCherrypick()
-        if self.merge_type.history_based:
+        if self.merge_type.supports_cherrypick:
             kwargs['cherrypick'] = (not self.base_is_ancestor or
                                     not self.base_is_other_ancestor)
         return self.merge_type(pb=self._pb,
@@ -407,13 +411,13 @@
                                **kwargs)
 
     def do_merge(self):
-        merge = self.make_merger()
         self.this_tree.lock_tree_write()
         if self.base_tree is not None:
             self.base_tree.lock_read()
         if self.other_tree is not None:
             self.other_tree.lock_read()
         try:
+            merge = self.make_merger()
             merge.do_merge()
             if self.recurse == 'down':
                 for path, file_id in self.this_tree.iter_references():
@@ -430,6 +434,7 @@
                     base_revision = self.base_tree.get_reference_revision(file_id)
                     sub_merge.base_tree = \
                         sub_tree.branch.repository.revision_tree(base_revision)
+                    sub_merge.base_rev_id = base_revision
                     sub_merge.do_merge()
 
         finally:
@@ -453,13 +458,15 @@
     supports_reprocess = True
     supports_show_base = True
     history_based = False
+    supports_cherrypick = True
     supports_reverse_cherrypick = True
     winner_idx = {"this": 2, "other": 1, "conflict": 1}
 
     def __init__(self, working_tree, this_tree, base_tree, other_tree, 
                  interesting_ids=None, reprocess=False, show_base=False,
                  pb=DummyProgress(), pp=None, change_reporter=None,
-                 interesting_files=None, do_merge=True):
+                 interesting_files=None, do_merge=True,
+                 cherrypick=False):
         """Initialize the merger object and perform the merge.
 
         :param working_tree: The working tree to apply the merge to
@@ -497,6 +504,7 @@
         self.pb = pb
         self.pp = pp
         self.change_reporter = change_reporter
+        self.cherrypick = cherrypick
         if self.pp is None:
             self.pp = ProgressPhase("Merge phase", 3, self.pb)
         if do_merge:
@@ -865,7 +873,8 @@
             base_lines = []
         other_lines = self.get_lines(self.other_tree, file_id)
         this_lines = self.get_lines(self.this_tree, file_id)
-        m3 = Merge3(base_lines, this_lines, other_lines)
+        m3 = Merge3(base_lines, this_lines, other_lines,
+                    is_cherrypick=self.cherrypick)
         start_marker = "!START OF MERGE CONFLICT!" + "I HOPE THIS IS UNIQUE"
         if self.show_base is True:
             base_marker = '|' * 7
@@ -1040,19 +1049,6 @@
     supports_reverse_cherrypick = False
     history_based = True
 
-    def __init__(self, working_tree, this_tree, base_tree, other_tree, 
-                 interesting_ids=None, pb=DummyProgress(), pp=None,
-                 reprocess=False, change_reporter=None,
-                 interesting_files=None, cherrypick=False, do_merge=True):
-        self.cherrypick = cherrypick
-        super(WeaveMerger, self).__init__(working_tree, this_tree, 
-                                          base_tree, other_tree, 
-                                          interesting_files=interesting_files,
-                                          interesting_ids=interesting_ids, 
-                                          pb=pb, pp=pp, reprocess=reprocess,
-                                          change_reporter=change_reporter,
-                                          do_merge=do_merge)
-
     def _merged_lines(self, file_id):
         """Generate the merged lines.
         There is no distinction between lines that are meant to contain <<<<<<<
@@ -1195,6 +1191,10 @@
     merger.reprocess = reprocess
     merger.other_rev_id = other_rev_id
     merger.other_basis = other_rev_id
+    get_revision_id = getattr(base_tree, 'get_revision_id', None)
+    if get_revision_id is None:
+        get_revision_id = base_tree.last_revision
+    merger.set_base_revision(get_revision_id(), this_branch)
     return merger.do_merge()
 
 def get_merge_type_registry():

=== modified file 'bzrlib/merge3.py'
--- a/bzrlib/merge3.py	2007-03-12 19:56:41 +0000
+++ b/bzrlib/merge3.py	2008-03-14 16:13:25 +0000
@@ -67,15 +67,14 @@
     Given BASE, OTHER, THIS, tries to produce a combined text
     incorporating the changes from both BASE->OTHER and BASE->THIS.
     All three will typically be sequences of lines."""
-    def __init__(self, base, a, b):
+    def __init__(self, base, a, b, is_cherrypick=False):
         check_text_lines(base)
         check_text_lines(a)
         check_text_lines(b)
         self.base = base
         self.a = a
         self.b = b
-
-
+        self.is_cherrypick = is_cherrypick
 
     def merge_lines(self,
                     name_a=None,
@@ -130,10 +129,6 @@
                 yield end_marker + newline
             else:
                 raise ValueError(what)
-        
-        
-
-
 
     def merge_annotated(self):
         """Return merge with conflicts, showing origin of lines.
@@ -161,10 +156,6 @@
                 yield '>>>>\n'
             else:
                 raise ValueError(what)
-        
-        
-
-
 
     def merge_groups(self):
         """Yield sequence of line groups.  Each one is a tuple:
@@ -200,7 +191,6 @@
             else:
                 raise ValueError(what)
 
-
     def merge_regions(self):
         """Return sequences of matching and conflicting regions.
 
@@ -250,23 +240,30 @@
 
             if len_a or len_b:
                 # try to avoid actually slicing the lists
-                equal_a = compare_range(self.a, ia, amatch,
-                                        self.base, iz, zmatch)
-                equal_b = compare_range(self.b, ib, bmatch,
-                                        self.base, iz, zmatch)
                 same = compare_range(self.a, ia, amatch,
                                      self.b, ib, bmatch)
 
                 if same:
                     yield 'same', ia, amatch
-                elif equal_a and not equal_b:
-                    yield 'b', ib, bmatch
-                elif equal_b and not equal_a:
-                    yield 'a', ia, amatch
-                elif not equal_a and not equal_b:
-                    yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
                 else:
-                    raise AssertionError("can't handle a=b=base but unmatched")
+                    equal_a = compare_range(self.a, ia, amatch,
+                                            self.base, iz, zmatch)
+                    equal_b = compare_range(self.b, ib, bmatch,
+                                            self.base, iz, zmatch)
+                    if equal_a and not equal_b:
+                        yield 'b', ib, bmatch
+                    elif equal_b and not equal_a:
+                        yield 'a', ia, amatch
+                    elif not equal_a and not equal_b:
+                        if self.is_cherrypick:
+                            for node in self._refine_cherrypick_conflict(
+                                                    iz, zmatch, ia, amatch,
+                                                    ib, bmatch):
+                                yield node
+                        else:
+                            yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
+                    else:
+                        raise AssertionError("can't handle a=b=base but unmatched")
 
                 ia = amatch
                 ib = bmatch
@@ -275,7 +272,6 @@
             # if the same part of the base was deleted on both sides
             # that's OK, we can just skip it.
 
-                
             if matchlen > 0:
                 assert ia == amatch
                 assert ib == bmatch
@@ -285,7 +281,46 @@
                 iz = zend
                 ia = aend
                 ib = bend
-    
+
+    def _refine_cherrypick_conflict(self, zstart, zend, astart, aend, bstart, bend):
+        """When cherrypicking b => a, ignore matches with b and base."""
+        # Do not emit regions which match, only regions which do not match
+        matches = bzrlib.patiencediff.PatienceSequenceMatcher(None,
+            self.base[zstart:zend], self.b[bstart:bend]).get_matching_blocks()
+        last_base_idx = 0
+        last_b_idx = 0
+        last_b_idx = 0
+        yielded_a = False
+        for base_idx, b_idx, match_len in matches:
+            conflict_z_len = base_idx - last_base_idx
+            conflict_b_len = b_idx - last_b_idx
+            if conflict_b_len == 0: # There are no lines in b which conflict,
+                                    # so skip it
+                pass
+            else:
+                if yielded_a:
+                    yield ('conflict',
+                           zstart + last_base_idx, zstart + base_idx,
+                           aend, aend, bstart + last_b_idx, bstart + b_idx)
+                else:
+                    # The first conflict gets the a-range
+                    yielded_a = True
+                    yield ('conflict', zstart + last_base_idx, zstart +
+                    base_idx,
+                           astart, aend, bstart + last_b_idx, bstart + b_idx)
+            last_base_idx = base_idx + match_len
+            last_b_idx = b_idx + match_len
+        if last_base_idx != zend - zstart or last_b_idx != bend - bstart:
+            if yielded_a:
+                yield ('conflict', zstart + last_base_idx, zstart + base_idx,
+                       aend, aend, bstart + last_b_idx, bstart + b_idx)
+            else:
+                # The first conflict gets the a-range
+                yielded_a = True
+                yield ('conflict', zstart + last_base_idx, zstart + base_idx,
+                       astart, aend, bstart + last_b_idx, bstart + b_idx)
+        if not yielded_a:
+            yield ('conflict', zstart, zend, astart, aend, bstart, bend)
 
     def reprocess_merge_regions(self, merge_regions):
         """Where there are conflict regions, remove the agreed lines.
@@ -318,12 +353,10 @@
             if reg is not None:
                 yield reg
 
-
     @staticmethod
     def mismatch_region(next_a, region_ia,  next_b, region_ib):
         if next_a < region_ia or next_b < region_ib:
             return 'conflict', None, None, next_a, region_ia, next_b, region_ib
-            
 
     def find_sync_regions(self):
         """Return a list of sync regions, where both descendents match the base.
@@ -388,8 +421,6 @@
 
         return sl
 
-
-
     def find_unconflicted(self):
         """Return a list of ranges in base that are not conflicted."""
         am = bzrlib.patiencediff.PatienceSequenceMatcher(

=== modified file 'bzrlib/tests/test_merge.py'
--- a/bzrlib/tests/test_merge.py	2008-03-03 17:39:50 +0000
+++ b/bzrlib/tests/test_merge.py	2008-03-14 16:23:28 +0000
@@ -352,6 +352,30 @@
         merger.merge_type = _mod_merge.Merge3Merger
         merger.do_merge()
 
+    def test_merge3_will_detect_cherrypick(self):
+        this_tree = self.make_branch_and_tree('this')
+        self.build_tree_contents([('this/file', "a\n")])
+        this_tree.add('file')
+        this_tree.commit('rev1')
+        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
+        self.build_tree_contents([('other/file', "a\nb\n")])
+        other_tree.commit('rev2b', rev_id='rev2b')
+        self.build_tree_contents([('other/file', "a\nb\nc\n")])
+        other_tree.commit('rev3b', rev_id='rev3b')
+        this_tree.lock_write()
+        self.addCleanup(this_tree.unlock)
+
+        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
+            this_tree, 'rev3b', 'rev2b', other_tree.branch)
+        merger.merge_type = _mod_merge.Merge3Merger
+        merger.do_merge()
+        self.assertFileEqual('a\n'
+                             '<<<<<<< TREE\n'
+                             '=======\n'
+                             'c\n'
+                             '>>>>>>> MERGE-SOURCE\n',
+                             'this/file')
+
     def test_make_merger(self):
         this_tree = self.make_branch_and_tree('this')
         this_tree.commit('rev1', rev_id='rev1')

=== modified file 'bzrlib/tests/test_merge3.py'
--- a/bzrlib/tests/test_merge3.py	2007-03-12 19:56:41 +0000
+++ b/bzrlib/tests/test_merge3.py	2008-03-04 14:25:46 +0000
@@ -383,3 +383,42 @@
         m_lines = m3.merge_lines('OTHER', 'THIS')
         self.assertEqual('<<<<<<< OTHER\rc\r=======\rb\r'
             '>>>>>>> THIS\r'.splitlines(True), list(m_lines))
+
+    def test_merge3_cherrypick(self):
+        base_text = "a\nb\n"
+        this_text = "a\n"
+        other_text = "a\nb\nc\n"
+        # When cherrypicking, lines in base are not part of the conflict
+        m3 = Merge3(base_text.splitlines(True), this_text.splitlines(True),
+                    other_text.splitlines(True), is_cherrypick=True)
+        m_lines = m3.merge_lines()
+        self.assertEqualDiff('a\n<<<<<<<\n=======\nc\n>>>>>>>\n',
+                             ''.join(m_lines))
+
+        # This is not symmetric
+        m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
+                    this_text.splitlines(True), is_cherrypick=True)
+        m_lines = m3.merge_lines()
+        self.assertEqualDiff('a\n<<<<<<<\nb\nc\n=======\n>>>>>>>\n',
+                             ''.join(m_lines))
+
+    def test_merge3_cherrypick_w_mixed(self):
+        base_text = 'a\nb\nc\nd\ne\n'
+        this_text = 'a\nb\nq\n'
+        other_text = 'a\nb\nc\nd\nf\ne\ng\n'
+        # When cherrypicking, lines in base are not part of the conflict
+        m3 = Merge3(base_text.splitlines(True), this_text.splitlines(True),
+                    other_text.splitlines(True), is_cherrypick=True)
+        m_lines = m3.merge_lines()
+        self.assertEqualDiff('a\n'
+                             'b\n'
+                             '<<<<<<<\n'
+                             'q\n'
+                             '=======\n'
+                             'f\n'
+                             '>>>>>>>\n'
+                             '<<<<<<<\n'
+                             '=======\n'
+                             'g\n'
+                             '>>>>>>>\n',
+                             ''.join(m_lines))




More information about the bazaar-commits mailing list