Over at HTML5 Doctor we’ve decided to mirror Mark Pilgrim’s “Dive into HTML5” book, and help update it. Jonathan Neal created an up-to-date mirror (with improvements) on GitHub, so I thought we’d give hosting via GitHub Pages a go. Using a
CNAME setting we can map the subdomain
diveinto.html5doctor.com to GitHub, which serves the content in a special
gh-pages branch. It’s working great.
gh-pages workflow #
Setting up GitHub Pages can appear a bit scary. Here’s how GitHub’s documentation suggests setting up the
$ cd /path/to/fancypants $ git symbolic-ref HEAD refs/heads/gh-pages $ rm .git/index $ git clean -fdx $ echo "My GitHub Page" > index.html $ git add . $ git commit -a -m "First pages commit" $ git push origin gh-pages
This makes a new
gh-pages branch with nothing in it, then adds a file and pushes it to GitHub. Now you have two branches with differing content:
master— your project’s code
gh-pages— your project’s website, hosted by GitHub using GitHub Pages
In Quick tip: git checkout specific files from another branch, Nicolas Gallagher covers how to add or update files on
gh-pages from the
master branch (this assumes you’re working in
$ git add . $ git status // to see what changes are going to be committed $ git commit -m "Some descriptive commit message" $ git push // push the master branch changes to GitHub $ git checkout gh-pages // go to the gh-pages branch $ git checkout master -- file1.ext file2.ext file3.ext // add/update file1-3 with changes from master branch $ git commit -m "Update file1-3 from master" $ git push // push the gh-pages branch changes to GitHub Pages $ git checkout master // return to the master branch
Lea Verou generally mirrors
master branch changes to
gh-pages, and covers the workflow in Easily keep gh-pages in sync with master. Do this by replacing the
git checkout master and second
git commit commands with
git rebase master:
$ git add . $ git status // to see what changes are going to be committed $ git commit -m 'Some descriptive commit message' $ git push // push the master branch changes to GitHub $ git checkout gh-pages // go to the gh-pages branch $ git rebase master // bring gh-pages up to date with master $ git push // push the gh-pages branch changes to GitHub Pages $ git checkout master // return to the master branch
By rebasing, all commits on the
master branch (and their commit messages) are applied to the
Using a post-commit hook #
#!/bin/sh git checkout gh-pages git rebase master git checkout master
This lets you replace the last five steps of Lea’s workflow with just git push --all. Nice!
git push #
git push origin master:gh-pages
This would replace the last four steps of Lea’s workflow. Your
master branch needs to be a mirror or subset of the remote
gh-pages branch, and it means if you’ve got the
gh-pages branch locally it’ll now be behind GitHub’s version. However, using this method you can essentially ignore (or not even have) the
gh-pages branch locally.
-f (force) makes the push happen even if the
gh-pages branch is newer (avoiding a “non-fast-forward updates were rejected” error). When using this method you shouldn’t be working on
gh-pages at all, so the only time this will happen is if someone else pushes changes ahead of you. In that case you can merge those changes into your local
master and push the
gh-pages branch again.
Setting up GitHub Pages using your current content #
However I wanted to have everything in
gh-pages and no
master branch, as the project page basically is the project. Ideally I’d just rename the
master branch to
$ git remote rename master gh-pages), but I worried this would cause problems with GitHub. Being lazy I just branched instead.
$ cd /path/to/diveintohtml5 $ git checkout -b gh-pages $ git push origin gh-pages
This worked fine even with
CNAME-based serving, but a typical
git pull failed with this error:
$ git pull You asked me to pull without telling me which branch you want to merge with, and 'branch.gh-pages.merge' in your configuration file does not tell me, either. Please specify which branch you want to use on the command line and try again (e.g. 'git pull <repository> <refspec>'). See git-pull(1) for details. If you often merge with the same branch, you may want to use something like the following in your configuration file: [branch "gh-pages"] remote = <nickname> merge = <remote-ref> [remote "<nickname>"] url = <url> fetch = <refspec> See git-config(1) for details.
I fixed this by editing the repo’s .git/config file and adding:
[branch "gh-pages"] remote = origin merge = refs/heads/gh-pages
master branch on GitHub #
This step could be messy, so I double-checked with GitHub support first (thanks Petros!). There are three things you need to do:
- Make the
gh-pagesbranch your default branch on GitHub: Repository Administration > Options > Set “Default Branch” setting to something other than
- Delete the
masterbranch on GitHub using
$ git push origin :master(which I think just sends a null branch to replace the remote
- Delete the
masterbranch in your local repo (once you’ve checked everything is working!) using
$ git branch -d master
After doing that I’ve ended up with a single
gh-pages branch on GitHub, and everything (apart from html5doctor.github.com/diveintohtml5) is working as expected. I’m not sure why the default GitHub Pages address fails, but given we’re using
CNAME to serve on a different domain it’s not a problem for us.
GitHub support also had this good advice:
First of all every time you are not sure about something, you can try doing it after you have cloned and fetched everything locally as a backup. If something goes wrong, you can push your repository again.
I hope GitHub adds admin options for choosing which branch to use for GitHub Pages (so you could choose
master), and for adding
CNAME information (adding a file to the repo is inelegant). I also hope they update the GitHub Pages documentation to cover the above setups.
In the meantime, if you have a repo you want to serve via
CNAME (not using the github.com URL), and you don’t have any separation between the
gh-pages branches, moving your repo from
gh-pages might be a good way to simplify things.