If you are new to the world of distributed version control systems such as Git, it can be hard at first to wrap your head around how the hell it actually works. Or never mind that, just getting it to work can be a struggle in itself!
I remember when I got started, in my case with Mercurial and Bitbucket (similar to Git and GitHub). I was tasked with figuring this stuff out for my team and I really struggled wrapping my head around the various concepts, figuring out how it all fit together, how
Git Bitbucket factored into all this and finally working out the most basic workflow from all the scattered, conflicted and (for me) far too advanced advice I found on the internet. When I finally managed to figure out branches, commit some changes, have them pushed and checked out somewhere? You know, I might have done a little dance in the office! And trust me, that never happens. I was really, really happy and proud of myself. And relieved. Immensely relieved.
Maybe you are a solo developer. You've heard about Git and how awesome it is and you have reached the point where you are able to do the basic actions and get your code on GitHub. Cool. But how do you actually go from there to having your code deployed on the production server?
You've probably cloned a couple of Git repositories from GitHub, so your first attempt was likely to simply clone your own Git repository into the destination directory of your server and pull whenever you made changes. This works. But you really, really shouldn't do that. You could mess around with Apache's .htaccess, denying access to the hidden .git directory, but it is easy to forget and I don't think Nginx even has an equivalent. There's a much better solution using a bare repository and a post-receive hook. Sounds complicated, but it really isn't. Let me show you.
Create a new repository
First, create a new directory
coolapp somewhere on your computer. Let's create a new Git repository inside it with
Next, create a new file in this directory, for example a
readme.md file with hello world written in it. Let's add the file to our Git repository and commit it:
git add . git commit -m "my first commit"
Link the repository up with GitHub
Visit GitHub, login to your account and create a new private repository. I'll assume your username is
solodev and your repository is aptly named
We want to link the local repository on your computer with this new remote repository on GitHub, so let's do that. On your computer:
git remote add origin email@example.com:solodev/coolapp.git git branch -M master git push -u origin master
Great, the repositories are now linked. Feel free to make some changes, commit those changes and do a
git push. So far so good. The next step is to get your files deployed onto the production server.
Prepare the server
Before we proceed any further, you'll need to make sure your production server is set up correctly. If you are currently using a password to login your server, it is not set up correctly. Please follow these instructions to switch to authentication with SSH keys before proceeding.
Ready to continue? Please login to your production server.
The way this is going to work is that we use a bare repository (a repository without checked out files) and a post-receive hook, which is just a script that places the files in the correct deployment directory on the server.
coolapp is stored and served from
/var/www/coolapp, lets create the directory
var/git to store our bare repositories and give this directory appropriate user rights. Then create the subdirectory for
coolapp. For example if you are logged in as
sudo mkdir /var/git sudo chown solodev:solodev /var/git mkdir /var/git/coolapp
Create a bare repository & write the post-receive hook script
var/git/coolapp, we are going to initialize a new bare repository:
git init --bare
Next, we are going to write the post-receive hook script with
#!/bin/sh git --work-tree=/var/www/coolapp --git-dir=/var/git/coolapp checkout -f
Save the file and make it executable:
sudo chmod u+x,g+x hooks/post-receive
Link the repository up with the the server
You are almost there. The final piece of the puzzle is to give the bare repository on the production server actual changes to work with, which it will then checkout into the working directory where your
coolapp is served from.
Back on your own computer, go to the
coolapp directory. Open the hidden
.git/config file with your favorite editor. You will find a section like this:
[remote "origin"] url = firstname.lastname@example.org:solodev/coolapp.git fetch = +refs/heads/*:refs/remotes/origin/*
We are going to modify it like this (with the pushurl):
And that's it! To test it out, make some changes, commit & push. You'll notice that your GitHub repository was updated and your server at the same time as well.
How cool is that?
I hope this helped you. I should note that this method breaks down quickly if you work in a team or have a more complicated setup with staging servers and/or multiple production servers.
If you would like to read more, check out:
- GitHub Actions, which explains how to set up hooks that hook directly into changes made to the GitHub repository.
- Vincent Driessen's git-flow branching model, which has become somewhat of a de facto standard workflow in software development.
- The GitHub flow branching model, a much simpler workflow for web development.