(Updated: 2020-05-05 to add notes on creating the orphan ‘gh-pages’ branch)

Preliminaries

Create an “orphan” git branch named ‘gh-pages’

GitHub Pages will allow you to publish your project’s site from a few different “sources”. Here we are concerned only with one of those approaches: an “orphan” git branch named 'gh-pages' within the repo.

The name 'gh-pages' is not optional; it is treated specially by GitHub Pages. You cannot choose an arbitrary branch name from which to publish your project’s site; the branch must be called 'gh-pages'.

Note that your project’s settings page in the GitHub web site will only show the 'gh-pages' branch as an option in the GitHub Pages “Source” drop-down if the branch already exists in your project’s repository.

For the purposes of publishing your project’s site on GitHub Pages, you’ll want the 'gh-pages' branch to be an “orphan”. That is, you want it to have a history that is entirely disconnected from the other existing branches in your repository. To achieve that, we are going to use the --orphan option to git-checkout(1):

    $ git checkout --orphan gh-pages
    Switched to a new branch 'gh-pages'

At this point, a git status would show that all of the repo’s files that were being tracked on the branch source point are now staged in the index; git does this in anticipation of the user wanting to create a new, clean go-forward history for the “as is” state of the files. That is not our use case, however; we are going to use an entirely different set of files on our new branch, so we can just clear out the git index:

    $ git rm -fr .
    
    $ git status
    On branch gh-pages

    No commits yet

    nothing to commit (create/copy files and use "git add" to track)

Now you have a clean 'gh-pages' branch with no commits. Read on to see how we want to populate it, starting with a file named 'Gemfile'.

In your brand new working directory for a site you intend to generate with Jekyll and host with GitHub Pages, you will want to have some tooling available locally to allow you to veiw the Jekyll-based site generation prior to pubishing it on GitHub Pages.

The Jekyll software is written in Ruby, and (as is true of most Ruby software) is released in the form of a “gem”.

    $ cat - <<EOF > Gemfile
    source 'http://rubygems.org'
    gem 'github-pages', group: :jekyll-plugins
    EOF

This will install (into the 'local-ruby-gems' subdir) the dependencies specified in the 'Gemfile' (see Gemfile(5)), along with all of their dependencies.

    $ bundle install --path=./local-ruby-gems --verbose

    $ cat - <<EOF > _config.yml
    title: my-project-name by Alan D. Salewski
    description: blah blah blah

    markdown: kramdown

    kramdown:
        input:     GFM  # Enable GitHub Flavored Markdown (fensed code blocks)
        hard-wrap: false

    highlighter: rouge

    exclude:
        - local-ruby-gems/    # avoid processing jekyll itself; see also https://github.com/jekyll/jekyll/issues/2938
    EOF

Regular usage

Prior to publishing: edit -> review -> commit cycle

Once you have your tooling setup in your project’s git working directory, you will basically just edit the Markdown files of individual articles in the '_drafts' subdirectory. The edit -> review -> commit cycle works almost the same as any other software project, with commits happening wherever makes sense for the particular article content.

The “review” phase mainly involves just rereading the article content and making adjustments as necessary. Before committing, however, you should view the Jekyll-rendered form of the article in your web browser. To do that, you could just 'git push' to GitHub Pages and hope for the best, but since you’ve gone through the trouble of setting up your local Jekyll-based tooling you should launch the local web server built into Jekyll for previewing your changes.

This will generate the static site and render it the way it will be published when you 'git push ...' your changes up to GitHub:

    $ bundle exec jekyll serve --watch
    Configuration file: /path/to/project/_config.yml
    Configuration file: /path/to/project/_config.yml
                Source: /path/to/project
           Destination: /path/to/project/_site
     Incremental build: disabled. Enable with --incremental
          Generating...
                        done in 0.389 seconds.
     Auto-regeneration: enabled for '/path/to/project'
    Configuration file: /path/to/project/_config.yml
        Server address: http://127.0.0.1:4000/
      Server running... press ctrl-c to stop.

The following variation of the same command (adds the '--drafts' option) will generate the static site and render it with all of your unpublished drafts integrated into the site:

    $ bundle exec jekyll serve --watch --drafts
    Configuration file: /path/to/project/_config.yml
    Configuration file: /path/to/project/_config.yml
                Source: /path/to/project
           Destination: /path/to/project/_site
     Incremental build: disabled. Enable with --incremental
          Generating...
                        done in 0.639 seconds.
     Auto-regeneration: enabled for '/path/to/project'
    Configuration file: /path/to/project/_config.yml
        Server address: http://127.0.0.1:4000/
      Server running... press ctrl-c to stop.

In addition to the normal posts (everything beneath the '_posts' subdir), the above command also includes everything beneath the '_drafts/' subdir.

Q: Should I check the Gemfile in?

(Concerned that it might have an adverse effect if interpreted by the remote GitHub site builder.)

A: Yes, empirical testing shows that the remote site builder does not break.

Publishing

Once you are happy with the content of an article, you can cause GitHub Pages to render it by moving it from the '_drafts/' subdir to the '_posts/writings/' subdir, with a publication date embedded in the file name:

    $ git mv _drafts/my-article.md _posts/writings/YYYY-MM-DD-my-article.md

Push your locally committed changes to GitHub to have them rendered by GitHub Pages:

    $ git push --follow-tags origin master
    ...