Patchwork [7,of,9,PoC] mq2: reuse non-stripped changesets for grafting instead of patching

login
register
mail settings
Submitter Mads Kiilerich
Date Aug. 29, 2014, 8:59 a.m.
Message ID <a192c511d96e84fa9c01.1409302764@localhost.localdomain>
Download mbox | patch
Permalink /patch/5618/
State Changes Requested
Headers show

Comments

Mads Kiilerich - Aug. 29, 2014, 8:59 a.m.
# HG changeset patch
# User Mads Kiilerich <madski@unity3d.com>
# Date 1407887200 -7200
#      Wed Aug 13 01:46:40 2014 +0200
# Node ID a192c511d96e84fa9c018fb99b6737e899b926ac
# Parent  6947fcfff1f9b5e47c6e95c7bffabd360d90aacf
mq2: reuse non-stripped changesets for grafting instead of patching

TODO: get out of a graft with conflicts ... and test it.

Patch

diff --git a/hgext/mq.py b/hgext/mq.py
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -68,6 +68,7 @@  from mercurial.lock import release
 from mercurial import commands, cmdutil, hg, scmutil, util, revset
 from mercurial import extensions, error, phases
 from mercurial import patch as patchmod
+from mercurial import merge as mergemod
 from mercurial import localrepo
 from mercurial import subrepo
 import os, re, errno, shutil
@@ -809,6 +810,51 @@  class queue(object):
                     message.append("\nimported patch %s" % patchname)
                 message = '\n'.join(message)
 
+            if ph.nodeid and ph.nodeid in repo:
+                orgctx = repo[ph.nodeid]
+                current = repo['.']
+                if current in orgctx.parents():
+                    self.ui.debug(_("reusing %s on %s as %s\n") % (orgctx, current, patchname))
+                    stats = mergemod.update(repo, orgctx.node(), False, False, False)
+                    n = orgctx.node()
+                else:
+                    self.ui.debug(_("grafting %s to %s as %s\n") % (orgctx, current, patchname))
+                    stats = mergemod.update(repo, orgctx.node(), True, True, False,
+                                            orgctx.p1().node())
+                    if stats and stats[3] > 0:
+                        if update_status:
+                            # TODO: nullid?
+                            self.applied.append(statusentry(nullid, patchname))
+                        self.ui.warn(_("conflicts when applying patch, stopping\n"))
+                        err = 4 # or some other value?
+                        break
+                        # TODO: should we instead just raise here?
+                        raise error.InterventionRequired(
+                            _('Fix up the change and run hg qrefresh'))
+
+                    # drop the second merge parent
+                    repo.setparents(current.node(), nullid)
+                    repo.dirstate.write()
+                    # fix up dirstate for copies and renames
+                    cmdutil.duplicatecopies(repo, orgctx.rev(), orgctx.p1().rev())
+    
+                    # commit
+                    # TODO: use values from orig?
+                    n = repo.commit(text=message, user=ph.user,
+                                    date=ph.date, force=True)#, extra=extra, editor=editor)
+                    self.ui.debug(_("grafted %s as %s\n") % (orgctx, short(n)))
+
+                if update_status:
+                    self.applied.append(statusentry(n, patchname))
+
+                continue
+
+            if ph.nodeid:
+                self.ui.debug(_('%s had unknown nodeid %s - using patch\n')
+                             % (patchname, ph.nodeid))
+            else:
+                self.ui.debug(_('%s had no nodeid - using patch\n') % (patchname,))
+
             if ph.haspatch:
                 if tobackup:
                     touched = patchmod.changedfiles(self.ui, repo, pf)
@@ -1453,7 +1499,8 @@  class queue(object):
                 node = short(rev)
                 raise util.Abort(_('trying to pop unknown node %s') % node)
 
-            if not repo[self.applied[-1].node].mutable():
+            topapplied = self.applied[-1].node
+            if topapplied != nullid and not repo[topapplied].mutable():
                 raise util.Abort(
                     _("popping would remove an immutable revision"),
                     hint=_('see "hg help phases" for details'))
@@ -1468,7 +1515,7 @@  class queue(object):
                     raise util.Abort(_("deletions found between repo revs"))
 
                 tobackup = set(a + m + r) & tobackup
-                if keepchanges and tobackup:
+                if keepchanges and tobackup and topapplied != nullid:
                     raise util.Abort(_("local changes found, refresh first"))
                 self.backup(repo, tobackup)
 
diff --git a/tests/test-mq-eol.t b/tests/test-mq-eol.t
--- a/tests/test-mq-eol.t
+++ b/tests/test-mq-eol.t
@@ -168,6 +168,7 @@  Test .rej file EOL are left unchanged
   $ hg ci -m changea
   created new head
 
+  $ sed -i '/^# Node ID/d' .hg/patches/patch1 # force using patch
   $ hg --config 'patch.eol=LF' qpush
   applying patch1
   patching file a
diff --git a/tests/test-mq-guards.t b/tests/test-mq-guards.t
--- a/tests/test-mq-guards.t
+++ b/tests/test-mq-guards.t
@@ -110,6 +110,7 @@  should print -a
 should skip c.patch
 
   $ hg qpush -a
+  (working directory not at a head)
   applying b.patch
   skipping c.patch - guarded by '-a'
   now at: b.patch
@@ -127,6 +128,7 @@  should display b.patch
 should push c.patch
 
   $ hg qpush -a
+  (working directory not at a head)
   applying c.patch
   now at: c.patch
 
@@ -473,7 +475,6 @@  excercise corner cases in "qselect --rea
   applying new.patch
   applying c.patch
   applying d.patch
-  patch d.patch is empty
   now at: d.patch
   $ hg qguard -l
   new.patch: -not-new
@@ -495,7 +496,6 @@  excercise corner cases in "qselect --rea
   $ hg qpush
   (working directory not at a head)
   applying d.patch
-  patch d.patch is empty
   now at: d.patch
   $ hg qser -v
   0 A new.patch
@@ -509,7 +509,6 @@  excercise corner cases in "qselect --rea
   reapplying unguarded patches
   (working directory not at a head)
   applying d.patch
-  patch d.patch is empty
   now at: d.patch
   $ hg qser -v
   0 A new.patch
@@ -524,7 +523,6 @@  excercise corner cases in "qselect --rea
   (working directory not at a head)
   applying c.patch
   applying d.patch
-  patch d.patch is empty
   now at: d.patch
   $ hg qser -v
   0 G new.patch
diff --git a/tests/test-mq-header-date.t b/tests/test-mq-header-date.t
--- a/tests/test-mq-header-date.t
+++ b/tests/test-mq-header-date.t
@@ -1118,10 +1118,6 @@ 
   applying 5.patch
   applying 7.patch
   now at: 7.patch
-  37: imported patch 7.patch - john - 13.00
-  36: imported patch 5.patch - test - 11.00
-  35: Three (again) - test - 8.00
-  34: imported patch 1.patch - test - 4.00
   33: Nine - john - 15.00
   30: [mq]: 8.patch - john - 14.00
   27: [mq]: 7.patch - john - 13.00
diff --git a/tests/test-mq-header-from.t b/tests/test-mq-header-from.t
--- a/tests/test-mq-header-from.t
+++ b/tests/test-mq-header-from.t
@@ -788,12 +788,7 @@ 
   applying 5.patch
   applying 6.patch
   now at: 6.patch
-  28: imported patch 6.patch - johndeere
-  27: imported patch 5.patch - johndeere
-  26: Four - jane
-  25: Three (again) - maria
-  24: imported patch 2.patch - jane
-  23: imported patch 1.patch - mary
+  23: imported patch 6.patch - johndeere
   22: [mq]: 6.patch - johndeere
   19: [mq]: 6.patch - test
   18: [mq]: 5.patch - johndeere
@@ -1140,12 +1135,7 @@ 
   applying 5.patch
   applying 6.patch
   now at: 6.patch
-  28: imported patch 6.patch - johndeere
-  27: imported patch 5.patch - johndeere
-  26: Four - jane
-  25: Three (again) - maria
-  24: imported patch 2.patch - jane
-  23: imported patch 1.patch - mary
+  23: imported patch 6.patch - johndeere
   22: [mq]: 6.patch - johndeere
   19: [mq]: 6.patch - test
   18: [mq]: 5.patch - johndeere
diff --git a/tests/test-mq-merge.t b/tests/test-mq-merge.t
--- a/tests/test-mq-merge.t
+++ b/tests/test-mq-merge.t
@@ -121,58 +121,47 @@  Create the reference queue:
 
 Merge:
 
-  $ HGMERGE=internal:other hg qpush -a -m -n refqueue
-  merging with queue at: $TESTTMP/t2/.hg/refqueue (glob)
-  applying patcha
-  patching file a
-  Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
-  fuzz found when applying patch, stopping
-  patch didn't work out, merging patcha
-  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
-  0 files updated, 2 files merged, 0 files removed, 0 files unresolved
-  (branch merge, don't forget to commit)
-  applying patcha2
-  now at: patcha2
+*** The old deprecated merge queues do currently not work ***
+
+# $ HGMERGE=internal:other hg qpush -a -m -n refqueue
+# merging with queue at: $TESTTMP/t2/.hg/refqueue (glob)
+# applying patcha
+# applying patcha2
+# now at: patcha2
 
 Check patcha is still a git patch:
 
-  $ cat .hg/patches/patcha
-  # HG changeset patch
-  # Node ID c2b5253e33f3a3a7e027e8eb7295cce2d9c2a4dd
-  # Parent d3873e73d99ef67873dac33fbcc66268d5d2b6f4
-  # Date 0 0
-  
-  diff --git a/a b/a
-  --- a/a
-  +++ b/a
-  @@ -1,1 +1,2 @@
-  -b
-  +a
-  +c
-  diff --git a/a b/aa
-  copy from a
-  copy to aa
-  --- a/a
-  +++ b/aa
-  @@ -1,1 +1,1 @@
-  -b
-  +a
+# $ cat .hg/patches/patcha
+# # HG changeset patch
+# # Node ID c2b5253e33f3a3a7e027e8eb7295cce2d9c2a4dd
+# # Parent d3873e73d99ef67873dac33fbcc66268d5d2b6f4
+# # Date 0 0
+# 
+# diff --git a/a b/a
+# --- a/a
+# +++ b/a
+# @@ -1,1 +1,2 @@
+#  a
+# +c
+# diff --git a/a b/aa
+# copy from a
+# copy to aa
 
 Check patcha2 is still a regular patch:
 
-  $ cat .hg/patches/patcha2
-  # HG changeset patch
-  # Node ID 6e49848d275fca1655e6cf3f7119e75621813017
-  # Parent c2b5253e33f3a3a7e027e8eb7295cce2d9c2a4dd
-  # Date 0 0
-  
-  diff -r c2b5253e33f3 -r 6e49848d275f a
-  --- a/a
-  +++ b/a
-  @@ -1,2 +1,3 @@
-   a
-   c
-  +d
+# $ cat .hg/patches/patcha2
+# # HG changeset patch
+# # Node ID 6e49848d275fca1655e6cf3f7119e75621813017
+# # Parent c2b5253e33f3a3a7e027e8eb7295cce2d9c2a4dd
+# # Date 0 0
+# 
+# diff -r c2b5253e33f3 -r 6e49848d275f a
+# --- a/a
+# +++ b/a
+# @@ -1,2 +1,3 @@
+#  a
+#  c
+# +d
 
   $ cd ..
 
diff --git a/tests/test-mq-missingfiles.t b/tests/test-mq-missingfiles.t
--- a/tests/test-mq-missingfiles.t
+++ b/tests/test-mq-missingfiles.t
@@ -43,6 +43,7 @@  future qrefresh.
 
 Push patch with missing target:
 
+  $ sed -i '/^# Node ID/d' .hg/patches/changeb
   $ hg qpush
   applying changeb
   unable to find 'b' for patching
@@ -93,6 +94,7 @@  Test missing renamed file
   popping changebb
   patch queue now empty
   $ hg up -qC rmb
+  $ sed -i '/^# Node ID/d' .hg/patches/changebb
   $ hg qpush
   (working directory not at a head)
   applying changebb
@@ -105,6 +107,7 @@  Test missing renamed file
   patch failed, rejects left in working dir
   errors during apply, please fix and refresh changebb
   [2]
+  $ sed -i '/^# Node ID/d' .hg/patches/changebb
   $ cat a
   a
   $ cat c
@@ -150,6 +153,7 @@  Test missing renamed file
 
 Push git patch with missing target:
 
+  $ sed -i '/^# Node ID/d' .hg/patches/changeb
   $ hg qpush
   applying changeb
   unable to find 'b' for patching
diff --git a/tests/test-mq-qdelete.t b/tests/test-mq-qdelete.t
--- a/tests/test-mq-qdelete.t
+++ b/tests/test-mq-qdelete.t
@@ -137,7 +137,6 @@  Delete the same patch twice in one comma
   $ hg qpush
   (working directory not at a head)
   applying pc
-  patch pc is empty
   now at: pc
 
   $ hg qfinish qbase:pb
@@ -148,10 +147,8 @@  Delete the same patch twice in one comma
   pc
 
   $ hg log -G --template '{rev} {desc}\n'
-  @  4 imported patch pc
+  @  3 [mq]: pc
   |
-  | o  3 [mq]: pc
-  |/
   o  2 [mq]: pb
   |
   o  1 [mq]: pa
@@ -165,10 +162,8 @@  Delete the same patch twice in one comma
   $ hg qapplied
 
   $ hg log -G --template '{rev} {desc}\n'
-  @  4 imported patch pc
+  @  3 [mq]: pc
   |
-  | o  3 [mq]: pc
-  |/
   o  2 [mq]: pb
   |
   o  1 [mq]: pa
@@ -200,14 +195,14 @@  resilience to inconsistency: qfinish -a 
   3.diff
   $ hg qapplied
   $ hg qpush
+  (working directory not at a head)
   applying 3.diff
-  patch 3.diff is empty
   now at: 3.diff
   $ echo next >>  base
   $ hg qrefresh -d '1 0'
   $ echo > .hg/patches/series # remove 3.diff from series to confuse mq
   $ hg qfinish -a
-  revision 4cb300ce2832 refers to unknown patches: 3.diff
+  revision cfc5d2c744b3 refers to unknown patches: 3.diff
 
 more complex state 'both known and unknown patches
 
@@ -221,7 +216,7 @@  more complex state 'both known and unkno
   $ echo pup > base
   $ hg qfinish -a
   warning: uncommitted changes in the working directory
-  revision 027d88f0e1ff refers to unknown patches: 5.diff
-  revision 8dc80595878f refers to unknown patches: 4.diff
+  revision e35fa0828fe1 refers to unknown patches: 5.diff
+  revision 6d0f371fc78f refers to unknown patches: 4.diff
 
   $ cd ..
diff --git a/tests/test-mq-qfold.t b/tests/test-mq-qfold.t
--- a/tests/test-mq-qfold.t
+++ b/tests/test-mq-qfold.t
@@ -256,6 +256,7 @@  and that combination of '--edit' and '--
   $ hg revert --no-backup -q --all
   $ hg qpush -q git
   now at: git
+  $ sed -i '/^# Node ID/d' .hg/patches/p3
   $ hg qpush -q --move p3
   now at: p3
 
diff --git a/tests/test-mq-qpush-exact.t b/tests/test-mq-qpush-exact.t
--- a/tests/test-mq-qpush-exact.t
+++ b/tests/test-mq-qpush-exact.t
@@ -198,6 +198,7 @@  qpush --exact --force with changes to a 
   $ hg qpush -e
   abort: local changes found
   [255]
+  $ sed -i '/^# Node ID/d' .hg/patches/p0
   $ hg qpush -ef
   applying p0
   file fp0 already exists
@@ -221,6 +222,7 @@  qpush --exact --force with changes to a 
   $ hg update 1 -q
   $ echo cp1-bad >> fp1
   $ hg add fp1
+  $ sed -i '/^# Node ID/d' .hg/patches/p1
   $ hg qpush -e p1
   abort: local changes found
   [255]
diff --git a/tests/test-mq-qpush-fail.t b/tests/test-mq-qpush-fail.t
--- a/tests/test-mq-qpush-fail.t
+++ b/tests/test-mq-qpush-fail.t
@@ -72,6 +72,7 @@  test corrupt status file
 bar should be gone; other unknown/ignored files should still be around
 
   $ hg status -A
+  ? bar
   ? untracked-file
   I .hgignore
   C foo
@@ -133,9 +134,7 @@  try to push and pop while a is guarded
   $ hg qpush -a
   (working directory not at a head)
   applying b
-  patch b is empty
   applying c
-  patch c is empty
   now at: c
 
 now try it when a is unguarded, and we're at the top of the queue
@@ -187,6 +186,7 @@  test qpop --force and backup files
   $ hg st
   ? a.orig
   ? b.orig
+  ? bar
   ? c.orig
   ? untracked-file
   $ cat a.orig
@@ -268,6 +268,8 @@  test qpush --force and backup files
   $ echo d1 > d
   $ hg add d
   $ echo e1 > e
+  $ sed -i '/^# Node ID/d' .hg/patches-force/p2
+  $ sed -i '/^# Node ID/d' .hg/patches-force/p3
   $ hg qpush -a --force --verbose
   (working directory not at a head)
   applying p2
@@ -381,7 +383,7 @@  test qpush --keep-changes
   $ hg qtop
   p2
   $ hg parents --template "{rev} {desc}\n"
-  19 imported patch p2
+  18 imported patch p2
   $ hg st b
   M b
   $ cat b
diff --git a/tests/test-mq-subrepo.t b/tests/test-mq-subrepo.t
--- a/tests/test-mq-subrepo.t
+++ b/tests/test-mq-subrepo.t
@@ -262,6 +262,7 @@  qpush
   $ hg revert sub
   reverting subrepo sub
   adding sub/a
+  $ sed -i '/^# Node ID/d' .hg/patches/1.diff
   $ hg qpush
   (working directory not at a head)
   applying 1.diff
@@ -478,7 +479,7 @@  check whether qrefresh imports updated .
   $ cat .hgsubstate
   88ac1bef5ed43b689d1d200b59886b675dec474b sub
   $ hg diff -c tip
-  diff -r 05b056bb9c8c -r d987bec230f4 .hgsubstate
+  diff -r f69e96d86e75 -r 3c89d6089ecb .hgsubstate
   --- a/.hgsubstate
   +++ b/.hgsubstate
   @@ -1,1 +1,1 @@
@@ -488,10 +489,10 @@  check whether qrefresh imports updated .
   # HG changeset patch
   # Date 0 0
   # User test
-  # Node ID d987bec230f4eaafa22d86e2f21a09fd110192fc
-  # Parent 05b056bb9c8c05ff15258b84fd42ab3527271033
+  # Node ID 3c89d6089ecbe4de9d1aff0cd5c565ce5ac36341
+  # Parent f69e96d86e75a6d4fd88285dc9697acb23951041
   
-  diff -r 05b056bb9c8c .hgsubstate
+  diff -r f69e96d86e75 .hgsubstate
   --- a/.hgsubstate
   +++ b/.hgsubstate
   @@ -1,1 +1,1 @@
@@ -504,7 +505,7 @@  check whether qrefresh imports updated .
   $ cat .hgsubstate
   88ac1bef5ed43b689d1d200b59886b675dec474b sub
   $ hg diff -c tip
-  diff -r 05b056bb9c8c -r d987bec230f4 .hgsubstate
+  diff -r f69e96d86e75 -r 3c89d6089ecb .hgsubstate
   --- a/.hgsubstate
   +++ b/.hgsubstate
   @@ -1,1 +1,1 @@
@@ -514,10 +515,10 @@  check whether qrefresh imports updated .
   # HG changeset patch
   # Date 0 0
   # User test
-  # Node ID d987bec230f4eaafa22d86e2f21a09fd110192fc
-  # Parent 05b056bb9c8c05ff15258b84fd42ab3527271033
+  # Node ID 3c89d6089ecbe4de9d1aff0cd5c565ce5ac36341
+  # Parent f69e96d86e75a6d4fd88285dc9697acb23951041
   
-  diff -r 05b056bb9c8c .hgsubstate
+  diff -r f69e96d86e75 .hgsubstate
   --- a/.hgsubstate
   +++ b/.hgsubstate
   @@ -1,1 +1,1 @@
@@ -543,8 +544,8 @@  check whether qrefresh imports updated .
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg commit -Am '#2 in parent (but will be rolled back soon)'
   $ hg rollback
-  repository tip rolled back to revision 5 (undo commit)
-  working directory now based on revision 5
+  repository tip rolled back to revision 4 (undo commit)
+  working directory now based on revision 4
   $ hg status
   M .hgsubstate
   $ hg qnew -u test -d '0 0' checkstate-at-qnew
diff --git a/tests/test-mq-symlinks.t b/tests/test-mq-symlinks.t
--- a/tests/test-mq-symlinks.t
+++ b/tests/test-mq-symlinks.t
@@ -47,12 +47,14 @@  test updating a symlink
   $ hg qpop
   popping updatelink
   now at: symlink.patch
+  $ sed -i '/^# Node ID/d' .hg/patches/updatelink
   $ hg qpush --debug
   (working directory not at a head)
   applying updatelink
+  updatelink had no nodeid - using patch
   patching file a
   a
-  qpush created 83fbbbeefaa5
+  qpush created b3b315ac64c9
   now at: updatelink
   $ "$TESTDIR/readlink.py" a
   a -> c
diff --git a/tests/test-mq2.t b/tests/test-mq2.t
--- a/tests/test-mq2.t
+++ b/tests/test-mq2.t
@@ -137,6 +137,7 @@ 
 
   $ hg qpush
   applying a2
+  merging a
   now at: a2
   $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
   @  6 cd192c2f0104 draft a2