Implementing a simple auto-deploy using git hooks

A common problem we all face is how to update the version of our code that is on-line. If you work with git and you don't use any tool for integration and deployment, your workflow probably looks a little like this:

  1. DO CODE \O/
  2. Decide that the code is stable (hopefully)
  3. Merge everything to the master or to a version branch
  4. ssh into the production server
  5. cd into your project directory
  6. Update the code
  7. Clean up stuff that may be messed up
  8. Grab a coffee and celebrate the new version on-line

There is a simple way to streamline things a bit on that workflow using hooks. (Not to be confused with GitHub's Webhooks)

So what's the magic?

My goal is to allow you to push your code directly to your server, as a git project, and allow you to do an auto-deploy from there.
Basically I'll give you a new git remote, like production, you'll do a git push production and BAM you can go get your coffee to celebrate.

Step by step

Setting up the server

  1. First of all, you'll need to create a new git bare repository.
    • ssh into your server
    • mkdir ~/yourapp.git
    • cd yourapp.git
    • git init --bare
  2. Now you'll have to cd to your hooks folder and open your post_receive file
    • This file will be executed every time your repository receives a commit.
    • Git creates a post_receive.sample file for you. You can rename it to post_receive or create a new one with the correct name.
  3. Suppose your code is being deployed at /var/www/html/yourApp and you created the yourapp.git folder at your home directory, put the following line at the file:
    • git --work-tree=/var/www/html/yourApp --git-dir=/home/<your_user>/git/yourapp.git checkout -f
  4. Save the file and allow it to be executed using a chmod +x post_receive

Setting up the client

  1. For that step, you'll register your production server as a remote.
  2. cd to your project respository
  3. Add a git remote to the directory of your bare repository
    • Supposing that the ssh host for your production server is ssh.myapp.com, your username there is dilbert and you create the bare repository at /home/dilbert/myapp.git, the remote path for the repository will be: ssh://dilbert@ssh.myapp.com:/home/dibert/myapp.git
    • Add this path as a remote using git remote add production ssh://dilbert@ssh.myapp.com:/home/dilbert/myapp.git
  4. Push your code to your new repository
    • git push production master
    • You are going to see some messages marked as remote
  5. That's it! Your new commit should now be online!

Tweaks

Okay, your code is online. But what else could you do? Here are a few tweaks you can do inside your post_receive file

  1. Print control messages
    • Remember that console messages that appeared after you did a git push production? You can print your custom messages too. Useful for displaying to you warnings and status updates about the deployment process.
  2. Install new dependencies
    • If you use composer, pip, npm, sbt or any other package manager, you can instruct your script to install its new dependencies.
  3. Migrate databases
    • Same thing
  4. Fix file/folder permissions issues
    • Sometimes when you put your code from git to your server, the permissions get messed up. You can fix them using your hook too. In Laravel projects, by example, your storage folder's permissions is sometimes set to a less permissive setting than needed.
  5. Run tests and print the results
    • You really shouldn't run tests in your production server. Except maybe for unit tests. Nevertheless, if you really want to, you can just add whatever command is needed to run your tests in your post_receive.
  6. Track a specific branch
    • By default, only master gets deployed

I will tackle those tweaks on a future post. For now, you should have a dead-simple but functional integration system.