Skip to content

Instantly share code, notes, and snippets.

@danmikita
Last active December 21, 2015 09:08
Show Gist options
  • Save danmikita/6282509 to your computer and use it in GitHub Desktop.
Save danmikita/6282509 to your computer and use it in GitHub Desktop.
In an enterprise it can be very important to track the release version of various applications. In an attempt to simplify how we track old releases, as well as how we roll back to previous versions, I wanted to find a way to use git push to deploy various git tags. This would allow for a more standard approach to deploys within our organization.

Git Push Deployments

Some Background Information

In git, a tag (like many other things) is what's called a treeish. It's a way of referring to a point in the history of the project. Treeishes can be a tag, a commit, a date specifier, an ordinal specifier or many other things. A branch is just like a tag but is movable. When you are on a branch and make a commit, the branch is moved to the new commit you made indicating it's current position.

Your HEAD is a pointer to a branch which is considered "current". Usually when you clone a repository, HEAD will point to master which in turn will point to a commit. When you then do something like git checkout experimental, you switch the HEAD to point to the experimental branch, which might point to a different commit.

When you do a git checkout v2.0 (v2.0 in this case is a tag), you are switching to a commit that is not pointed to by a branch. The HEAD is now "detached" and not pointing to a branch. If you decide to make a commit now (as you may), there's no branch pointer to update to track this commit. Switching back to another commit will make you lose this new commit you've made.

Usually, what you can do is say git checkout -b v2.0-fixes v2.0. This will create a new branch pointer at the commit pointed to by the treeish v2.0 (a tag in this case) and then shift your HEAD to point to that. Now, if you make commits, it will be possible to track them (using the v2.0-fixes branch) and you can work like you usually would.

It is also important to define the difference between the GIT_WORK_TREE and the GIT_DIR.

  • GIT_WORK_TREE describes the code that is in the top level directory of your local git repo. It is what you make code changes to and commit.

  • GIT_DIR refers to the .git folder which contains the hooks folder among others.

Getting Started

Remote Set-Up

To set up the ability to deploy from your local git repository to a remote server, you will need to start by setting up a bare git repository on that server. Create a directory and change to that directory.

mkdir ExampleApp.git
cd ExampleApp.git
git init --bare

Now if you look at what that created within the folder, you'll notice it actually created the contents of a .git folder. This beens that this folder is now considered your GIT_DIR. Next we need to set up this new repository as a remote within our local git repository.

Local Set-Up

git remote add production ssh://192.168.1.1/var/git/ExampleApp.git

We then just need to do our first push of our code.

git push production +master:refs/heads/master

From this point on, when ever we make a code change, we only need to run the command:

git push production

Tag Deployment

To create a tag (or release) and push that to a specific remote (or environement) you would run:

git tag -a v1.1 -m 'Version description'

git push -f production v1.1^{}:master

This last command probably looks quite scary, and it definatley requires the understanding of treeishes to comprehend. What you see in regards to v1.1^{} is called a Tree Pointer.

Tree Pointer

This disambiguates a commit from the tree that it points to. If you want the sha that a commit points to, you can add the '{tree}' spec to the end of it.

master^{tree}

To put it simply, this crazy syntax is allowing you to place the pointer on your master branch to the sha location of your tag. From there you can run a generic git checkout -f within your post-receive hook and checkout that specific tag.

Post Receive Hook

As for the post-receive hook, this is a basic example that you can edit. It is based upon a Java application to show how you can compile the code, start/stop your various services, and move files around all within this hook. Notice the export statements near the beginning, they are important.

#!/bin/bash

echo "Running post-receive"
export GIT_WORK_TREE=/home/danmikita/temp
export GIT_DIR=/home/danmikita/temp/FavoriteColors.git

echo "Check out local copy"
cd $GIT_WORK_TREE
git checkout -f

echo "Maven build the new code"
mvn clean package

echo "Starting the new process under nohup"
nohup java -jar target/example-site-develop-SNAPSHOT.jar server example.yml > /var/log/example/example-log.log 2>&1 &

echo "Complete. Verify operation by visiting http://example.org/"
@danmikita
Copy link
Author

You can look at the man page for more on 'Tree Pointers'

man git revisions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment