Deploying a git Repository with rsync and Tagging

Organizing the git Repository

Generally, I organize my digital projects according to this basic file structure:

File/DirectoryDescription
01_Docs/Documentation related to the project, if I’m not using the wiki services provided by a service such as GitHub or BitBucket.
02_Website/The “rendered” site. This is the directory structure that gets deployed to my web host.
03_WebSource/Any un-compiled source files (such as un-minified Javascript or CSS/LESS). The “rendered” files get pushed into the directory above.
99_Utility/Any utility scripts.
README.mdThe requisite README file explaining the project.

Any additional components would be organized within the numbered directory scheme (for example, if there was a related desktop or mobile app, it would fall somewhere between the 01_Docs/ folder and 99_Utility/. All this is to say that it gives me a single directory that will be used to deploy from.

Deploying a git Repository to Production

My go-to Bash script for deploying to production is (surprisingly enough) called deploy.sh, and it lives in the  99_Utility/ directory:

#!/bin/bash
DIR="$( dirname "${BASH_SOURCE[0]}" )" && pwd )/../02_Website/"
cd "$DIR"
TAGVERSION=$(date +Release-%Y.%m.%d-%Hh%Mm%Ss)
echo ""
echo "--> Tagging as $TAGVERSION and pushing to master repo..."
git tag $TAGVERSION
git push origin $TAGVERSION
echo ""
echo "--> Deploying to remote server using rsync..."
rsync -avzhe ssh --progress 
  --exclude cache/ --exclude templates_c/ 
  --delete . username@remotehost:directory

Let me step through each line of the script to explain what it does.

First, the cd command looks for where the script is located in my file system. This helps me avoid hard-coding a directory name, let’s me run it from any directory, and makes it portable to different environments (so if on one computer, the git repository is located in /opt/projects/projectname, but it’s under ~/projects/projectname on another computer, I don’t need to worry about it running correctly.

Next, I create a unique, human-readable tag name. Most projects involve version numbers in the tags. For me, tagging by release date/time works just fine… and let’s me automate it’s creation (removing the most error-prone variable from the equation… my own brain).

Why am I using tags this way? If something goes wrong, I can always see what the last deployment revision was, and easily undo the mistakes I’ve made… and it’s done automatically, so I can’t forget to do it. To grab a previous deployment, I simply run this command locally:

git fetch && git checkout tagname

After that, the two git commands create the tag based on the current codebase, and then pushes it to the remote master repository.

And now the fun part… rsync. This command tells the shell to synchronize my local files in the 02_Website/ folder to the remote host (obvs replace username, remotehost and the full directory path).

  • It will give you visual feedback as it works (–progress).
  • This sample project uses the Smarty PHP template engine, so there are two directories that exist for caching and pre-compiling of the templates, but I don’t want to sync them. The –exclude parameters handle that. You can have multiple –exclude parameters for multiple files/directories, or if there are a bunch of things you’d like to exclude use the –exclude-from parameter instead. See “Exclude multiple files and directories with rsync” for an excellent explanation of how to accomplish this. There are also special permissions on these two folders on my production host, so I don’t want to overwrite them, and foul things up.
  • The –delete parameter ensures that any files that are no longer of the site are removed from the remote server.

As an aside, I include the directories, but not the contents of my cache/ and templates_c/ folders. Since git won’t track an empty folder, the solution is to add a .gitignore file inside these directories with following contents:

*
!.gitignore

This forces git to record the directory, but not the files. This is a little trick I learned from a posting on StackOverflow.

That’s It.

And that’s all there is to deploying a git repository. It may not be the precise “proper” workflow, or the most efficient way, but it works for my needs and helps to lessen user error in the deployment process.

You may also like...

Leave a Reply

%d bloggers like this: