How can I automate checkout on click?
Consider the following situation:
I have a git repository foo.git that contains the javascript project code. This repository has a branch production that contains the state of the code served by the web server that pulls the code from /var/www/foo
. This repository is the main repository for the project. Everyone pushes and pulls from / to him.
Is it possible to upgrade /var/www/foo
to a production checkout when someone pushes to that particular branch? You can assume that the git daemon (or the git user, which is the user that all people register to connect to over SSH) has write permission to the specified directory.
source to share
You need to create a bare repository on the server with git init --bare
. Then use the post-receive
hook to start the deployment. How you deploy is up to you.
My deployment strategy
I usually put a directory deploy
somewhere logical. Then each checkout I unpack the last branch to deploy/COMMIT_ID
, where COMMIT_ID
is the hash of the last push. Once validation is complete, you can reassign the symbolic link to the latest deployment directory.
My usual directory structure:
deploy.git/
deploy/
a7922231/
b2f0a2af/
latest -> b2f0a2af
Unpacking the update
Instead of using, git-checkout
I usually use git-archive
to unpack a branch into a directory.
# Assuming current directory is deploy.git
HEAD=`cat refs/heads/master`
mkdir -p ../deploy/${HEAD}
git archive master | tar -x -C ../deploy/${HEAD}
Your webserver may be pointing to deploy/latest
, updates will be more or less atomic.
I use this a lot during production and have several advantages over unpacking over the same directory.
- kickbacks are simple.
- you can perform post-decompression procedures such as compiling or installing dependencies without interrupting your current deployment.
Tips
- each update is appended to the deployment log , which indicates when the updates happened and what their hash IDs are. This makes rollbacks a lot easier.
source to share
You need to create a file post-receive
in yours /git/foo.git/hooks directory
(based on my comment above). Something like this (with some debug protocol):
#!/bin/sh
echo 'Hook called'
pullneeded=false
while read oldrev newrev refname
do
echo "OLDREV $oldrev NEWREV $newrev REFNAME $refname"
if [ "$refname" == "refs/heads/production" ]; then
echo 'Pull needed'
pullneeded=true
fi
done
if [ $pullneeded ]; then
echo 'Pull'
cd /var/www/foo
git --git-dir=/var/www/foo/.git pull
fi
echo 'Hook done'
You need to set up a git repository /var/www/foo
to track the production branch of another repository. If it is called a source, then it is:
git branch --set-upstream production origin/production
And of course the production department should be checked out in your repository /var/www/foo
.
UPDATED
Maybe a hook is post-update
more appropriate (sample from here fooobar.com/questions/1994383 / ... ):
#!/bin/bash
case " $* " in
*' refs/heads/production '*)
cd /var/www/foo
git --git-dir=/var/www/foo/.git pull
;;
esac
source to share