personal web log written by izabeera and dryobates

mercurial

Move changesets between branches in Mercurial

by dryobates

You have commited changeset into wrong branch, pushed changes and want fix that now? You can’t change history in Mercurial, but fixing that wrong commit is possible.

Sometimes in a hurry you can quickly make a fix, commit and push changes to central repository only to see that it was committed on wrong branch. Mercurial by design has immutable history so editing it with tools like histedit is praying for disaster.

Here’s how you can do it correctly. Let’s assume that you have two branches:

$hg branches
feature1                       1:c91eed4eba26
default                        0:8a789386959f (inactive)

And you accidentally do two commits in default branch instead of feature1 branch:

$hg glog
@  changeset:   3:f21869a31705
|  tag:         tip
|  user:        jstolarski
|  date:        Sun Oct 26 12:14:34 2014 +0100
|  files:       README
|  description:
|  change2
|
|
o  changeset:   2:775bb1e20812
|  parent:      0:8a789386959f
|  user:        jstolarski
|  date:        Sun Oct 26 12:14:23 2014 +0100
|  files:       README
|  description:
|  change1
|
|
| o  changeset:   1:c91eed4eba26
|/   branch:      feature1
|    user:        jstolarski
|    date:        Sun Oct 26 12:13:14 2014 +0100
|    files:       README
|    description:
|    feature1
|
|
o  changeset:   0:8a789386959f
   user:        jstolarski
   date:        Sun Oct 26 12:12:45 2014 +0100
   files:       README
   description:
   initial

Now you have to backout changes from default branch in reversed order. First revision nr 3:f21869a31705:

$hg backout -r 3
README
committed changeset 4:7f60747c0f08
changeset 4:7f60747c0f08 backs out changeset 3:f21869a31705

It should ask you for commit message and commit automatically as it’s top revision. Now backout revision 2:775bb1e20812:

$hg backout -r 2
resolving manifests
merging README
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
changeset 775bb1e20812 backed out, don't forget to commit.

As you see that backout wasn’t committed automatically as it’s not top revision. You can check suggested changes and if everything is correct commit that change:

$hg commit -m 'Backed out changeset 775bb1e20812'
README
committed changeset 5:9e4fd1a9ea88

Now default branch has been reverted into state before doing two wrong changesets:

$hg glog
@  changeset:   5:9e4fd1a9ea88
|  tag:         tip
|  user:        jstolarski
|  date:        Sun Oct 26 12:27:07 2014 +0100
|  files:       README
|  description:
|  Backed out changeset 775bb1e20812
|
|
o  changeset:   4:7f60747c0f08
|  user:        jstolarski
|  date:        Sun Oct 26 12:16:21 2014 +0100
|  files:       README
|  description:
|  Backed out changeset f21869a31705
|
|
o  changeset:   3:f21869a31705
|  user:        jstolarski
|  date:        Sun Oct 26 12:14:34 2014 +0100
|  files:       README
|  description:
|  change2
|
|
o  changeset:   2:775bb1e20812
|  parent:      0:8a789386959f
|  user:        jstolarski
|  date:        Sun Oct 26 12:14:23 2014 +0100
|  files:       README
|  description:
|  change1
|
|
| o  changeset:   1:c91eed4eba26
|/   branch:      feature1
|    user:        jstolarski
|    date:        Sun Oct 26 12:13:14 2014 +0100
|    files:       README
|    description:
|    feature1
|
|
o  changeset:   0:8a789386959f
   user:        jstolarski
   date:        Sun Oct 26 12:12:45 2014 +0100
   files:       README
   description:
   initial

Now you can switch to feature1 branch and do changes again. But why waste your time and do it again? Let’s try to apply the same changes on correct branch using graft:

$hg up feature1
resolving manifests
getting README
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$hg graft -r 2:3
grafting revision 2
resolving manifests
merging README
README
grafting revision 3
resolving manifests
merging README
README

There was no conflicts so changes were applied immediately:

$hg log -b feature1
changeset:   7:f08e221ee697
branch:      feature1
tag:         tip
user:        jstolarski
date:        Sun Oct 26 12:14:34 2014 +0100
files:       README
description:
change2


changeset:   6:450504d5cc1d
branch:      feature1
parent:      1:c91eed4eba26
user:        jstolarski
date:        Sun Oct 26 12:14:23 2014 +0100
files:       README
description:
change1


changeset:   1:c91eed4eba26
branch:      feature1
user:        jstolarski
date:        Sun Oct 26 12:13:14 2014 +0100
files:       README
description:
feature1

If there were conflicts you have to manually resolve conflicts (working directory have partial merge) and continue with:

$hg graft -c

So summary:

$hg backout -r 3 && hg backout -r 2 && hg commit -m 'Backed out changeset 775bb1e20812' && hg up feature1 && hg graft -r 2:3

But I wouldn’t advise you doing it without checking intermediate states if you once done mistake committing on wrong branch :)

Note

Above examples were made with Mercurial version 3.1.2

dryobates
dryobates
Jakub Stolarski. Software engineer. I work professionally as programmer since 2005. Speeding up software development with Test Driven Development, task automation and optimization for performance are things that focus my mind from my early career up to now. If you ask me for my religion: Python, Vim and FreeBSD are my trinity ;) Email: jakub@stolarscy.com

Archive

Tag cloud