[PATCH V2] rebase: add flag to commit to insert commit in stack

cdelahousse at fb.com cdelahousse at fb.com
Wed Nov 25 23:03:08 UTC 2015


# HG changeset patch
# User Christian Delahousse <cdelahousse at fb.com>
# Date 1448492314 28800
#      Wed Nov 25 14:58:34 2015 -0800
# Node ID aa9a87863f9af5ad37d477131196a65d5437d116
# Parent  61fbf5dc12b23e7a2a30cf04ebd9f096c42a1f61
rebase: add flag to commit to insert commit in stack

This patch adds a flag to insert a commit within an existing stack without
forcing the user to do a separate rebase step. From the call to commit --insert,
the tool flag is passed into our call to rebase in case the user specifies it.

If the rebase portion fails, the user is prompted on how to proceed. If --amend
is passed in, the current commit is amended and the stack is maintained
on top of the new commit.

A new test file is created because as there was no existing suitable place to
test the functionality.

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -1229,6 +1229,35 @@
 
     return obsoletenotrebased
 
+def commitinsert(orig, ui, repo, *args, **opts):
+    '''Insert a commit and rebase the current descendants on top of it
+    '''
+    ret = None
+    if opts.get('insert'):
+        wlock = lock = None
+        try:
+            wlock = repo.wlock()
+            lock = repo.lock()
+            descendants = list(repo.revs('(.::) - .'))
+            ret = orig(ui, repo, *args, **opts)
+            rebaseopts = {
+                'dest' : '.',
+                'rev' : descendants,
+                'tool': opts.get('tool')
+            }
+
+            try:
+                rebase(ui, repo, **rebaseopts)
+            except error.InterventionRequired:
+                raise error.Abort(_('commit --insert failed during rebase '
+                    'because of unresolved conflicts'), hint=_('see hg '
+                    'resolve, then hg rebase --continue or hg rebase --abort'))
+        finally:
+            release(lock, wlock)
+    else:
+        ret = orig(ui, repo, *args, **opts)
+    return ret
+
 def summaryhook(ui, repo):
     if not os.path.exists(repo.join('rebasestate')):
         return
@@ -1248,6 +1277,10 @@
 
 def uisetup(ui):
     #Replace pull with a decorator to provide --rebase option
+    entry = extensions.wrapcommand(commands.table, 'commit', commitinsert)
+    entry[1].append(('', 'insert', None,
+                     _('insert a commit after the current one and rebase '
+                        'descendants on top of it')))
     entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
     entry[1].append(('', 'rebase', None,
                      _("rebase working directory to branch head")))
diff --git a/tests/test-commit-insert.t b/tests/test-commit-insert.t
new file mode 100644
--- /dev/null
+++ b/tests/test-commit-insert.t
@@ -0,0 +1,104 @@
+  $ cat >> $HGRCPATH << EOF
+  > [ui]
+  > logtemplate={rev}:{node|short} {desc|firstline}
+  > [experimental]
+  > evolution=createmarkers,allowunstable
+  > [phases]
+  > publish=False
+  > [extensions]
+  > rebase=
+  > EOF
+
+  $ mkcommit() {
+  >    echo "$1" > "$1"
+  >    hg add "$1"
+  >    hg ci -m "add $1"
+  > }
+
+  $ mkinsert() {
+  >    echo "$1" > "$1"
+  >    hg add "$1"
+  >    hg commit --insert -m "add $1"
+  > }
+
+Test commit --insert inserts a commit midway through the stack and rebases
+  $ hg init repo
+  $ cd repo
+  $ mkcommit a
+  $ mkcommit b
+  $ mkcommit c
+  $ mkcommit d
+  $ mkcommit e
+  $ hg up -r 'desc(b)' -q
+  $ mkcommit f
+  created new head
+  $ hg up -r 'desc(b)' -q
+  $ hg log -G
+  o  5:62d48859d3ff add f
+  |
+  | o  4:9d206ffc875e add e
+  | |
+  | o  3:47d2a3944de8 add d
+  | |
+  | o  2:4538525df7e2 add c
+  |/
+  @  1:7c3bad9141dc add b
+  |
+  o  0:1f0dee641bb7 add a
+  
+  $ mkinsert inserted
+  created new head
+  rebasing 2:4538525df7e2 "add c"
+  rebasing 3:47d2a3944de8 "add d"
+  rebasing 4:9d206ffc875e "add e"
+  rebasing 5:62d48859d3ff "add f"
+  $ hg log -G
+  o  10:e8b1420e489a add f
+  |
+  | o  9:f15deecf3961 add e
+  | |
+  | o  8:5c44ffbdf4bc add d
+  | |
+  | o  7:40e9af76281f add c
+  |/
+  @  6:76c6dadac81f add inserted
+  |
+  o  1:7c3bad9141dc add b
+  |
+  o  0:1f0dee641bb7 add a
+  
+Test commit with both --amend and --insert amends the commit properly
+  $ echo 'content' > inserted
+  $ hg commit --amend --insert --message 'modified inserted' -q
+  $ hg log -G
+  o  16:a3b1913b9e14 add f
+  |
+  | o  15:e51039ab4348 add e
+  | |
+  | o  14:9bd4195e1b56 add d
+  | |
+  | o  13:c2484d20e987 add c
+  |/
+  @  12:cc2ad5e24cd3 modified inserted
+  |
+  o  1:7c3bad9141dc add b
+  |
+  o  0:1f0dee641bb7 add a
+  
+
+Test rebase conflict
+  $ hg up -r 'desc(f)' -q
+  $ echo 'ff' > f
+  $ hg commit --amend
+  $ hg up '.^'
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo '' > f
+  $ hg add f
+  $ hg commit --insert --message 'add f that will conflict' -q
+  warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
+  abort: commit --insert failed during rebase because of unresolved conflicts
+  (see hg resolve, then hg rebase --continue or hg rebase --abort)
+  [255]
+
+  $ hg rebase --abort -q
+  rebase aborted


More information about the Mercurial-devel mailing list