Update - It's never that easy, is it?
I've recognized a flaw in the original instructions I suggested: when doing a checkout
with path arguments, you might expect a file to be removed from your working path because it isn't in the commit you're checking out; but then you might be surprised...
As with any history rewrite, it's worth noting that you probably shouldn't do this (using any of the methods form any of these answers, including this one) to any merge you've already pushed. That said...
The previous answers are fine, but if you'd like to avoid using (or needing to know) plumbing commands or other git inner workings - and if that's more important to you than having a one-liner like Jared's solution - then here's an alternative:
The overall structure of this solution is similar to zeeker's, but where he uses plumbing commands to manipulate HEAD or "tricks" git into completing a merge, we'll just use porcelain.
So as before we have
* (master) Merge Commit
| \
| * (feature) fixed something
* | older commit on master
Let's begin:
1) Tag the old merge
We'll actually be using this tag. (If you want to write down the abbreviated SHA1 instead, that'll work; but the point here is making the fix user friendly, so...)
git tag badmerge master
Now we have
* (master) [badmerge] Merge Commit
| \
| * (feature) fixed something
* | older commit on master
2) Take the merge out of master's history
git branch -f master master^
Simple enough:
* [badmerge] Merge Commit
| \
| * (feature) fixed something
* | (master) older commit on master
3) Start a new merge
git checkout feature
If we just run git merge master
now, we know the merge will fail; but we don't want to redo the manual conflict resolution. If we had a way to overlay the data from badmerge onto our new merge commit, we'd be all set... and we do!
To start the merge (a) without creating conflict state to be cleaned up, but (b) leaving the merge commit open so we can "fix" it:
git merge --no-commit --strategy=ours master
4) Overlay the already-resolved/merged data from badmerge
Making sure we're in the root directory of the repo we might then do git checkout badmerge -- .
(note that we've provided a path (.) to git checkout
, so it only updates the working tree and the index); but this actually can be a problem.
If the merge resulted in files being deleted (but they're in our working tree right now), then the above command won't get rid of them. So if we're not sure, we have a couple options to be safe from that possibility:
We could first clear our working tree... but we do need to be careful about not wiping out the .git folder, and may need special handling for anything in our ignore file.
In the simple case - .git is the only .-file, nothing being ignored - we could do
rm -rf *
git checkout badmerge -- .
Or, if that seems too risky, another approach is to skip the rm
, do the git checkout badmerge -- .
, and then diff against badmerge to see if anything needs cleaning up.
5) Complete the merge
git commit
git tag -d badmerge