[PATCH] merge: respect bookmarks during merge

David Soria Parra dsp at php.net
Sun May 13 03:19:36 CDT 2012


# HG changeset patch
# User David Soria Parra <dsp at php.net>
# Date 1336897153 -7200
# Node ID c0222da7aa81eb207652ddc486b5e4c503ad9144
# Parent  21422ce4ccca39c16d6aeb99d6cb372e780d8732
merge: respect bookmarks during merge

Bookmarks will behave more like named branches when merge tries to pick
a revision to merge.

Bookmarks now to respect the current bookmarks.  Bookmarks will not
accidentally merged with unnamed heads or other bookmarks. However merge
can pick heads with diverging bookmarks and pick those automatically.

We end up with two cases for picking a revision to merge:
 (1) In case of an current bookmark, merge can pick a branch head that has a
     diverged bookmark
 (2) In case of no current bookmark, merge can pick a branch head that does not
     have a bookmark.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -4159,17 +4159,44 @@
     if not node:
         node = opts.get('rev')
 
-    if not node:
-        branch = repo[None].branch()
-        bheads = repo.branchheads(branch)
-        if len(bheads) > 2:
+    if node:
+        node = scmutil.revsingle(repo, node).node()
+
+    branch = repo[None].branch()
+    bheads = repo.branchheads(branch)
+    if not node and repo._bookmarkcurrent:
+        cur = repo._bookmarkcurrent.split('@', 1)[0]
+        candidates = []
+        for mark, n in repo._bookmarks.iteritems():
+            if n in bheads and mark.split('@', 1)[0] == cur:
+                candidates.append(n)
+
+        if len(candidates) == 2:
+            node = candidates[0]
+        elif len(candidates) > 2:
+            raise util.Abort(_("multiple matching bookmarks to merge - "
+                "please merge with an explicit rev or bookmark"),
+                hint=_("run 'hg heads' to see all heads"))
+        elif len(candidates) <= 1:
+            raise util.Abort(_("no matching bookmark to merge - "
+                "please merge with an explicit rev or bookmark"),
+                hint=_("run 'hg heads' to see all heads"))
+
+    if not node and not repo._bookmarkcurrent:
+        nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
+
+        if len(nbhs) > 2:
             raise util.Abort(_("branch '%s' has %d heads - "
                                "please merge with an explicit rev")
                              % (branch, len(bheads)),
                              hint=_("run 'hg heads .' to see heads"))
 
         parent = repo.dirstate.p1()
-        if len(bheads) == 1:
+        if len(nbhs) == 1:
+            if len(bheads) > 1:
+                raise util.Abort(_("heads are bookmarked - "
+                                   "please merge with an explicit rev"),
+                                 hint=_("run 'hg heads' to see all heads"))
             if len(repo.heads()) > 1:
                 raise util.Abort(_("branch '%s' has one head - "
                                    "please merge with an explicit rev")
@@ -4184,9 +4211,7 @@
             raise util.Abort(_('working directory not at a head revision'),
                              hint=_("use 'hg update' or merge with an "
                                     "explicit revision"))
-        node = parent == bheads[0] and bheads[-1] or bheads[0]
-    else:
-        node = scmutil.revsingle(repo, node).node()
+        node = parent == nbhs[0] and nbhs[-1] or [0]
 
     if opts.get('preview'):
         # find nodes that are ancestors of p2 but not of p1
diff --git a/tests/test-bookmarks-merge.t b/tests/test-bookmarks-merge.t
--- a/tests/test-bookmarks-merge.t
+++ b/tests/test-bookmarks-merge.t
@@ -29,3 +29,41 @@
   $ hg bookmarks
      b                         1:d2ae7f538514
    * c                         3:b8f96cf4688b
+
+  $ hg up -C 3
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo d > d
+  $ hg add d
+  $ hg commit -m'd'
+
+  $ hg up -C 3
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo e > e
+  $ hg add e
+  $ hg commit -m'e'
+  created new head
+  $ hg up -C 5
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg bookmark e
+  $ hg bookmarks
+     b                         1:d2ae7f538514
+     c                         3:b8f96cf4688b
+   * e                         5:26bee9c5bcf3
+
+# the picked side is bookmarked
+
+  $ hg up -C 4
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge
+  abort: heads are bookmarked - please merge with an explicit rev
+  (run 'hg heads' to see all heads)
+  [255]
+
+# our revision is bookmarked
+
+  $ hg up -C e
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge
+  abort: no matching bookmark to merge - please merge with an explicit rev or bookmark
+  (run 'hg heads' to see all heads)
+  [255]
diff --git a/tests/test-convert-hg-source.t b/tests/test-convert-hg-source.t
--- a/tests/test-convert-hg-source.t
+++ b/tests/test-convert-hg-source.t
@@ -19,7 +19,7 @@
   $ hg ci -m 'make bar and baz copies of foo' -d '2 0'
   created new head
   $ hg bookmark premerge1
-  $ hg merge
+  $ hg merge -r 1
   merging baz and foo to baz
   1 files updated, 1 files merged, 0 files removed, 0 files unresolved
   (branch merge, don't forget to commit)


More information about the Mercurial-devel mailing list