How to undo a merge on a branch where there have been subsequent commits?
Let's say I have a develop
branch where multiple people branch off of to work on either bugfixes or features.
Let's say now I have a branch called featureA
that I worked on while some other person worked on featureB
and someone else on bugfixA
.
I accidentally merged my featureA
branch into develop
. featureB
and bugfixA
are also merged into develop
but do not need to be unmerged.
Now we carved a branch off of develop with all those merges and called it releaseA
. So now I need to unmerge my featureA
from releaseA
and put a PR for that.
How do I go about this?
Here's what I'm thinking:
-
git log
which will show the commit id for thefeatureA
merge git reset --merge <commit id for featureA
git commit 'merge revert'
-
git push
toreleaseA
Now I haven't tried this because I'm unsure what happens to the other merges if I revert my commit, because featureB
and bugfixA
merges happened in develop
after my merge and don't need to be removed from the releaseA
. Only featureA
needs to be removed from releaseA
and I need to submit another PR for that unmerge.
Will that affect the other merges/commits?
Is this the right track or am I missing something?
Example of git log --oneline --graph
* f092f2f0f (HEAD -> release/releaseA, origin/release/releaseA, origin/develop, origin/HEAD, develop) Merge branch 'feature/featureB' into 'develop'
|\
| * f023f02f9 (origin/feature/featureB) commit mesage feat A
* | f2902f921 Merge branch 'feature/featureA' into 'develop'
|\ \
| * | 3e2011910 (origin/feature/featureA, feature/featureA) feat: commit feat B
* | | 0131f1921 Merge branch 'bugfix/bugfixA' into 'develop'
|\ \ \
| |/ /
|/| |
| * | f29190198 some commit message
|/ /
* | 013e9112f Merge branch 'bugfix/bugfixB' into 'develop'
|\ \
| * | 37f78f300 another rcommit message
* | | 29aef3119 Merge branch 'bugfix/featureC' into 'develop'
|\ \ \
| |/ /
|/| |
| * | a819cd3d6 (origin/bugfix/featureC, bugfix/featureC) update: feat C commit msg
| * | 031119101 fix: some fix
| * | c1ec250d7 fix: some other fix
* | | 771ee7a10 Merge branch 'bugfix/bugfixC' into 'develop'
I think it's important to mention that I ran that command on releaseA branch. releaseA branch is basically carved off develop and I need to unmerge featureA from releaseA but keep it in develop.
Solution 1:
Since you created a new branch, releaseA
, for which you want to rewrite history, and you are not messing with the shared develop
branch, this should be easy.
Simply use git rebase -i
to rewrite the history for releaseA
:
-
The following command will let you rewrite history starting from the parent of the commit you want to remove (
f2902f921
, the merge commit forfeatureA
):git rebase -i --rebase-merges f2902f921^ releaseA
The
--rebase-merges
switch will replay merge commits as merge commits instead of as simple linear commits. If you don't need this behavior, exclude this switch. Seegit help rebase
for more info. -
In the interactive rebase commit list, remove the line for the merge commit,
f2902f921
. Or replace the wordpick
withskip
. Either way that commit will not be included when the rebase commit list is replayed. -
Save and close the rebase commit list.
git rebase
will now replay the commits in the order given in this list. You will have to deal with any conflicts as commits are replayed. -
Check the results. Once you are satisfied, force push the rewritten history for
releaseA
:git push -f releaseA
⚠️ Warning
Review the dangers of rewriting history per my link above. That said, given what you want to achieve, there is no way around this.
git rebase -i
is one of the most powerful and useful commands in git. Learn it!