listen up

Setting Up Server Environments For A Seamless Git Deployment

Chances are, you’re already using a Git repository to track your code changes. So wouldn’t it make sense to just push those changes to your server? Wouldn’t it be nice to just push your develop branch to a staging environment and push your master branch to a production environment?

I’m going to assume you already have your local project set up with a develop and master branch… So let’s move right in to setting up the remote repositories on your server.

Setting Up The Remote Repository

Login to your server via your terminal and lets create a folder for your repo to live in.

## Login to your server
$ ssh [email protected]
## create repo folder
$ mkdir repos
## navigate to created folder
$ cd !$

Awesome. Now lets make an empty git repository inside of /repos/.

## create and name your repo folder
$ mkdir yourrepo.git
## navigate to your repo folder
$ cd !$
## initialize empty repo
$ git init --bare

Now here is where the fun comes in. We’re going to need to setup whats called a post-receive hook to tell our repo what to do with the branches once they are received. So lets navigate to our hooks folder. Chances are, there is not a post-receive file so we will have to create one.

## navigate to hooks folder
$ cd hooks
## create post-receive file
$ touch post-receive

Now we’re ready to go… Let’s dive into the script we will be using to do the magic. The first thing we need to do in our script is tell it where our staging and production trees will be living. We are going to assume that our production lives in public_html/ and that staging lives in public_html/staging/ to make it nice and easy. Of course, you can have your environments live where ever you want on your server. Open post-receive using your editor of choice and lets get this rolling.

#!/bin/sh
GIT_DIR=$PWD
STAGING_TREE=/home/youruser/public_html/staging
PRODUCTION_TREE=/home/youruser/public_html/
GIT_WORK_TREE=

The above section is pretty straight forward. We are telling the script that the git directory, GIT_DIR lives in the previous working directory, and that the staging and production trees live in their respective spots on our server. Next we need to setup our git work tree, so that the repository knows where to place the files based on branches. So continuing in the same file:

while read oldrev newrev refname
do
  	GIT_BRANCH=$(git rev-parse --symbolic --abbrev-ref $refname)
        if (test "$GIT_BRANCH" = "master" ); then
                cd $PRODUCTION_TREE || EXIT
                GIT_WORK_TREE=$PWD
        fi
	if (test "$GIT_BRANCH" = "develop" ); then
                cd $STAGING_TREE || EXIT
                GIT_WORK_TREE=$PWD
        fi
done

What this section of the script does is check the commits and decide where to place them. If the commits exists on master then it puts it in the production tree, if its in the branch develop it moves it to the staging tree.

Next we just need to add one more piece to manage our work trees and branches. Continuing in the same file add:

if (test "$GIT_WORK_TREE" != ""); then
        cd $GIT_DIR
        git --work-tree="$GIT_WORK_TREE" checkout $GIT_BRANCH -f
fi

This just makes sure that the correct branch and work trees are checked out.

All together, your script should look something like this:

#!/bin/sh
GIT_DIR=$PWD
STAGING_TREE=/home/youruser/public_html/staging/
PRODUCTION_TREE=/home/youruser/public_html/
GIT_WORK_TREE=
while read oldrev newrev refname
do
  	GIT_BRANCH=$(git rev-parse --symbolic --abbrev-ref $refname)
        if (test "$GIT_BRANCH" = "master" ); then
                cd $PRODUCTION_TREE || EXIT
                GIT_WORK_TREE=$PWD
        fi
	if (test "$GIT_BRANCH" = "develop" ); then
                cd $STAGING_TREE || EXIT
                GIT_WORK_TREE=$PWD
        fi
done
if (test "$GIT_WORK_TREE" != ""); then
        cd $GIT_DIR
        git --work-tree="$GIT_WORK_TREE" checkout $GIT_BRANCH -f
fi

One last step we need to do on our server is set the right permissions for git to be able to execute the script. So in the hooks/ directory simply run chmod +x post-receive and we’re set.

Setting Up Your Local Repository

Now we just need to setup your local repository to have our new server side repository as a remote. Again, we’re going to assume you’re already up and running with a project using git. So let’s add the remote repository, we’re going to name it “server”.

$ git add remote server ssh://[email protected]/home/repos/yourrepo.git

Now, we can test our first push. Let’s push our develop branch to staging.

$ git push server develop:develop

This command then pushes our local develop branch to the develop branch on our remote server/repo which is mapped to our staging environment.

We repeat the same process for production:

$ git push server master:master
## or
$ git push server

And that’s it! You did it. No need for FTP, no need for two remote repositories, your branches push to their respective environments and your dev time just got a little easier and shorter.