Some time back, I wanted to setup my server so I could push code to my repositories, and have it automatically deployed to a website root directory after doing a git push from my local machine.
I can’t remember where I found the instructions so I can’t give credit to whom I got it from, but here’s how I did it.
This is followed by a tutorial on how to extend this setup to multiple branches and work-trees for “live” and “development” versions of a website.I use this method for small personal projects where I really only need one branch to be automatically deployed. I will assume you already have a local git repository (Head here for instructions how to, this is still somewhat valid!) with some code in it under a branch called ‘master’, and that you will push code to a remote server holding both your repository and your web server.
Create the remote repository (basic git setup)
On server:
mkdir /path/to/repo/project.git
cd /path/to/repo/project.git
git init --bare
On local machine:
cd /path/to/mycode
git init
git remote add origin git@yourserver:project.git
At this point (providing you have setup git on your server correctly, which I’m not going to cover here! This how-to is still valid) you should be able to simply push your code to your server with the usual command
git push origin master
Adding single branch automatic deployment
First, you’ll need a place to deploy your code to, that’s call the detached work tree from Git’s point of view because it’s a copy of the code without the history or references. I have both my repositories and webserver on the same machine so these instructions are for this configuration only. This detached work tree needs to be under your webserver’s root directory if you’re deploying a web site, but you could deploy that whatever place you want.
On server:
Create the work-tree directory and make make sure the git user (or the one you use for git repositories) has permissions to write to this directory:
mkdir /path/under/root/dir/project
chown git:git /path/under/root/dir/project
Then, you need to add a bit of configuration to your repository (created above):
cd /path/to/repo/project.git
git config core.worktree /path/under/root/dir/project
git config core.bare false
git config receive.denycurrentbranch ignore
Finally, all you have to do is create and make executable a “post-receive” hook in your repository’s hooks folder:
cd /path/to/repo/project.git/hooks/
touch post-receive
chmod +x post-receive
vi post-receive
And paste this code into this file:
#!/bin/sh git checkout -f
And voilà! Next time you push new changes from your local machine to the main server, the default (master) branch will be automatically checked out from your repository into the detached working tree.
EDIT: Following Luca’s comments below, it’s worth noting that if you have no local changes, nothing will get pushed, and the hook will not be fired! So when you do your next push (after all the setup), remember to edit a file to somewhat “force” a push. Then your content will be checked out by the hook. No update, no deployment
[...] to the bottomdown #ekynoxe development / design / photography / (and a bit of triathlon) « Automated deployment on remote server with git [...]
thanks!
I set up this environment in my dev server and works like a charm.
You might want to add an extra step:
I had to checkout your branch (in this case master) before being able to do
git checkout -f
which is in the post-receive hook.
What do you mean “checkout your branch”? Where was this? On the server, your local machine?
sorry I meant my branch :)
when you do (in your tutorial)
git push origin master
in order for the post-receive hook to start working I had to run first
git checkout master
then it worked.
Without doing this step first, it looks the repo is not set to any branch and a call to git checkout -f will result in a:
fatal: You are on a branch yet to be born
Ah, it might be because you tried to push without any content changes.
Doing a git push origin master with no content will not push anything, and the hook will not get fired
Actually, it might be because you’re not pushing anything to a branch named ‘master’ and git fails to recognise that… I think I need to check if git implies that the push has to be on a branch named ‘master’