I have a branch that looks like this:
A->B->C->D->...->Z
^
1->2-^
where C
is a merge from 2
an
You could use the thg backout tool.
This will create a new head which you will need to merge with Z or rebase on to Z.
Assume we have this published history of commits (top is the newest):
revZ
|
...
|
revD
|
revC <- unwated merge commit (rev2 to revB)
| \
wanted branch -> revB rev2 <- unwanted branch
| |
Instead, we would like to have top state as if we had this history:
revZ'
|
...
|
revD'
|
wanted branch -> revB rev2 <- unwanted branch
| |
Callapse the history after merge commit (revD - revZ) into one commit
$ hg update -r revC # Update to merge commit
$ hg revert --all -r revZ # revert to the newest commit
$ hg commit -m "collapsed commits" # Create new commit (revTmp1)
revZ
|
...
|
revTmp1 revD
\ /
revC
| \
revB rev2
| |
Copy changes after merge (revTmp1) to wanted branch (revB)
$ hg update -r revB # Update to the last "wanted" commit before merge
$ hg graft -r revTmp1 # Copy changes from revTmp1 (create revTmp2 commit)
revZ
|
...
|
revTmp1 revD
\ /
revTmp2 revC
\ / \
revB rev2
| |
Create a "backout" commit
$ hg update -r revZ # Update to the top commit
$ hg revert --all -r revTmp2 # Copy state revTmp2
$ hg commit -m "reverted revC merge" # Create revZ' commit
revZ'
|
revZ
|
...
|
revTmp1 revD
\ /
revTmp2 revC
\ / \
revB rev2
| |
Clean the temporary commits
$ hg strip revTmp1 revTmp2
revZ' <- reverted revC merge
|
revZ
|
revD
|
revC <- unwated merge commit (rev2 to revB)
| \
wanted branch -> revB rev2 <- unwanted branch
| |
A little bit late, but I had the same situation a while ago. This worked for me smoothly:
hg update -C -r "revision-C"
hg revert --all -r "revision-B"
hg commit -m 'UNDO blah blah whatever the merge did'
hg update -C -r "revision-Z-or-whatever-the-current-head-is"
hg merge -r "the-new-revision-created-in-step-3"
Basically, this is exactly what backout does.
DISCLAIMER: Please note however that if you later in the future want to merge the 1->2 branch again, you will most probably run into some issues. And "some issues" is a somewhat euphemestic term here. In fact, even BIG PROBLEMS may appear in such a case. This scenario is dangerous mainly because the problems may arise much later and totally unexpected. It is highly recommended to abandon the "1" branch completely to avoid these risks. (Also see the comments below.)
For details, see Backout wiki page.
You can rebase D
to Z
onto B
. The documentation for rebase even discusses some similar situations. This should be doable in one command.
Use backout tool, but be aware of what you are doing:
Backout
option) aren't some changes from other
branches that you don't want to back out. If so, uncheck them before
commit. 1-2
(or "numbered branch") into branch A-Z
now (or later), you will lose all changes from "numbered branch" before changeset 2
(including) - that's what warning in @Marvin's answer is about.A-Z
is not direct ancesstor of "numbered branch", then find first descendant branch between A-Z
and 1-2
and update workbench to its tip.A-Z
(= backout) -> click Merge with local
A-Z
and 1-2
, repeat steps 4. and 5.1-2
yet.1-2
(for example changes from revisions D
- Z
).
Tip: To be really sure what files were affected by any merge, right click on that revision and click Diff to parent
This is basically scenario that we used today, when we find out that one branch (which was still in development) was accidentally merged into default (instead of another one, which had the same color in revisions graph :). (Both branches had pushed changes after this merge.) It might seems time-consuming, but still better than backout merge only and find numerous unexpected errors days (or weeks) later. (Own experience.)
Mercurial does allow backing out a merge revision; however, the functionality is deprecated. The danger is that backout does nothing but perform a reverse commit; if you change your mind and want to re-add the removed merge, you can't do this by merging the branch again. (Hg will refuse to perform a merge with an ancestor of the current revision; or, if there were some other commits on the branch after the merge, it will only merge the following commits.)
The command syntax is:
hg backout --rev MergeRevision --parent ParentRevision
Where ParentRevision is the parent of the merge revision on the original branch (i.e. not on the merged branch); usually, this is the first parent of the merge.
The command is not available in TortoiseHg Workbench.
After performing the backout (and resolving potential conflicts), make sure to review the new revision and amend it if necessary.