Categories
Computers Weird Errors

Recover from a GIT squash/rebase and merge gone awry

Everyone loves GIT, the source control system. But sometimes you can end up in a situation where a pull request is showing duplicate commits for some work you did long ago in the past.

Here’s a technique for recovering from that.

First, make sure you have NO uncommited files. Type git status and make sure it reports “nothing to commit, working tree clean”. Second, type git log and copy the last commit id and email it to yourself or do something with it just in case you need to recover from some terrible mistake.

NOTE

This assumes your making a pull request from your branch against a branch called “develop” and that your remote server is called “origin”. This also assumes that you own your branch and can overwrite the copy on the remote. If other people share your branch none of these techniques are safe to employ without their cooperation

First, the easiest method, but one that does not always work:

git fetch origin
git rebase origin/develop

If this works without complaint, you’re probably golden. Simply push your branch — possibly via git push -f if you’ve previously pushed this branch. This forcibly replaces the remote but that’s probably okay because we just fixed it.

If you’re still here, that’s because rebase didn’t work. Let’s abort by typing

git rebase --abort

Now let’s try doing cherry-pick. This requires that you list all the commits that you’ve made that you want to keep. Let’s look at the git log and copy to a text file all the commits that you want to keep

git log --oneline --graph

At some point as you read down that list you’ll get to old commits that are already part of origin/develop. You’ll need that list of commit ids from oldest to newest, for example if you saw this:

* 754fe93 My most recent commit
* 953511b More work on this feature
* 5a6df59 My first commit for this feature
*   19ec9be Merge develop into my branch
|\  
| * 6804047 An old commit that's somehow duplicate
| *   65e7f73 another old commit ..?

The list of commit ids you’d need would be 5a6df59 953511b 754fe93. Now to fix your branch, you would do

git fetch origin
git reset --hard origin/develop
git cherry-pick 5a6df59 953511b 754fe93

If this works without trouble, then you’re golden. Go to “you’re probably golden” above and you’re done.

If you’re still here, that’s because cherry-pick also failed you. It might be possible to fix this by doing a series of merges, but that can get tedious. So abandon this by doing

git cherry-pick --abort

The last technique I employ is a big hammer. This requires that you merge develop into your branch:

git fetch origin
git log

Now remember (copy) the commit id of the most recent commit. Now reset your branch back to origin/develop and squash your commit onto it.

git reset --hard origin/develop
git merge --squash <copied commit id>
git commit -m 'my commit message goes here'

Prior to the commit, you may have to fix merge conflicts. Such is life.

You now have one commit that is the sum of your changes from your branch! If you want it to be multiple smaller commits you could do that by resetting and committing parts one at a time.

If at any time you panic and feel you’ve lost work, simply use the command

git reset --hard <commit id you copied at the start and emailed to yourself>

And you should be back to the state you started in.