Site Mechanics
This site source is an mdbook instance, which is automatically deployed to GitHub Pages when Pull-Requests are merged.
This page describes the implementation of this deployment. Let me know if you find this helpful, or if you have issues / questions / improvements, please use this site's issue tracker.
Design Goals
- Rendered content (anything generated by a program) should not be in revision control, because it's not source code. Typically humans shouldn't care about changes to rendered content unless they are diagnosing automation problems. By contrast, humans should definitely care about source, especially for a book.
- The book is automatically rendered to the public site whenever a PR is merged.
- The "rendering branch"
gh-pagestracks all rendered revisions in its history, while also linking to each render source revision (as a merge).
Components
To achieve these goals, we have several components:
- We use a special purpose
gh-pagesbranch that does contain rendered output. This should be the only exception. Other branches can have human-meaningful source. mdbookmust be configured to render into./docsas a requirement of GitHub Pages: book.toml- We
.gitignorethedocs/dir, since this is rendered output, not human-meaningful source: .gitignore - We add a
deploy.tomlGitHub Action which will deploy whenever we merge a PR tomainbranch: .github/workflows/deploy.yaml - We configure the GitHub repository to enable GitHub Page hosting.
Setting It Up
Create and mdbook
See the mdbook guide to get started.
Configure mdbook and .gitignore
First we need to configure to render to ./docs by adding this to book.toml:
[build]
# Follow gh pages convention:
build-dir = "./docs"
-and let's also ignore the render dir, because of our first design goal by adding this to .gitignore:
docs/
Add the deploy.yaml GitHub Action
The .github/workflows/deploy.yaml does all the good stuff. It:
- triggers on any push to
main(the default repo branch), - installs
mdbook, - checks out the source,
- creates a new merge commit on
gh-pagesthat overwrites the previous content with the new revision onmain, - renders the source with
mdbook, - removes
./docsfrom.gitignoresince this is the one exception to committing rendered content, - disables
jekyll(the standard GitHub Pages rendering system), - and finally, commits and pushes the rendered content to the
gh-pagesbranch.
This should result in two commits onto gh-pages per render cycle: one is a merge that overwrites the previous contents of gh-pages with the new main content, and the second includes the rendering output. This design enables seeing the deployment history on the gh-pages which is tracked interleaved merge/render commits. Each merge additionally points to the revision of main where the content comes from, overwriting any previous changes on the gh-pages branch.
Configuring GitHub Pages
The final step is to tell GitHub Pages where to find the rendered site content:
- repo -> "Settings" -> "Pages"
- Set source to
gh-pagesbranch. You may need to create this branch first; one way is by merging a PR tomainto trigger the deploy action to produce your first render. - Set the path to
docs/.
Writing Cycle
Because this rendering only occurs when you merge to main, it should only be used for "finished" updates you want to publish to the world. Make sure to render and review your edits as you go prior to merging a PR.
On linux I use this command to quickly view the rendered version:
$ mdbook build && xdg-open ./docs/index.html
This works better for me than the mdbook built-in reloading webserver; do whatever works best for you.
Fin.
Now you can edit the source of your site in a clean manner without the clutter of renderings. Enjoy!