Deploy Your Website From the Command Line With Git

Yesterday I posted about how I’m going to start shipping my projects (boy, I’ve really been posting a ton lately, huh?) and today I started the process. In doing so I’m finding that I have to keep setting up a deployment method over and over and keep having to glance over at a couple of browser tabs I have open to pages that I’ve saved about Git deployment. So instead of having to keep looking up those blogs I figured I’ll post my method (taken from a handful of other methods) here as a handy reference for myself and maybe others might find it useful too. So here’s how to use Git hooks to deploy your site (or app, as the cool kids are calling ‘em these days).

Setting up your repos and a little housekeeping

So before I get into the nitty gritty I’m going to talk about my strategy for version control in general and how I keep track of my repos for versioning, sharing, and deployment.

The Git repos

So often times I’ll have a project like Beautician that I host as a service and publicly on Github. For any project of mine that isn’t public (read: Github only) I host the repo in three places:

  • On my server (specifically, in my git folder)

  • On Github

  • And finally, back on my server (in the deployment folder)

Setting up the repositories on your server

I won’t go into how to setup your Github repos. Github have great docs and they walk you through that process. For the purposes of this “tutorial” I want to note that whenever my repo isn’t public-only my Github remote is named public and not origin like most repos on Github. (For any n00bs out there, it doesn’t matter what you name your remotes on Github or anywhere so long as you remember the name and you set the URI correctly).

On the server my private repoos are stored in my home folder in folder called git (I like my server’s home folder nice and organized like the rest of my server). So the first thing I do is set up my origin remote on the server like so:

1
2
3
4
5
6
7
ssh user@server.com
# I never enter a password because I have key based authentication set up and so should you
cd ~/git
mkdir new_repo.git
cd new_repo.git
git init --bare # Create a bare repository - the --bare flag is important here
pwd # if you're not totally comfortable with Linux server administration it'll help to print out the path to the repo. You'll need this in the next step

So to explain what I did: I logged into my server, changed into my git folder, create a folder to hold the repository, changed into the new folder/repository, and initialized it as a bare git repository. The pwd commands spits out the full path to the folder you’re in which you can then use to build the URI when you setup your remote on your local machine.

Back on your local machine you should cd into your project’s folder and initialize a Git repository if you haven’t already. Here’s how to set up your local copy to be linked up with your private server’s repo:

1
2
3
4
5
6
cd ~/Sites/my_project # Your path will be different, just open a terminal window and cd into your project
git init
git add .
git commit -m "Getting ready to push to my private remote"
git remote add origin ssh:user@server.com/path/to/repo.git # this is where the output of pwd comes in handy
git push origin master

That’s it! Now you have a private git repository on your own private server. In case I lost you, this is what we did. We opened a terminal window and changed directories into our project’s folder. We initialized the folder to keep track of changes with git (its now a full-fledged repo just like the one on the server is). We added and commited our files so Git has something to track and push. We then added the path to our repository on the server as a remote named origin. If you used pwd in the first step then you can add whatever it output directly after the user@server.com part of your remote command. Then we pushed the changes to the server. Simple stuff so far.

Setting up Git deployment

Now that we have our repos all set up its time to use some hooks to publish our sites with Git. Why would we want to do that? Because FTP is lame and so 90’s. Once you publish a site from the command line once you’ll be hooked and you’ll understand why its far superior to selectively uploading files with an FTP client. If you’ve never done this before its actually very simple. There’s a tiny bit of up-front work and after that you’ll be publishing sites with just a couple of keystrokes. Here we go…

Set up the deployment repo

I keep a third repository around for deployment. We could use our original private repository on the server to deploy our site but what if I’m pushing half baked or broken code just to get if off my computer as a backup? We don’t want our changes live if they’re not ready. (At this point I should note that we could actually use Git branches along with this technique so that we can deploy production code publicly and keep development code private in a single repo but mistakes happen and not everyone is proficient enough with Git to be able to swiftly rollback changes reliably if mistakes occur so this is mostly mistake-proof). Here’s how to set it up:

If you haven’t already, create the paths to your site on your server and setup your server software to recognize them (Apache users will have to setup a virtual host file).

1
2
3
4
5
6
ssh user@server.com
cd /srv/www/my_site.com/public_html # Your path may vary
mkdir production.git
cd production.git
git init --bare
cd hooks

In the hooks folder you’ll find some sample scripts. One of them may be called post-receive.sample. I run the latest version of Git on a server running Ubuntu 12.04 and in my case I don’t get the sample script. You could either edit the sample or create a new file. I’ll show you how to create a new file. Back to the example…

1
2
touch post-receive
nano post-receive

So by this point we’ve created a post-receive hook file and opened it up in a cute little Linux text editor we’re running from the command line called Nano. In this file you’ll want to add this code:

1
2
#!/bin/sh
GIT_WORK_TREE=/path/to/your/document/root git checkout -f master

Just two lines!!! That’s all it takes for a working post-receive hook. Now, there’s just a little more…

Press Control+X to save then Y then Enter to confirm and you’ll be taken back to your filesystem in the command line…

In order for the post-receive hook to run we need to make it executable so we run this command:

1
chmod +x post-receive

Note: If you get any kind of permissions error while executing any of these steps just put the word sudo in front of the commands. For example sudo chmod +x.

Now that the file is executable we need to do just one more thing on the server. Depending on where you host your files on the server, you might need elevated permissions to modify files. I host my files outside my user’s home folder in the /srv folder so I need to change the ownership and permissions on a few directories. You can check the permissions and ownership of files and folders by running ls -l. This will list out all the folders in your current directory, their owners, group, and permissions. Anyway, on to changing permissions (if applicable to you, do this. Otherwise feel free to skip):

1
2
3
4
cd ../../../ # This brings us up 3 folder levels so we can manipulate our document root
sudo chown your_username:your_usergroup public_html # Replace public_html with the name of your site's document root
sudo chmod 777 public_html
exit

Now we’re ready to go. We just set up a repo meant for deployment on our private server, created a Git hook for deployment, made sure the hook will run, and now we’re ready for the fun part. Back on your local machine run:

1
2
git remote add production ssh://user@server.com/path/to/deployment/repo.git
git push production master

And we’re done! Your files should push to the production repo just like any other remote and if you didn’t get any error messages then it most likely worked. Open your browser and check your site to make sure the changes took effect.

And that’s how you deploy a site using Git. And from now on instead of uploading files through FTP you’ll just be pushing to repos and avoiding the hassle. Enjoy!

Git, Servers and deployment, Web development

« I Ship, Therefore I Am Self Expression »

Comments