Automate deployment using GitHub hooks
Tags: git, githubhooks, deployment, becode
Published: 2019-08-13 15:08:29

---
title: Automate deployment using GitHub hooks
published: true
description: Let's quickly see how to setup an efficient pipeline to deploy using git and GitHub hooks
tags: git, github-hooks, deployment, BeCode
cover_image: https://thepracticaldev.s3.amazonaws.com/i/u8lioyliyagq85e3o4cz.gif

---

The first time I witnessed the cleverness of the _deployment using git_ strategy was with GitHub Pages: simply `git push` to the master branch of your repository and your static web page is updated. As simple as that.

I wanted to be able to deploy with the same elegance on my own servers and for more complex applications. I thought I understood how it worked but not how to automate it. So I would manually `ssh` into the server, `cd` my way into the project folder, then `git pull`. Every. time. Not really convenient.

When I discovered [Trellis](htts://roots.io/trellis) I learned to use ansible  to be able to deploy by using a oneliner: `./deploy.sh production domain.com`)...

But then Ansible is a power tool, which does a lot of other things than just deploy. And I learned the hard way that I should not update my local Ansible version otherwise... All hell break loose. 
Also, I would still have to `git push` to the remote prior to launching the deployment.

## One line to rule them all

Working at [BeCode](https://becode.org) is cool because you get to meet dozen of fellow developers, craving to learn and explore. One of our learners pointed me in the direction of using a GitHub Post-Receive hook, thanks to which deployment is a simple : `git push production master`. The hook launches a local script that `git checkout` the master branch on the production server, then runs any other custom operations you want (such as `composer update` for example).

Let's see how to set it up.

### 1. Setup a bare Git repository on production server

First, create a "bare" repository – one that does not contain the working copy files. It basically is the content of the .git repository folder in a normal working copy. Name it whatever you like (you could also omit the .git part from project.git but I find it best to keep it):

```sh
cd /path/to/project/folder/
mkdir project-name.git
cd project-name.git
git init --bare
```


### 2. Configure the GitHub hook

Create a post-receive hook at `/path/to/project/folder/project-name.git/hooks/post-receive`

```bash
touch hooks/post-receive
```


Fill it with your version of the following code (use your specific folder paths) :

```sh
#!/bin/sh
NOW=$(date +'%d-%m-%Y_%T')
# check out master branch
GIT_WORK_TREE=/path/to/destination/folder/htdocs git checkout -f master

# custom steps for deployment
# For example, let's execute composer to refresh our dependencies : 
cd /path/to/destination/folder/htdocs
composer update
# backup current version, in case we need to do a rollback
cp -R /path/to/destination/folder/htdocs/. /backups/project-name/$NOW/
```

Make sure it is executable: 

```bash
chmod +x post-receive
```

### 3. Add the remote-repository to your local system

Let's now add a reference to this bare repository to our local system, as a remote location. Let's call this remote "production". (It could also be called "staging" or "live" or "test"... should you want to deploy to a different system or to multiple systems.)

```bash
cd ~/path/to/working-copy/
$ git remote add production ssh://username@myserver.com:22/path/to/project/folder/project-name.git
```


Check that your new remote is now available, and all the existing ones:

```bash
git remote -v
```


### And... that's it!

You can now deploy using this beautiful one liner :

```bash
git push production master
```

## Going beyond ? TDD !!

With this, I have the raw basis of a deployment pipeline. The next step would be to add code testing to make sure code updates do not introduce bugs or break anything (regression testing). I assume I should look at how to use [Ansible](https://github.com/trinitronx/ansible-tdd) for that. 

Since I don't know how to do that yet, I'll leave you to ~~google~~ [dev.to/search](https://dev.to/search?q=TDD) your way around that one !