Imagine you have a subdirectory of generated files and you want to store
them into Git as a standalone (orphan) branch. For example, you have
intention of publishing them as a GitHub Pages
gh-pages Git branch of the project. Git’s plumbing commands
allow automating storing the generated files into the
recreating the branch each time you publish. Here’s a Bash oneliner to
For that Bash command list, I presume that
- the generated files are already in the
- you include
.gitignorefile of the project, and
- the Git index (staging area) is clear currently.
Let’s go over the parts of the command list.
1. Stage the generated files into Git index
I’ll use the
--force switch to allow Git to add ignored files.
2. Create a Git tree object from the current index
A Git tree object groups Git objects and stores the paths of the objects. The tree object will be used to create a commit object in the next step.
--prefix=build/ option makes Git to treat the
build directory as
the root directory for the files within the directory. For example, a
file with the
build/dir/index.html path gets recorded with the
dir/index.html path inside the tree object.
The command prints the name of the tree object to stdout (I’ll use the
$tree shell variable for that in the next step).
3. Create a Git commit object from the tree object
The command prints the commit object id to stdout (let’s put it into the
4. Set a branch to refer to the commit object
This overwrites the
gh-pages branch, if it exists already.
5. Reset index to the current HEAD
This needs to be done for clearing the index.
Now the target branch,
gh-pages, contains a single orphaned commit,
build subdirectory as the root directory of the files.
If you want to, you can store the previous commit of the
branch as the parent of the next commit, but then there are edge cases
to consider: you’ll need to detect if the target branch exists already
and whether the new contents of the
build directory differ between the
next and the previous commit (it doesn’t make sense to create a new
commit with an empty diff compared to the parent commit). Covering them
would require elaborate scripting compared to the Bash oneliner I went
As a real example, the Hacker’s Tiny Slide
Deck project uses
this trick in storing the generated slides (an html file) and the
gh-pages branch of the
project, from where GitHub Pages publishes them. The relevant Git
commands are in
Here’s a screenshot of GitUp app’s map view of the
Git repository of Hacker’s Tiny Slide Deck, showing what the standalone
gh-pages branch looks like:
The chapter titled Git Objects from the Pro Git book is a great resource for learning more about Git internals.