Force Push a Git Subtree

Table of Contents

Problem

For… reasons… you force pushed a branch to your remote repository. For example, I’ve definitely done the following thing before (not that I’m proud of it):

$ git add . 
$ git commit -m "useful message" 
$ git push 
$ #
$ # shoot, i really should have also changed [ ... ]
$ git add . 
$ git commit -m "..." 
$ #
$ # interactive rebase to "fixup" the last commit
$ # i.e. this essentially puts the last change into 
$ #      the previous commit message 
$ git rebase -i HEAD~2
$ git push -f

Additionally, if this repo is, for example, a Jekyll blog, you may be building the _site folder and pushing only that to the remote gh-pages branch.

git subtree push --prefix _site origin gh-pages

However, after you just did a dumb dumb thing and forced a push, the next time you run the git subtree push ... command, you will get a hard reject - something like this:

! [rejected]        gh-pages -> gh-pages (fetch first)
error: failed to push some refs to 'file:///...'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first merge the remote changes (e.g.,
hint: 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Solution

In this case, pulling will not help because it thinks you have less (and older) code than it does. You did just bury some changes into a previous commit message, after all.

The following solution is taken shamelessly from this excellent GitHub Gist and preserved here for others (including my future-self) to find.

$ # create a local gh-pages branch containing the splitted output folder
$ git subtree split --prefix _site -b gh-pages 
$ #
$ # force the push of the gh-pages branch to the remote gh-pages branch at origin
$ git push -f origin gh-pages:gh-pages 
$ #
$ # delete the local gh-pages because you will need it later
$ git branch -D gh-pages 

You are now free to go about your business.

More