Background: I recently merged a rather large topic branch into master
. A couple of days later I discovered this topic branch contained bugs. So I git revert -m 1 <merge-commit>
ed it.
Problem: Now I'd like to check out the topic branch and rebase it against current master
so that I can 1) fix the bugs and 2) (again) merge the fixed up topic branch with master. Creating the new branch, fixedtopic
is the easy part, but every time I do
git checkout fixedtopic
git rebase master
git decides that it's not willing to replay the old commits since they are already merged into master
. Instead it simply does a fast-forward rebase.
Question: How can force replay of the commits onto fixedtopic
using rebase
? Can I? I'd rather not use cherry-pick
since it's a bit more cumbersome.
Additional:
git reset
ing the merge commit it not an option, since I have pushed the master upstream.master
and revert my revert. The reason for this is that I'd like to rewrite some of the topic branch's history using interactive rebase.master
(or branch based on master
).By default, the git pull command performs a merge, but you can force it to integrate the remote branch with a rebase by passing it the --rebase option.
To undo a git merge, you need to find the commit ID of your last commit. Then, you need to use the git reset command to reset your repository to its state in that commit. There is no “git revert merge” command.
You can use the Git reset command to undo a merge. Firstly, you need to check for the commit hash (or id) so you can use it to go back to the previous commit. To check for the hash, run git log or git reflog . git reflog is a better option because things are more readable with it.
The documentation (git help rebase) suggests that "git rebase --force-rebase" does just this -- but (Git 1.9.1) it doesn't. The documentation also suggests that "git rebase -i --no-ff" is equivalent to that command -- but it isn't: it does work.
Having cloned your gist, the commands:
git checkout topic
git rebase -i --no-ff --onto master 7b3af topic
produce the desired result, with new versions of the "third" and "fourth" commits on top of master, and topic
pointing at the new version of "fourth". In the second command, the SHA 7b3af
is the "second" commit, the point where topic
was branched from.
One way to achieve this is to interactively rebase the topic branch and reword the first commit after branching out of master (e.g. git rebase -i HEAD~10
if you have 10 commits in the branch). This will rewrite sha's of all the commits inside the topic branch. Therefore you will be able to rebase the usual way with git rebase master
.
With git 2.22
, the solution suggested by jurglic does not seem to work anymore.
Let's start with the status, to make sure that we are talking about the same thing:
P---o---o---M---o---o---o---o---o---W---o---o---master
\ / \ /
A---B---C D (revert A-B-C)
I had created a dev branch with A-B-C
commits and it was merged in M
, but immediately we noticed there was an error so it was reverted in W
. I would like to rebase A-B-C
on master
and fix the issue before merging it again.
Here is what I did:
git checkout C (detached HEAD)
git checkout -b redo
git rebase -i master
But at this point, git offered me only the following:
noop
# Rebase A..C onto X (1 command)
This meant that it figured out that I was trying to reapply the exact same commits and they had already been merged.
To workaround this problem, jurglic had suggested to modify A
's the commit message but it seems that git 2.22
is clever enough to figure it out and was still offering me the exact same noop
. I tried other solutions, using --force-rebase
and/or --no-ff
, but I was all the time back to noop
.
Finally, I used an easy short-cut by entering manually in the rebase -i
selection editor and I replaced noop
with:
pick A
pick B
pick C
or, if you want to save even more keystrokes:
p A
p B
p C
This worked finally like a charm.
You need to use --onto
to prevent Git form trying to determine the appropriate unmerged commits on its own.
E.g. (with topic branch checked out):
git rebase --onto master <id-of-branch-point>
For <id-of-branch-point>
you want the git merge-base
of your topic branch and the commit on master before the merge that you reverted.
Edit
Re-reading your situation again, it might be a better if you fast-forward the topic branch to the point where you reverted the merge, then revert the reversion and fix the topic branch from that point. This way you won't get a repetition of all the commits in the original topic branch but with new ids in the final history of master. Whatever you do, you're going to end up with a history involving "do, undo, redo", but this way might be considered a cleaner history.
What seems to work best is to check out a new branch, and then re-instate the previous working branch by reverting revert.
Everything else that I've tried is overly complicated and/or doesn't work.
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