Mark Eschbach

Software Developer && System Analyst

Autodeploying with Git

Git, as a version control system, is great at detecting file changes. This includes renames and rewrites, even when done outside of the Git tool chain. An interesting application of a Git repository is to autodeploy the files, tracking all changes. You can do this with your application in development, testing, and production configurations.

Core to my technique is using a post-receive hook within the target repository. The hook will checkout a copy of a specific branch such as production or beta into a specific directory. You may configure an application such as Jenkins to push to the remote repository, allowing for the target repostiory to have now knowledge of your build and distribution systems. To do this you must have a source repository, which must share common history with the target repositor(y/ies).

When provisioning a new system for deployment I cretae a new bare repository, then seed that repository with the branches I will be using. This is accomplished in lines 1-4 of the source below. The branches you wish to use should be created in your source repository and pushed backed to the origin host.

ssh deployer@target-host.example.com "mkdir -p repositories"
ssh deployer@target-host.example.com "git init --bare repositories/target-repository.git"
git checkout -b beta master
git push deployer@target-host.example.com beta
git push origin beta

The magic is within the post-receive hook. The hook defines the variable GIT_WORK_TREE, which allows us to use a location outside of the repository as the working copy. Git will ignore the fact we have a bare repository. For example, to always checkout the branch production to /home/deployer/websites/com.example your post-receive hook would look like the following:

#!/bin/sh
echo "Deploying files..."
GIT_WORK_TREE=/home/deployer/websites/com.example git checkout -f production 

The sharp hooks of snags

I only rarely need to deploy a new project or repository. As a result I keep getting snagged by git running via Jenkins complaining there are no common refspecs. Jenkin's git plugin (at least right now) checks the code out in a local detached branch from your target. Depending on your use case you may change the Jenkins settings (or just check it out in your scripts), or push the full refspec (IE: git push deploy/cloud origin/cloud ).