Skip to content

Instantly share code, notes, and snippets.

@DavZim
Last active February 13, 2020 09:08
Show Gist options
  • Save DavZim/ad5edec10d2507f2ecba360b7452cf92 to your computer and use it in GitHub Desktop.
Save DavZim/ad5edec10d2507f2ecba360b7452cf92 to your computer and use it in GitHub Desktop.
Simple explanation how to use git-hooks to automatically deploy your code to production

How to Deploy git to a Server using git-hooks

The following script outlines how we can use git-hooks for continuous deployment (when you push your git repository, it will automatically be deployed to the server).

Note, this script is heavily based on but slightly extends this gist, see also this explanation.

Basic idea: using git-hooks to copy the files on a target machine from a remote git repository to a specific target location.

For this, we need multiple components:

  • On the target machine (the production server)
    1. bare-repository that servers as a remote for our local repository
    2. target-folder which is the folder that will contain the code and from where the production is run
    3. post-receive hook that copies the files from the bare-repository to the target-folder
  • On the development machine (our laptop)
    1. ssh-config that specifies the connection to our server (name, ip, key-file, etc)
    2. add the target machine as a remote to our local git repo, allowing us to push to it

Here is how to achieve that:

Setup the target machine (=the server)

  1. Initiate bare repository ~/git-repo.git, this repo will contain all the git stuff and most importantly the hook that copies the master branch to the target-folder
git init --bare ~/git-repo.git
  1. Create the target-folder that will contain the code later on. Skip this step if you already have a folder for the app/whatever-your-server-does, but make sure to change TARGET in the next step
mkdir target-folder
  1. Create post-receive hook in the git repository

The basic idea is that this bash-script is run after a new push is received on the server, it checks if a certain branch is updated and copies the contents to the target folder

vim git-repo.git/hooks/post-receive
chmod +x git-repo.git/hooks/post-receive

An example post-receive hook might look like this

#!/bin/bash
TARGET="/home/ubuntu/target-folder"  # the path to the target folder where the code will be copied to
GIT_DIR="/home/ubuntu/git-repo.git"  # the path to the git repository
BRANCH="master"                      # which branch should we consider here, i.e., only pushes to master will be copied to TARGET 
LOGFILE="/home/ubuntu/deployment-history.log"

# datetime for logging
DATETIME=$(date +'%Y-%m-%d %H:%M:%S')

while read oldrev newrev ref
do
  # only checking out the master (or whatever branch you would like to deploy)
  if [ "$ref" = "refs/heads/$BRANCH" ];
  then
    COMMIT=$(echo $newrev | cut -c 1-7)
    TXT="[${DATETIME}] ref $ref | commit ${COMMIT} | Copying branch ${BRANCH} to ${TARGET}"
    echo $TXT
    echo $TXT >> $LOGFILE
    git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
  else
    TXT="[${DATETIME}] ref $ref | Only branch ${BRANCH} accepted, nothing done"
    echo $TXT
    echo $TXT >> $LOGFILE
  fi
done

Setup the local machine (=our laptop)

  1. Configure ssh-config to allow git to connect to the server
vim ~/.ssh/config

add to ~/.ssh/config (or create if necessary) (see this answer for an explanation)

host name-of-the-server
 HostName 123.456.789.012
 IdentityFile ~/path/to/the/key.key
 User git

where name-of-the-server is an arbitrary name that we use later to address the server, 123.456.789.012 is the IP address of the server, and ~path/to/the/key.key is the same key you would use in ssh (i.e., in ssh -i ~/path/to/the/key.key [email protected].

  1. Add the target machine as a remote

Go to your repository and add the target as a remote

git remote add production ubuntu@name-of-the-server:git-repo.git

where production is the name of the remote, ubuntu the user on the target machine, name-of-the-server the name of the server as specified in the previous step, and git-repo.git the bare git repository as setup in the first step.

If you mess up this step (or want to change it), git remote rm production removes the production repository.

And you are all setup.

Working with the setup

Work as usual, once you have committed your changes, push the master branch to production with

git push production master

To make sure that the new version is in production, you can look at the logs (on the target machine) tail ~/git-repo/deployment-hook.log (or whatever you named your logfile).

Outro

As always: Make sure that you only commit production-level code to master (and subsequently push only working code to the target server/production). Alternatively, you can can change the master branch to another production branch or similar.

This heavily encourages a good git branching model such as this one: branching-model

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