Deploying Websites with Git on Dreamhost

Note: This article has been updated since it was first posted in March 2012.

For someone who version-controls with filenames, Git is amazing stuff. I had been using Git to just do the bare-minimum of version control on my local machine, but I thought this would be a good opportunity to explore Git and learn more. In this guide I’ll take you through using Git to publish a site to Dreamhost. I’m making the assumption that you already have your local site in a Git repo, and that you’re running OS X. Unix will likely use the same commands but Windows won’t, hopefully this can get you pointed in the right direction though.

Getting started

You’ll need to SSH into your Dreamhost server to perform some of the setup, and luckily Dreamhost has a wiki page about getting that started. If you already have SSH access with a user, you can type ssh user@server.dreamhost.com into a terminal, and then enter your password after the prompt.

Now that we’re on the server, we can see if Git is installed by running which git. If you see a path like /usr/bin/git in the terminal then you are good to go. If you don’t have Git on your server already, Dreamhost has a wiki page to help you out (they have a pretty thorough wiki, including lots of unofficial topics).

Setup the server

In your home folder on Dreamhost, we’re going to run some commands to set up the remote Git repo.

mkdir website.git && cd website.git
git init --bare

You should change website.git to something more descriptive, I named mine after the site’s domain that this is for: brandonevans.ca.git. Now that we have an empty repo set up, we need to use a Git hook so that when we push our site to this remote repo it will get moved to the folder it’s hosted from. This folder is probably the domain name of your site, so the full path of mine is /home/brandonevans/brandonevans.ca. I use these in the example below. When you use the cat command, whatever you type next is going to be saved into the hooks/post-receive file. When you’re done typing everything from #! (hash-bang) to checkout -f, type control-d to save the file.

cat > hooks/post-receive

#!/bin/sh
git --work-tree=/home/brandonevans/brandonevans.ca --git-dir=/home/brandonevans/brandonevans.ca.git checkout -f

Once this file is created, run chmod +x hooks/post-receive to allow that file to be executed by the system. Now the remote hook is set up, and we can tell our local repo how to send our files up to the server. Exit the SSH session with exit and navigate to your site’s local directory on your computer.

Linking the repos

First we need to tell the local repo about the new remote repo we just setup. Here we’re setting the name of the remote to web, but you can change that as you wish (production, staging, TUBES, etc.). Again, you’ll want to put your own username and Git repo name into the command.

git remote add web ssh://brandonevans@server.dreamhost.com/home/brandonevans/brandonevans.ca.git

And now, we push! But first, realize that this will overwrite what is currently in your site’s public folder. Make sure anything you want is saved and committed in the local Git repo first, and backed up twice (never hurts).

git push web +master:refs/heads/master

If everything is working, you’ll see output like:

Counting objects: 30, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (17/17), done.
Writing objects: 100% (17/17), 5.16 KiB, done.
Total 17 (delta 11), reused 0 (delta 0)
To ssh://brandonevans@server.dreamhost.com/home/brandonevans/brandonevans.ca.git
   1f92b40..757a17a  master -> master

If you don’t see this you can try adding the remote repo with your own url like: ssh://myuser@myowndomain.com/home/etc

Now go check out your site to make sure everything looks right.

Big files

When I first set this up, my site had a lot of large audio files hosted on it. Because I’m on a shared server, these large files caused an issue when the hook did the first checkout, as Dreamhost’s procwatch killed git-checkout because of high resource usage. I was able to solve this with some configuration changes using git config --global and the following settings:

pack.windowmemory=10m
pack.sizelimit=20m
pack.threads=1
pack.packsizelimit=60m
pack.deltacachsize=50m
core.packedgitwindowsize=50m
core.packedgitlimit=50m
core.deltacachesize=50m
core.repositoryformatversion=0
core.filemode=true
core.bare=true

I’ve since moved all large files to an S3 bucket, and I’d definitely recommend never storing large files in your Git repo. Having a small repo makes it so much easier for you or someone else to clone it.

Finale

And that’s it! For a basic website like I’m running, this knocks out the FTP step after I commit changes because Git already knows the changes that need to be pushed. It’s also really cool to see how powerful Git hooks can be. Two resources I used in researching this article were Pro Git and Abhijit Menon-Sen’s Using Git to manage a web site. If you have any questions or suggestions about this feel free to reach out on twitter: @interstateone.