Is there a way to redo a merge in git?

Solution 1:

Not sure if this is the "blessed" way to do it, but here's what I did to resolve the same problem without having to "force push" or anything gross like that.

Let's assume your history looks something like this (and M is the flubbed merge):

-A--B--C--M (master points here)
  \      /
   D----E

Running git checkout -b merge_fix <commit ID E> creates a branch before we made any mistakes:

-A--B--C--M (master points here)
  \      /
   D----E (HEAD and merge_fix point here)

Now, let's re-do the merge on our new branch. We can't just merge in master, so we need to manually pick the commit before our bad merge: git merge <commit ID C> Don't make the same mistakes you did last time!

-A--B--C--M (master points here)
  \      X
   D----E-G (HEAD and merge_fix point here)

Assuming that commit G looks good, now we want to sync up with the top of the master branch. This command tells git to ignore the changes that were made to master, and force our changes to become the merge result: git merge -s ours master

-A--B--C--M (master points here)
  \      X  \
   D----E-G--H (HEAD and merge_fix point here)

Finally, (again assuming that commit H looks good, we want to fast-forward master to include our fixed merge:

git checkout master
git merge merge_fix

This really just moves the master branch pointer to H, but I'll take the opportunity to clean up my ASCII art a bit:

-A--B--C--M--H (HEAD, master, and merge_fix all point here)
  \      X  /
   D----E--G

And there you have it! you've successfully re-done the merge without invalidating any history!

Solution 2:

You can do it, like this:

  1. Reset to the commit before your merge.
  2. Perform the merge again
  3. Force push

That is:

git reset --hard SHA1
git merge branchname
git commit
git push --force remotename branchname

Just keep in mind that git push --force will rewrite whatever you had at the remote branch, and other people using that branch may be affected by this too. (Normally you should not do this.)