Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you easily unmerge a topic branch in Subversion/git?

So I have /trunk, to which all things golden are eventually committed. And I have a topic branch, /topicA.

Normally, you would merge /topicA into trunk and it would be one commit. Hooray! To undo this merge, you just have to reverse merge the commit caused by this merge. Easy peasy.

Now, let's say I have /topicA and I merge it into /trunk... But then I have a bugfix that relates to /topicA. So, should I be committing to /topicA again? I can even remerge /topicA so that /trunk contains /topicA. But how to I rollback all of /topicA, original work AND bugfixes, easily?

Commit history:

  • Commit to /topicA
  • Commit to /topicA
  • Commit to /topicA
  • ...
  • Merge /topicA into /trunk
  • ...
  • Bugfix1 to /topicA
  • Remerge /topicA into /trunk for bugfixes
  • ...
  • Bugfix2 to /topicA
  • Bugfix3 to /topicA
  • Remerge /topicA into /trunk for bugfixes
  • ...
  • ??? (unmerge /topicA, bugfixes included)

I know you can just unmerge each bugfix and then the initial merge, but that doesn't seem sexy at all.

Does git have an answer to this as well?

like image 728
Mark Canlas Avatar asked Jul 11 '11 20:07

Mark Canlas


2 Answers

You can rewrite history using

git rebase --interactive --preserve-merges <hash before first merge>

This will bring up your default text editor with a list of commits including your merges. Remove all merges from the list that comes up in the editor and save, then exit. git will replay all the commits excluding the ones that you removed, thus rewriting history. Your /topicA branch will still exist, so you can simply merge it into truck.

It helps that all the merges have the words "Merge branches" in the interactive editor, so it's easy to identify them.

Here's a example of the text in the editor that is bought up after the command is issued on a fictional repository

pick 07c2942 Added "Hello" to README
pick e98e38b Added "There" to README
pick e3d66ad Added "Here" to README
pick 2105946 Merge branches 'master' and 'tmp'

You don't want the merge to happen so you simple remove that line and the line just before it since it is part of the merge in this case.

pick 07c2942 Added "Hello" to README
pick e98e38b Added "There" to README

Save and exit and git will now replay these commits, minus the merge.

Note you can remove any line, and that commit will be removed from the repository. Also you can rearrange the commits to whatever order you like. If you have merges in the middle, you can cut and paste them to the end.

like image 187
James Hurford Avatar answered Nov 02 '22 21:11

James Hurford


In our project, we keep one more branch until integration is done (trunk_plus_topicA in your case). It's created from the trunk. We merge to it commits from the trunk as well as from topicA.

Then, after integration tests are done, and we are sure we want topicA, the whole topicA_plus_trunk gets merged into the trunk (or you can replace trunk with the trunk_plus_topicA).

In canse when topicA is going to be merged only to the trunk (or dropped at all), you don't need extra branch. You can simply merge commits from the trunk to the topicA. Do bugfixing, integration and testing in topicA, and at the end merge it all at once to the trunk.

As my friend says - "the easiest way to fix a broken plate is to not brake it in the first place." This advice doesn't work well in a real life, but works quite often in software engineering.

like image 1
Michał Šrajer Avatar answered Nov 02 '22 21:11

Michał Šrajer