Goal: Deploy SSG manually without CI/CD, utilizing git worktree feature.
For anyone who think previous Zeit Now Article is too easy, or think Netlify article is boring. I have good material for you.
How about deploying SSG without third party CI/CD ? Sure, you can deploy manually, using only your git client on local PC, or notebook, or whatever you call your workstation. We are going to learn method other than git refs.
I’m using Pelican SSG as an example. It is rare that people using Pelican. But do not worry. The example should be easy to follow.
Hypotethically, this example also applied for other SSG as well, such as: Jekyll, Hugo, Hexo, or Eleventy.
However, this article is only an example of how
git worktree works.
The methods described here is not recommended for daily use.
Manual CI/CD is not recommended for daily use.
After you read this article, you might desire to apply the method,
in other CI/CD, such as Circle-CI or other.
git worktree is crucial step,
before you get your foot, step on complex CI/CD.
It is not a must, but this will shorter your configuration some lines.
1: Understanding Worktree
Why do we need worktree 🤔?
Because most practice in simple SSG,
is putting the
generated site in the same repository as the
In short, we need two branches.
Some says this is bad practice. But people do it anyway, so why bother? As long as the repository is yours alone to work with, you are safe.
This method here is not something you want to do on daily basis.
You just need to understand how
so that you can solve some issue using
worktree whenever you need.
So you know how to
pull in your daily life.
It is time to leverage your knowledge using worktree.
In a nutshell
In a nutshell,
git worktree enable you to work,
with different branches in a same time.
Normally you can only open one branch at a time,
when you switch
the content of your directory will reflect current opened branch.
You cannot edit other branch while working on an active branch.
git worktree solve this limitation by opening other branch in other directory.
This means, you can edit both branch at a time.
Supposed that I have two branches:
developfor source code, and
masterfor live site.
Consider these two directories separated by tmux below:
Both directories comes from the same repository.
What make both different is the two branches:
Top Directory: pelican-repository, using
Bottom Directory: pelican-site, using
I also intentionally using
develop for source and
master for live site,
in contrast to common practice,
master for source and
gh-pages for live site.
Remember that neither gitlab and bitbucket have
Thus we need to generalized the situation.
This example is using Pelican as an example.
As default, Pelican generate the live site into
Consider see both directories, separated by tmux.
It is going to be hard to tell github or gitlab or bitbucket,
to use subdirectory as the source of your live site.
Those three above use
branch instead, as the source of your live site.
Do Not Upload
Normally you don’t want to push this
output directory to repository.
So you tell
.gitignore not to upload this
output __pycache__ .pyc
git worktree, you can copy from build
develop branch to
This is what we desire to achieve:
We can just copy-paste from
output directory from
into root directory in
Because the process is just copying from a directory to other directory.
2: Prepare Your Repository
Now it is a good time to get start with an example.
Please do not get intimidated of the long commands. Just type it, and you will get the same result.
The application in real life example, should be only a few lines. Much more shorter than example below. Once you get the idea. This is not scary at all.
$ mkdir pelican-repository $ cd pelican-repository $ git init Initialized empty Git repository in /media/Works/repository/test/pelican-repository/.git/
Create Master Branch
$ git checkout -b master Switched to a new branch 'master' $ echo "Test Master Branch" > MASTER.md $ git add MASTER.md $ ls MASTER.md $ git commit -m "Master: First Commit" create mode 100644 MASTER.md $ git branch | cat * master
Create Develop Branch
$ git checkout -b develop $ ls MASTER.md $ rm MASTER.md $ echo "Test Develop Branch" > DEVELOP.md $ git add DEVELOP.md $ ls DEVELOP.md $ git commit -m "Develop: Second Commit" create mode 100644 DEVELOP.md $ git branch | cat * develop master
$ git add --all $ git status deleted: MASTER.md $ git commit -m "Develop: Clean up MASTER.md" $ ls DEVELOP.md
So that we now have both clear
$ git checkout master Switched to branch 'master' $ ls MASTER.md $ git checkout develop Switched to branch 'develop' $ ls DEVELOP.md
$ git worktree list /media/Works/repository/test/pelican-repository 0f1ab9e [develop] $ git worktree add ../pelican-site master Preparing worktree (checking out 'master') HEAD is now at 28036ae Master: First Commit $ ls ../pelican-site/ MASTER.md
Now your branch should like this below:
3: Source and Build
Now come the SSG part.
I have already prepare my pelican site in other directory,
You can have it from here:
Pick any steps you want, and put it there.
In my case, I copy only the last step
step-07 into root directory.
Add Source Code to Develop
$ cp -rT ../pelican-example/ ./ $ ls -a . content .git lib output plugins README.md tutor-07 .. DEVELOP.md .gitignore Makefile pelicanconf.py publishconf.py tasks.py $ cat .gitignore output __pycache__ .pyc *.swp *.swo
$ make publish pelican \ /media/Works/repository/test/pelican-repository/content \ -o /media/Works/repository/test/pelican-repository/output \ -s /media/Works/repository/test/pelican-repository/pelicanconf.py Done: Processed 10 articles, 0 drafts, 3 pages, 0 hidden pages and 0 draft pages in 2.21 seconds. $ ls output 2014 2017 2019 archives.html author blog category index.html tag theme 2015 2018 archives archives.py.txt authors.html categories.html feed.xml pages tags.html
Copy Build to Master
We should commit each branch separately.
$ cp -r output/* ../pelican-site/ $ ls ../pelican-site/ 2014 2017 2019 archives.html author blog category index.html tag theme 2015 2018 archives archives.py.txt authors.html categories.html feed.xml pages tags.html
Now it is a good time to compare both
The only different is, the
In real life configuration.
It is common to delete all before copy,
so you have clean land to start with.
Commit Source Code
$ git status On branch develop Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore Makefile README.md content/ lib/ pelicanconf.py plugins/ publishconf.py tasks.py tutor-07/ $ git add --all $ git commit -m "Add pelican example source"
Commit Build Site
$ cd ../pelican-site $ git status On branch develop Untracked files: (use "git add <file>..." to include in what will be committed) 2014/ 2015/ 2017/ 2018/ 2019/ archives.html archives.py.txt archives/ author/ authors.html blog/ categories.html category/ feed.xml index.html pages/ tag/ tags.html theme/ $ git add --all $ git commit -m "First Build"
Now consider comparing
HEAD for each branches.
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s" | cat * 4f08227 (master) First Build | * 701bc4e (HEAD -> develop) Add pelican example source | * 0f1ab9e Develop: Clean up MASTER.md | * 9c7cea2 Develop: Second Commit |/ * 28036ae Master: First Commit%
Each directory show different
HEAD, reflecting each branch.
What is Next ?
Done with these steps. Now it is time to push to either bitbucket or gitlab or github.
Consider continue reading [ CI/CD - Git Worktree - Part Two ]. Finishing this worktree feature guidance with examples.