Very simple ‘git push’ workflow to deploy code on your own server

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, December 29, 2015

Follow me on Twitter as @mattiasgeniar

This technique isn't new. In fact, it's far from it. Around 2013, everyone seemed to be using this (or some variant of it) to deploy simple projects. But since then, it seems to have quiet down a bit. That's a shame, because it's super easy to use.

Here’s how it works.

A git-push-to-deploy scenario

Imagine being able to do just the following to push a change to production.


This boils down to just 2 commands to push your change to production (or any release cycle, really):

$ git commit -am "Commit this awesome change"
$ git push live master

This would be unthinkable in large projects (no code review, no approval process, …), but for simple projects this is absolutely dead easy to use.

Preparations on the server

If you’re reading “server” and thinking “wait a minute, I don’t have a server", this probably isn’t for you. You need a server (or at least: an SSH account, does not have to be root) in order for this to work. Shared hosting etc. probably won’t work, unless you’re given an SSH account which can execute git binaries.

Assuming you have the following directory structure for your site in your home directory:

$ ls -l

First, create a new directory that will contain your git repository data (the ‘raw’ data). I’ll name it repo.git in this example.

$ mkdir ~/repo.git
$ cd ~/repo.git
$ git init --bare

Your server is now ready to ‘host’ a git repository: that’s the magic behind git init --bare.

As a final touch, you need to add a post-receive hook to that repository. A post-receive hook is a simple bash-script (or any kind of executable, really) that gets called whenever this repository receives data from a git push.

We’ll use this to trigger an update of your live site whenever a new change is committed to this repository.

$ vim ~/repo.git/hooks/post-receive

Copy/paste the following content in there.

git --work-tree=~/htdocs --git-dir=~/repo.git checkout -f
git --work-tree=~/htdocs --git-dir=~/repo.git pull
echo "Hooray, the new version is published!"

And make sure the file is executable.

$ chmod +x ~/repo.git/hooks/post-receive

When you first configure this, you’ll need to make a first git clone manually to your htdocs directory (if this directory already exists, either move it temporarily (as a back-up) or remove it altogether).

$ git clone ~/repo.git ~/htdocs

Now you’re all set to start receiving git pushes and auto-update your site.

Preparations on the client side

On the client-side, you only need to add a new git remote location. This will refer to your newly created repository.

From within the root of your git repository (the top most directory), add your new git remote.

$ git remote add live ssh://your_username@your_hostname.tld/~/repo.git

This will add a new repository to your git configuration named live which points to ssh://your_username@your_hostname.tld/~/repo.git. The endpoint may look cryptic, but it’s just your SSH username @ server name or IP / path to your git repo.

If you were to list your git remotes locally, it would look like this (with different URLs, obviously).

$  git remote -v
live	ssh:// (fetch)
live	ssh:// (push)
origin (fetch)
origin (push)

For this example, I abused my string encoder/decoder tool, which you can also find on Github.

Now, whenever you do the following:

$ git commit -am "your commit message"
$ git push live master

… your server will receive the data from the git push and it will trigger its post-receive you configured above, making a checkout in your htdocs folder from the git repository.

Boom, your change is live.

Update: as was pointed out to me by @pjaspers, there’s a ruby gem called git-deploy that can help with most of the setup involved.

Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.