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:
/topicA
/topicA
/topicA
/topicA
into /trunk
/topicA
/topicA
into /trunk
for bugfixes/topicA
/topicA
/topicA
into /trunk
for bugfixes/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?
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.
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.
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