Deploying a Website with Git in 4 Steps

Git is incredibly handy for moving work around to different machines, so a reasonable thing to consider is actually deploying a website to your server. I’ve done this in a few different ways, but this is a simple recipe to accomplishing the task. In these steps, I assume you’ve already SSH’d into the server and you know where your web root is.

  1. On the server, outside of the web root:
    mkdir myRepo.git
    cd myRepo.git
    git init --bare
  2. On the local machine:
    git remote add myServer myUsername@ServerHostname:~/path/to/myRepo.git
    git push myServer master

    The name for your remote can be whatever you want, but the server hostname needs to be what you use to SSH into your server. The way we’re setting this up, unless you have SSH certificates already installed, this process will ask you for your password every time you attempt to push something up to the server.

  3. Back on the server, in the web root, at the location you want the website to be deployed:
    git clone ~/path/to/myRepo.git .
  4. And then, to make the live repository auto-update, you need to modify the hooks/post-receive file in the bare repository. You may need to rename it from post-receive.sample, but this is what it should contain:
    cd /absolute/path/to/myLiveDir
    env -i git pull --ff-only origin master
    env -i git submodule sync
    env -i git submodule update --recursive

    The reason for those last two commands is so your submodules, if you have any, will remain in sync and checked out on the deployed repository. You might also need to change the permissions on this file, if they’re not already correct:

    chmod 755 post-receive

And you’re set. All you need to do to push new commits to being live on your server is:

git push myServer master

For those interested, what’s happening here is that you’re pushing to a repository on your server. It’s a bare repository, so it only contains the git object version of your files. This repository, however, upon receipt of new commits, will push them to a regular repository in the web root. The reason to have essentially a proxy repository is because, without overriding some protective settings, git disallows updating a non-bare remote repository:

Refusing to update checked out branch: refs/heads/master. By default, updating the current branch in a non-bare repository is denied, because it will make the index and work tree inconsistent with what you pushed, and will require ‘git reset –hard’ to match the work tree to HEAD.

So, setting up this proxy allows you to keep this setting intact. Further, because we told git to only allow fast-forward updates, we have to resolve any potential merge conflicts before the live repository will accept any changes. It’s pretty simple to stay ahead of this, just don’t make any commits directly to the live repository and always reconcile with the bare repository before attempting to push.

Related to this and the topic of a planned post, you can use a similar strategy to version and synchronize a database schema. It’s definitely a more complicated, and somewhat riskier process, but one that deserves some attention soon.