Backing out a rename

Greg Ward gerg.ward+hg at gmail.com
Mon Oct 27 19:14:34 UTC 2008


I'm playing around with using "hg backout" to revert a changeset that
renamed and patched a file.  I love how the original changeset knows
that it's a rename with a patch, and you can see that in "hg view" or with
"hg diff --git".  But when I backout the rename, that information is
lost: now all I see is addition and removal of whole files.

Example: first, I setup the repository and add the file that will be
at the centre of things:

  $ hg init test
  $ cd test
  $ cat > frob.c
  /* frob.c
   *
   * frob the whizzbobulator until it begs for mercy
   */

  ...code...
  ^D
  $ hg add frob.c
  $ hg ci -m"Add code to frob the whizzbobulator." frob.c

Here comes the changeset that I'm going to backout: I rename frob.c and
edit so its content reflects the rename:

  $ hg mv frob.c klob.c
  $ [edit klob.c, changing "frob" to "klob"]
  $ hg ci -m"Terminology fix: it's klob, not frob."

What I *like* is that before that commit, "hg diff --git" knows that I
am doing a rename+patch.  Take that, CVS.  And after the commit,
"hg diff -r1 -r2 --git" shows the same thing, as does "hg view".  Rock on.

Now I decide my rename was bad, and the right terminology is in fact
"frob" not "klob".  So I backout r1:

  $ hg backout 1

Since there's no merge required, the backout is committed immediately as
r2.  But when I run "hg diff --git -r1 -r2", hg no longer realizes that
the changeset is a rename+patch; it thinks it's just one file being
added and another being removed.  ;-(

Here's the *good* diff, i.e. of the original rename+patch:

  $ hg diff --git -r0 -r1
  diff --git a/frob.c b/klob.c
  rename from frob.c
  rename to klob.c
  --- a/frob.c
  +++ b/klob.c
  @@ -1,6 +1,6 @@
  -/* frob.c
  +/* klob.c
    *
  - * frob the whizzbobulator until it begs for mercy
  + * klob the whizzbobulator until it begs for mercy
    */

  ...code...

And here is the diff of the backout, where hg has forgotten that the
change was a rename+patch:

  $ hg diff --git -r1 -r2
  diff --git a/frob.c b/frob.c
  new file mode 100644
  --- /dev/null
  +++ b/frob.c
  @@ -0,0 +1,6 @@
  +/* frob.c
  + *
  + * frob the whizzbobulator until it begs for mercy
  + */
  +
  +...code...
  diff --git a/klob.c b/klob.c
  deleted file mode 100644
  --- a/klob.c
  +++ /dev/null
  @@ -1,6 +0,0 @@
  -/* klob.c
  - *
  - * klob the whizzbobulator until it begs for mercy
  - */
  -
  -...code...

I can workaround this by manually backing out the rename:

  $ hg rollback      # undo the commit done by "hg backout"
  $ hg up -C         # throw away work done by "hg backout"
  $ hg mv klob.c frob.c
  $ hg diff --git -r0 -r1 | patch -p1 -R
patching file frob.c
  $ hg ci -m"Revert terminology fix: it really is frob, not klob."

This way, hg correctly realizes that both changesets are rename+patch
operations.

Is this a bug in backout?  (Oh yeah, I'm using hg 1.0.1.  Same behaviour
with my build of 1.0.1 under Python 2.5.1 on Fedora Core 4 or Ubuntu's
build on Ubuntu 8.04 (hardy).)

        Greg



More information about the Mercurial mailing list