[PATCH] backout: provide linear backout as a default (without --merge option)

Gilles Moris gilles.moris at free.fr
Tue Sep 21 06:53:46 CDT 2010


# HG changeset patch
# User Gilles Moris <gilles.moris at free.fr>
# Date 1284107298 -7200
# Node ID 478385c46665cdc7192e0f876a2e8b2bc957f2fc
# Parent  17feeef6da9ed761c416d3b054dc7cc0247e6269
backout: provide linear backout as a default (without --merge option)

This change enables to have a backout changeset that will keep the
history linear, i.e. committed as a child of the working directory parent.

The default behavior was previously to just commit a reverted change as a
child of the backed out changeset and thus creating a new head. Most of
the time, you would use the --merge option, as it does not make sense to
keep this dangling head as is.
The previous behavior can be restored using 'hg update --clean .' after a
'hg backout --merge'.

The --merge option itself is not affected by this change. There is also
still an autocommit of the backout if a merge is not needed, i.e. in case
of the backout of the parent of the working directory.

So previously we had (pwd = parent of the working directory):
                  pwd     older
backout           auto    merge
backout --merge   auto    commit

With the new linear approach:
                  pwd     older
backout           auto    commit
backout --merge   auto    commit

auto: commit done by the backout command
merge: backout also already committed but explicit merge and commit needed
commit: user need to commit the update/merge

diff -r 17feeef6da9e -r 478385c46665 mercurial/commands.py
--- a/mercurial/commands.py	Thu Feb 12 22:55:51 2009 +0100
+++ b/mercurial/commands.py	Fri Sep 10 10:28:18 2010 +0200
@@ -204,17 +204,26 @@
 def backout(ui, repo, node=None, rev=None, **opts):
     '''reverse effect of earlier changeset
 
-    Commit the backed out changes as a new changeset. The new
-    changeset is a child of the backed out changeset.
-
-    If you backout a changeset other than the tip, a new head is
-    created. This head will be the new tip and you should merge this
-    backout changeset with another head.
-
+    The backout command merges the reverse effect of the backed out
+    changeset into the working directory.
+
+    With the --merge option, it first commit the backed out changes
+    as a new changeset. This new changeset is a child of the backed
+    out changeset.
     The --merge option remembers the parent of the working directory
     before starting the backout, then merges the new head with that
-    changeset afterwards. This saves you from doing the merge by hand.
-    The result of this merge is not committed, as with a normal merge.
+    changeset afterwards.
+    This will result in an explicit merge in the history log.
+
+    If you backout a changeset other than the original parent of the
+    working directory, the result of this merge is not committed,
+    as with a normal merge. Otherwise, no merge is needed and the
+    commit is automatic.
+
+    Note that the default behavior (without --merge) has changed in
+    version 1.7. To restore the previous default behaviour, use
+    :hg:`backout --merge` and then :hg:`update --clean .` to get rid of
+    the ongoing merge.
 
     See :hg:`help dates` for a list of formats valid for -d/--date.
 
@@ -268,6 +277,9 @@
     revert_opts['rev'] = hex(parent)
     revert_opts['no_backup'] = None
     revert(ui, repo, **revert_opts)
+    if not opts.get('merge') and op1 != node:
+        return hg.update(repo, op1)
+
     commit_opts = opts.copy()
     commit_opts['addremove'] = False
     if not commit_opts['message'] and not commit_opts['logfile']:
@@ -279,17 +291,12 @@
         return '%d:%s' % (repo.changelog.rev(node), short(node))
     ui.status(_('changeset %s backs out changeset %s\n') %
               (nice(repo.changelog.tip()), nice(node)))
-    if op1 != node:
+    if opts.get('merge') and op1 != node:
         hg.clean(repo, op1, show_stats=False)
-        if opts.get('merge'):
-            ui.status(_('merging with changeset %s\n')
-                      % nice(repo.changelog.tip()))
-            hg.merge(repo, hex(repo.changelog.tip()))
-        else:
-            ui.status(_('the backout changeset is a new head - '
-                        'do not forget to merge\n'))
-            ui.status(_('(use "backout --merge" '
-                        'if you want to auto-merge)\n'))
+        ui.status(_('merging with changeset %s\n')
+                  % nice(repo.changelog.tip()))
+        return hg.merge(repo, hex(repo.changelog.tip()))
+    return 0
 
 def bisect(ui, repo, rev=None, extra=None, command=None,
                reset=None, good=None, bad=None, skip=None, noupdate=None):
diff -r 17feeef6da9e -r 478385c46665 tests/test-backout.t
--- a/tests/test-backout.t	Thu Feb 12 22:55:51 2009 +0100
+++ b/tests/test-backout.t	Fri Sep 10 10:28:18 2010 +0200
@@ -39,7 +39,7 @@
   $ hg rm a
   $ hg commit -d '1 0' -m b
 
-  $ hg backout -d '2 0' --merge tip
+  $ hg backout -d '2 0' tip
   adding a
   changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
   $ cat a
@@ -131,12 +131,26 @@
   $ echo 1 > b
   $ hg commit -d '2 0' -A -m c
   adding b
+
+without --merge
   $ hg backout -d '3 0' 1
   reverting a
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg locate b
+  b
+  $ hg update -C tip
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg locate b
+  b
+
+with --merge
+  $ hg backout --merge -d '3 0' 1
+  reverting a
   created new head
   changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
-  the backout changeset is a new head - do not forget to merge
-  (use "backout --merge" if you want to auto-merge)
+  merging with changeset 3:3202beb76721
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
   $ hg locate b
   b
   $ hg update -C tip
@@ -220,14 +234,28 @@
   $ echo branch2 > file2
   $ hg ci -d '2 0' -Am file2
   adding file2
-  $ hg backout -d '3 0' -r 1 -m 'backout on branch1'
+
+without --merge
+  $ hg backout -r 1
+  removing file1
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg branch
+  branch2
+  $ hg status -A
+  R file1
+  C default
+  C file2
+
+with --merge
+  $ hg update -qC
+  $ hg backout --merge -d '3 0' -r 1 -m 'backout on branch1'
   removing file1
   created new head
   changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
-  the backout changeset is a new head - do not forget to merge
-  (use "backout --merge" if you want to auto-merge)
-
-XXX maybe backout shouldn't suggest a merge here as it is a different branch?
+  merging with changeset 3:d4e8f6db59fb
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg update -q -C 2
 
 on branch2 with branch1 not merged, so file1 should still exist:
 


More information about the Mercurial-devel mailing list