My Git Hooks, Part 3 - Evolution and Special Casing

February 07, 2014

This is Part 3 of a series of posts on my git hooks. Part 1 described why I did this, and why it’s in Ruby. Part 2 described the basics of how it works.

Remember, my git hook project is available on GitHub

Evolution: Other Vendors and Projects

I first wrote these hooks when focused a Ruby On Rails app, with some JavaScript and CSS thrown in. That meant that

  1. A lot of RoR-isms crept in, and
  2. Some of the idiosyncrasies of this project/vendor crept in.

As I moved on to other consulting gigs and other companies, I found that the old rules weren’t cutting it, so I made a few changes.

Switch on File Type for Other languages - Markdown###

When I started working in Markdown a lot more often, I found that the H1 marker (a series of equals signs on the line below the H1 text) was getting picked up by my code that detected Git conflict markers. I didn’t want to rip out the multiple-equals-sign detection, so I left it in for most files, while disabling it for .md and .mmd files.

I still detect >>>> and <<<< in all file types, so I thought that losing ==== in .md files was acceptable.

Git Variables to Handle Other Companies / Architectures

My old employer’s build system required that the addition or removal of .css, .js, and some other file types in the assets directory be accompanied by a change to production.rb. Back in the day, I just built code into my pre-commit hook to require that. Once I moved on to another employer, this was a big burden. I decided to make that behavior customizable via a git environment variable.

Now, if the git hook detects that such a file was added in a checkin without a change to production.rb, it throws an error describing the problem, while telling the user how to avoid such an error in the future by setting a particular git variable. The error message even describes how to set that variable globally, so that it can be handled once and for all.

Here’s an example:

Error: git pre-commit hook found attempt to add foo.css without editing production.rb
This may be OK, or not, depending on your project requirements.

To permanently allow this for this repo, run
git config hooks.newassetsrequireproductionchange false
and try again.

To permanently allow this for *all* repos, run
git config --global hooks.newassetsrequireproductionchange false
and try again.

In the past, an unset variable would be treated in the most “generous” manner possible, so as to not cause erroneous errors. I soon realized that unless I was prompted, I would never set a value to be more stringent on repository initialization - I might as well not even have the variable, because I’d never bother to set it!

I recently changed the behavior to err on the side of caution, causing one-time errors in the interest of robustness.

Other Libraries

Detecting “New to You” Constructs - binding.pry

During a talk at the BostonRB Project Night, I saw a presentation demonstrating the use of binding.pry in source code for debugging. I immediately thought, “ooh, I’ll use that!”, immediately followed by “yeah, and then I’ll check that in, won’t I?” Before the talk was finished, I had added a check for that to the hook and pushed to Github. As I learn more and more interesting debugging techniques, I’ll preemptively prevent myself from checking them in.

Please, find your own and create issues or pull requests!

Handling Exceptions on a Per-Project-Type-Basis - console.log in Node (Pending)

When I was doing mostly RoR work with a little bit of JavaScript, I found myself leaving in console.log calls. Not only is that bad, form, but it’s a disaster on IE. So I added a call to detect that.

Unfortunately, calls to console.log are SOP in Node. Worse, since Node JS files just use the standard .js (or .coffee) extension, I can’t use the same trick that I did for Markdown.

I have an enhancement request in my repo to detect the project type (using logic similar to Heroku’s when it decides which buildpacks to run), and change behavior accordingly. In this case, I paln to turn off the console.log check in a Node-based repo.

The Best/Worst Part

You know what the best, and worst, part of this is? That I can’t submit the pre-commit hook, or, indeed, this file without triggering a ton of errors! :-)

Of course, doing so provides a great test of the hooks themselves. If the code won’t catch my use of ==== or binding.pry above, why did I even bother?


In the next post or two I’ll get into…

  • Distribution ideas and best practices, and
  • Setting up git to “guarantee” that this becomes part of your workflow.
Tags: git
comments powered by Disqus