Patchwork [1,of,2,V2] graft: allow creating sibling grafts

login
register
mail settings
Submitter Durham Goode
Date April 7, 2015, 1:28 a.m.
Message ID <cd7d644d0389ae9cf8a5.1428370130@dev2000.prn2.facebook.com>
Download mbox | patch
Permalink /patch/8519/
State Accepted
Headers show

Comments

Durham Goode - April 7, 2015, 1:28 a.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1428260138 25200
#      Sun Apr 05 11:55:38 2015 -0700
# Node ID cd7d644d0389ae9cf8a54d7b7033fdc5a98b4483
# Parent  4a4018831d2ebc3c9cae9c6613e6a2497b4f0993
graft: allow creating sibling grafts

Previously it was impossible to graft a commit onto it's own parent (i.e. create
a copy of the commit). This is useful when wanting to create a backup of the
commit before continuing to amend it. This patch enables that behavior.

The change to the histedit test is because histedit uses graft to apply commits.
The test in question moves a commit backwards onto an ancestor. Since the graft
logic now more explicitly supports this, it knows to simply accept the incoming
changes (since they are more recent), instead of prompting.

Patch

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -1184,9 +1184,17 @@  def graft(repo, ctx, pctx, labels):
     labels - merge labels eg ['local', 'graft']
 
     """
+    # If we're grafting a descendant onto an ancestor, be sure to pass
+    # mergeancestor=True to update. This does two things: 1) allows the merge if
+    # the destination is the same as the parent of the ctx (so we can use graft
+    # to copy commits), and 2) informs update that the incoming changes are
+    # newer than the destination so it doesn't prompt about "remote changed foo
+    # which local deleted".
+    mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
 
     stats = update(repo, ctx.node(), True, True, False, pctx.node(),
-                   labels=labels)
+                   mergeancestor=mergeancestor, labels=labels)
+
     # drop the second merge parent
     repo.dirstate.beginparentchange()
     repo.setparents(repo['.'].node(), nullid)
diff --git a/tests/test-graft.t b/tests/test-graft.t
--- a/tests/test-graft.t
+++ b/tests/test-graft.t
@@ -730,3 +730,29 @@  Empty graft
   $ hg graft -f 27
   grafting 27:3d35c4c79e5a "28"
   note: graft of 27:3d35c4c79e5a created no changes to commit
+
+  $ cd ..
+
+Graft to duplicate a commit
+
+  $ hg init graftsibling
+  $ cd graftsibling
+  $ touch a
+  $ hg commit -qAm a
+  $ touch b
+  $ hg commit -qAm b
+  $ hg log -G -T '{rev}\n'
+  @  1
+  |
+  o  0
+  
+  $ hg up -q 0
+  $ hg graft -r 1
+  grafting 1:0e067c57feba "b" (tip)
+  $ hg log -G -T '{rev}\n'
+  @  2
+  |
+  | o  1
+  |/
+  o  0
+  
diff --git a/tests/test-histedit-non-commute-abort.t b/tests/test-histedit-non-commute-abort.t
--- a/tests/test-histedit-non-commute-abort.t
+++ b/tests/test-histedit-non-commute-abort.t
@@ -70,8 +70,6 @@  edit the history
   > pick 652413bf663e f
   > EOF
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
-  remote changed e which local deleted
-  use (c)hanged version or leave (d)eleted? c
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   merging e
   warning: conflicts during merge.