Deploying to Production with Git

On your last day at any job, it is fun to go and change a bunch of things and then leave it all with your colleagues and say “Peace Out!” One thing you could do is rewrite/rework the project’s build and deploy process. Here is a way you could do it using Git with a Django project using Nginx and UWSGI (and yes, I did this all on my last day :).

The process is (1) automate our build process with a Makefile, (2) setup a Git repo on the live server to push to, and (3) use a Git hook to automatically call our Makefile targets.

Build with a Makefile

First things first, lets write a Makefile because they are very helpful. You can replace a Makefile with some other script or set of scripts, but I find Makefiles to be a very good idea on Unix based systems. You just need something to automate the your build process.

Here is an excerpt that is pretty similar to the Makefile I used:

# Makefile for building and deploying
#

UWSGI=/etc/init.d/uwsgi
NGINX=/etc/init.d/nginx

deploy: dependencies clean minified_static_files

restart: $(UWSGI) $(NGINX)
	$(UWSGI) restart
	$(NGINX) restart

stop: $(UWSGI) $(NGINX)
	$(NGINX) stop
	$(UWSGI) stop

dependencies: dependencies.pip
	pip install -r dependencies.pip # Or requirements.txt

resources:
	python resources_build.py # Minifies static files.

minified_static_files: resources
	python manage.py collectstatic # Collect into static_files/

clean:
	@-rm -rf static_files/
	@-find . -name '__pycache__' -exec /bin/rm -rf {} ;
	@echo 'Successfully Cleaned!'

.PHONY: clean resources dependencies restart stop deploy

You can put any useful commands that you run often in your project during development or when deploying to production. Put this in the root of your project directory or anywhere else in your Git project so you will not lose it.

Setup Production Git Repo

Lets use a Bare Git Repository. Log in to your production server, create a new directory, and initialize it as a bare git repository.

mkdir prod-repo
cd prod-repo
git init --bare

You will need to add this repository to your Git remotes on your local machine. The command looks something like this:

git remote add production ssh://username@www.yourserver.com:PORT/path/to/prod-repo

FYI: The PORT is whatever port you run your ssh server on.

Post-Receive Git Hook

Now lets setup a post-receive git hook on the production bare git repository that will call your makefile (or other automatic script) once a push has been received.

vim prod-repo/hooks/post-receive

A git hook file is any executable script, so you can write it in bash, sh, python, ruby, etc. Lets keep it simple and use sh.

#!/bin/sh
#
# SOURCE_DEST is whatever directory you have configured
# uwsgi look for your app in.  This is where Git will put
# the new source files that you push to this repo.

# Variables
SOURCE_DEST=/path/to/source
GIT_DIR=/path/to/prod-repo

# Update the HEAD to latest commit
git --work-tree=$SOURCE_DEST --git-dir=$GIT_DIR checkout -f

cd $SOURCE_DEST

# Run make targets
make deploy
make restart

# Fix permissions for Code
chown -R www-user $SOURCE_DEST
chgrp -R www-user $SOURCE_DEST

Putting it all Together

To update production, just issue a git push command to your production remote:

git push production master

This will push your changes on git and run your post-receive git hook script which calls your Makefile targets. Customize this to fit your needs. You can easily add in targets to run database migrations, compile coffeescript, pre-process CSS for SASS or Less, run unit tests, etc. The sky is the limit. It would also be a good idea to use a git tag each time before you push to production. Consider using some client-side git hook to accomplish that 🙂

Advertisements
Deploying to Production with Git

Git Commands You Should Know

Git is awesome! I used Subversion a lot when doing Java projects in school, and we used Mercurial at Qualtrics but Git is my favorite by far. I like Git and Mercurial over Subversion because of the distributed design: every repository contains the entire codebase and version data. Mercurial does have a little (IMHO very little) better command line interface than Git, but I feel Git has far more power especially when editing commit history (interactive rebase FTW). For a more in-depth discussion of Git vs. Mercurial (and why Git is better), I recommend this Atlassian blog post.

This post however is not about why Git is better than other DVCS. I would like to point out a few helpful commands that I use often (like all the time and you should to) or commands I wish I knew about when I first started using Git. I will skip some common commands like add, commit, push, merge, fetch, and pull and try to focus on non-essential but useful commands; the ones you could work without but really shouldn’t.

Continue reading “Git Commands You Should Know”

Git Commands You Should Know

Staging Portions of Files in Git

Git is a great tool.  Hands down, it is the best VCS on the market (well, if free and open source count as “on the market”).  One of the features I really like about Git is the ability to stage and unstage files for a commit.  This helps you keep your commits logically cohesive without trying to force yourself to only work on one task at a time; you can work on a few different tasks, and then put your changes into different commits by staging them appropriately.

Until recently, I thought I could only stage and commit whole files.  But NO!!!  You can stage and commit a portion of the changes in a file using Interactive Staging.  Handy my friends!

Continue reading “Staging Portions of Files in Git”

Staging Portions of Files in Git