Patchwork [4,of,6] merge: give priority to "not at head" failures for bare 'hg merge'

login
register
mail settings
Submitter Pierre-Yves David
Date Feb. 12, 2016, 2:29 p.m.
Message ID <d6574d816512a8d5e7ed.1455287347@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/13131/
State Accepted
Headers show

Comments

Pierre-Yves David - Feb. 12, 2016, 2:29 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1454939758 -3600
#      Mon Feb 08 14:55:58 2016 +0100
# Node ID d6574d816512a8d5e7ed4f8a36e4556ce6788393
# Parent  b28f7171ac9e1a35153b7bf7f9d448a6d1c08270
# EXP-Topic destination
# Available At http://hg.netv6.net/marmoute-wip/mercurial/
#              hg pull http://hg.netv6.net/marmoute-wip/mercurial/ -r d6574d816512
merge: give priority to "not at head" failures for bare 'hg merge'

We refuse to pick a destination for a bare 'hg merge' if the working copy is not
at head. This is meant to prevent strange merge from user who forget to update.
(Moreover, such merge does not reduce actually the number of heads)

However, we were doing that as the last possible failure type. So user were
recommended to merge with an explicit head (from this bad location) if the
branch had too many heads.

We now make "not on branch heads" class of failure the first things to check
and fail on. The one test that change was actually trying to check for these
failure (and did not). The new test output is correct.

Patch

diff --git a/mercurial/destutil.py b/mercurial/destutil.py
--- a/mercurial/destutil.py
+++ b/mercurial/destutil.py
@@ -191,35 +191,37 @@  def _destmergebook(repo):
     return node
 
 def _destmergebranch(repo):
     """find merge destination based on branch heads"""
     node = None
+    parent = repo.dirstate.p1()
     branch = repo[None].branch()
     bheads = repo.branchheads(branch)
     nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
 
+    if parent not in bheads:
+        if len(repo.heads()) <= 1:
+            msg, hint = msgdestmerge['nootherheadsbehind']
+        else:
+            msg, hint = msgdestmerge['notatheads']
+        raise error.Abort(msg, hint=hint)
+
     if len(nbhs) > 2:
         msg, hint = msgdestmerge['toomanyheads']
         msg %= (branch, len(bheads))
         raise error.Abort(msg, hint=hint)
 
-    parent = repo.dirstate.p1()
     if len(nbhs) <= 1:
         if len(bheads) > 1:
             msg, hint = msgdestmerge['bookmarkedheads']
         elif len(repo.heads()) > 1:
             msg, hint = msgdestmerge['nootherbranchheads']
             msg %= branch
-        elif parent != repo.lookup(branch):
-            msg, hint = msgdestmerge['nootherheadsbehind']
         else:
             msg, hint = msgdestmerge['nootherheads']
         raise error.Abort(msg, hint=hint)
 
-    if parent not in bheads:
-        msg, hint = msgdestmerge['notatheads']
-        raise error.Abort(msg, hint=hint)
     if parent == nbhs[0]:
         node = nbhs[-1]
     else:
         node = nbhs[0]
     assert node is not None
diff --git a/tests/test-merge-default.t b/tests/test-merge-default.t
--- a/tests/test-merge-default.t
+++ b/tests/test-merge-default.t
@@ -25,12 +25,12 @@ 
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 Should fail because not at a head:
 
   $ hg merge
-  abort: branch 'default' has 3 heads - please merge with an explicit rev
-  (run 'hg heads .' to see heads)
+  abort: working directory not at a head revision
+  (use 'hg update' or merge with an explicit revision)
   [255]
 
   $ hg up
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   2 other heads for branch "default"