The Problem

Here’s the scenario:

I had a git repo that looks like this:

A-B----     master
   \   /
    C-D     *develop

I was on the develop branch. Here’s the foolish thing that I did:

There were no changes after B on the master branch, and as such, when I merged, git did a fast-forward. My repo now looked like this:

A-B-C-D   master, develop, remotes/publish/master, remotes/publish/develop.

I wanted to keep develop at D, but revert master to B, and then merge the changes made at D into master.

What I Should’ve Done to Start With

What I should’ve done was:

git checkout master     #change to `master` branch
git checkout -b hotfix  #make a new branch called `hotfix` from `master`
#make file changes
git commit              #commit the `hotfix`
git checkout master     #switch back to `master`
git merge hotfix        #pull in the hotfix changes
git checkout develop    #switch to `develop`
git merge hotfix        #pull in the hotfix changes
git push publish        #push everything to my remote.

Resulting in a diagram that looks like this:

    D--     hotfix
   /   \
A-B---- E   master
   \    |
    C---F   *develop

Fixing the Mistake

Turns out the solution wasn’t really that hard, but git can be really scary if you’re not sure what you’re doing. The develop branch is already in the right spot, so we just need to:

# Make sure we're on the `master` branch
git checkout master
# Move `master` back to revision `B`, deleting all other changes in the working
# directory.
git reset --hard sha-of-B
# Because we've reverted some changes, we need to force the remote to accept the
# reversion.
git push publish --force

That reverts the master branch back before the merge. To then pull in the changes made in the hotfix:

git cherry-pick sha-of-D    #pull in only the changes made in revision D.
git push publish

And we’re done!

Thanks to Simon Boudrias for his help on this one. See the StackOverflow question here.