Steve Grunwell

Open-source contributor, speaker, and electronics tinkerer

Automatically Recompile Sass upon Deployment Using Git Hooks

As I wrote about the other day, my site’s styles are written using Sass, a Ruby-based CSS pre-compiler. When you’re the only one working on a site, compiling Sass files locally and committing the generated CSS isn’t the worst thing in the world. When you’re working in a team environment however, it’s necessary to consider that several developers of different experience levels may touch a site throughout its lifecycle. What would happen if a developer who had never used Sass needed to make an update to a site? How long would it be before someone starts complaining that the change they made to the CSS file was overwritten after the next compilation of the corresponding .scss file?

This technique has one goal: keep generated CSS files out of the git repository. In order to do this, we’ll need to make sure of a few things:

  1. Generated files are explicitly blocked from the repo (to prevent someone who doesn’t know any better from committing them)
  2. Automatically recompile our SASS files into CSS upon deployment (This assumes that you have Ruby, RubyGems, and Sass running on your target machine).

Keeping generated files out of the Git repository

This should be as simple as updating (or creating) your .gitignore file and explicitly excluding the generated files you want to block. If you want to be a real hard-ass, you could add *.css, but if you go this route be sure to let in any CSS files that aren’t generated by SASS (remember: adding a ! before a rule in the .gitignore file will allow that file to be tracked):

If you’re using a third-party tool/framework/library that has its own stylesheets (for instance: WordPress) you’ll need to explicitly allow those styles into the repo. For that reason I’d recommend blacklisting the generated files instead of whitelisting the non-generated.

Automatically recompile our Sass upon deployment

This is where the magic happens. Git has a nice little feature called “Git Hooks” which allow us to execute scripts at different points throughout the repository lifecycle. You can use git hooks to do things like validate commit message formatting, strip trailing whitespace, email someone whenever code is deployed, etc. In this case, we’ll be using the post-merge hook, found in .git/hooks/post-merge.

According to the manual, the post-merge hook fires when a git merge is invoked on a repository (generally speaking, git pull is the same as a git fetch followed by a git merge) and, in my experience, only when updates have actually been made since the last pull (i.e. if you receive the “Already up-to-date.” response after performing a git pull, your hook will not run). This means that by tying our SASS compilation into the post-merge hook we can be certain that our CSS files will be generated if and only if something has changed in the repository.

Since I wanted to explicitly declare which Sass files to compile and their resulting filenames and keep this script under version control, I chose to put my calls to the Sass gem in a bash file within my repository:

This is a rather rudimentary script (I don’t have much experience with bash scripting), so improvements (like error checking) are more than welcome, but this gets the job done. When I run a git pull on production, I get the regular merge-related messaging followed by:

Then in my git hook:

If I wanted to I could certainly have put my entire recompile_sass script into .git/hooks/post-merge but, as I mentioned before, I wanted it to be tracked under version control. It’s also worth noting that when the git hook executes it does so from the root of the git repository, so you’ll need to set paths to any scripts appropriately.

Extra Credit

If you combine this technique with my tip on using git checksums to invalidate browser caches you can ensure that not only are your generated CSS files automatically regenerated upon deployment but they are also re-downloaded by browsers when updates have been made.

Wrapping Up

For many teams generating and committing CSS files from SASS locally may be just fine, but I’m a big proponent of keeping generated files out of version control. With minimal configuration you can keep your repos clean, prevent unaware developers from unknowingly editing a generated file, and reap the benefits of CSS pre-processors.

How do you and your team handle generated CSS? Is there a better way to pull this off? Please let me know in the comments!

Additional References

Previous

An Introduction to Sass in Responsive Design

Next

Using WordPress Advanced Custom Fields Exports

3 Comments

  1. We use Capistrano tasks at Van Patten Media to handle this. It’s admittedly not the ideal way to handle it (your method is a bit smoother) but it’s imperative in our server environment that the compilation happens locally and not server-side.

    Our compilation task actually creates a temporary clone of the repo in question (so you know you’re getting the current revision, and not your working copy), then compiles it and scp’s it from that temporary directory.

    The full code for this is on Github, for any interested parties!

  2. Peter Sorensen

    Thanks! Exactly what I was looking for.

  3. Jackson Darlow

    I tried this, and I just get:
    “remote: hooks/post-receive: 21: sass: not found”

    I’ve made sure to add sass to ~/.bashrc for my user, and I can sass in CLI just fine as the user, but I still get that error when I push.

    Ubuntu 10.04.4 LTS

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Be excellent to each other.