Simple deployment to GitHub Pages with git worktree
I’ve recently been building single-page apps with React, and using webpack to transform/bundle the JS and CSS into a distributable form. GitHub Pages is the perfect place to host these projects, as deployment is only a
git push away, from the
At least, it ought to be that simple—but instead I’ve found myself awkwardly copying build output from
master to the project root on
gh-pages (GitHub gives you no choice but to serve your site from there). That or I’ll add the build output files to
.gitignore, and put up with them polluting the project root.
Thankfully, git has a trick up its sleeve to avoid all this:
worktree, added in version 2.5. Glossing over the gory details contained in the
man page, the command allows you to check out additional branches into subdirectories of your repository’s root, like so:
git worktree add dist gh-pages
Now when you
dist, you’ll be on the
gh-pages branch. Go back up a level, and you’re back on
master. Very convenient.
A few things to watch out for: when running this command, git will complain if
dist already exists. This also assumes that you already have a
gh-pages branch. If not,
worktree add can create it for you by giving it the flag,
If you create a new branch like this, however, it’ll contain all the history of the branch you were on when the command was executed. I prefer an empty history, to be able to clearly see deploys on their own—probably best combined with judicious use of tags, to link back to the history in your development branches.
An empty history requires an orphan branch, created as follows:
git checkout --orphan gh-pages
Somewhat annoyingly, this populates the index with the contents of the branch from which you perform the
checkout (and there’s no corresponding
--orphan option for the
branch command to do what we really want). The workaround is easy though. Just clear the index, make an initial commit on the new branch (an empty one will do), then checkout the previous branch with the flag,
--force, to silence warnings about overwriting files that were carried over with the orphan checkout—they’ve not changed. Then the new worktree can be added:
git reset git commit --allow-empty -m 'Initial commit' git checkout --force master git worktree add dist gh-pages
Finally, you can run your build tool of choice (with
dist configured as its output directory, of course) and push to production:
rm -rf dist/* && NODE_ENV=production webpack -p git tag v0.0.1 cd dist git add --all git commit -m 'Deploy v0.0.1' git push cd ..
You could make deploying easier still by adding a post-commit hook that runs (roughly) the above whenever you create a new tag. But that’s for another post.