Managing a standard product and a personal version on GitHub
SG 2019-01-26: From 2015 until 2019, this blog ran on homebrew PHP software called Upblog, a kind of headless CMS. Now it is a static site built with Jekyll.
This blog platform, Upblog, is on GitHub; I want anyone to be able to download and install it. But I also have a version that I want to use for myself. I soon realised I didn’t want to be copying-and-pasting code changes across from the standard to my personal, so there had to be a proper way to do this with git.
How to do it
The Upblog software is hosted at
My personal installation is
I have a folder for developing Upblog, which is isolated from my website folder. This has a git repo in it, which only has one remote:
$ cd ~/projects/upblog $ git remote -v origin https://github.com/stegriff/upblog (fetch) origin https://github.com/stegriff/upblog (push)
Then there is my website folder, which has two remotes:
$ cd ~/stegriff/upblog $ git remote -v origin https://github.com/stegriff/sg-upblog (fetch) origin https://github.com/stegriff/sg-upblog (push) product https://github.com/stegriff/upblog (fetch) product https://github.com/stegriff/upblog (push)
So the origin for my website is it’s own GitHub repo, but I’ve also added the
product remote (in the usual way):
$ git remote add product https://github.com/stegriff/upblog
Developing the standard product
I write code to add features to the standard product. Be disciplined! Don’t add features to your live site! When a feature is tested and ready, I check everything is committed and then I push to the SP’s origin. Now my changes are in the GitHub version at
Check your site is clean
If I’ve added new posts, templates, or other sitely things, I make sure they’re all committed to the website’s origin (
Ignore some files during pull and merge
We basically want to pull
product remote changes into my personal now. This has a few caveats. I want to ignore certain files because I don’t want to overwrite instance-related config or templates specific to my website. This can be done!
I have added a
.gitattributes file in the website directory as so:
/templates/*.* merge=ours config.php merge=ours .htaccess merge=ours README.md merge=ours
I’m not totally sure that the templates line actually works yet, but it’s a WIP. The merge strategy above needs to be configured at the prompt, like this:
$ git config --global merge.ours.driver true
I got both of those steps from the progit book.
Pull and merge
In my website directory:
$ git pull --no-commit --edit product master
--edit gives you peace of mind that you can sort everything out before committing. Since I got my gitattributes file straight, I don’t actually use these flags any more, but they might be helpful to you on your first few merges.
If there are any problems, I resolve these using my default merging tool (TortoiseMerge) by running
$ git mergetool -y
If you don’t have a nice GUI merge tool, you should install one.
During this process, throw in lots of
git status for good measure. You might be left with a
.orig file for any files you used the tool on, so just delete those in your file browser or by using
git add everything that you want to commit. I like to get my staged/unstaged into exactly the right state so that I can then
git add -A
When you’re ready, commit the result and push back to origin
$ git commit -m 'Merged new product features' $ git push origin master
If you’re completely unhappy with how a merge is going and you want to put everything back the way it was:
$ git merge --abort $ git status
If the merge has overwritten one or two key files, and you wanted to keep your site’s version, this can be fixed (using example of
$ git reset HEAD config.php $ git checkout -- config.php $ git status
git reset is the opposite of
git add; it unstages a change.
git checkout reverts changes on a file to the last commit.
Don’t maintain multiple codebases when you don’t have to! :)