I have a branch that looks like this:
A->B->C->D->...->Z
^
1->2-^
where C
is a merge from 2
and its ancestors.
I realize now that I should not have merged. I could go back to B
and graft D
...Z
but that's a lot of work. Can I backout JUST C
?
When I try to hg backout --merge C
I get abort: cannot backout a merge changeset.
These changes have been pushed to the central repo and I'm not looking to modify history or anything, I just want the inverse of 2
and it's ancestors back to the common descendant with B
.
Revert changes already committed To backout a specific changeset use hg backout -r CHANGESET . This will prompt you directly with a request for the commit message to use in the backout. To revert a file to a specific changeset, use hg revert -r CHANGESET FILENAME . This will revert the file without committing it.
Backout works by applying a changeset that's the opposite of the changeset to be backed out. That new changeset is committed to the repository, and eventually merged.
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.
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.)
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.
You can rebase D
to Z
onto B
. The documentation for rebase even discusses some similar situations. This should be doable in one command.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With