Skip to content

Instantly share code, notes, and snippets.

@bobgilmore
Last active November 20, 2022 08:57
Show Gist options
  • Save bobgilmore/5424641 to your computer and use it in GitHub Desktop.
Save bobgilmore/5424641 to your computer and use it in GitHub Desktop.
Git Pre-Commit Presentation

What's a Git Hook?

  • A hook that's run before (or after) parts of Git commit, push, etc.
  • Can reject or modify commits.
  • "But I don't use the command line for Git, I use an app."
    • Doesn't matter - your app just uses them anyway!

Many Git-Hooks to Customize Git

  • Client-side
    • pre-commit
    • prepare-commit-msg, ...
  • Server-side
    • pre-receive, ...

How to Make a Git-Hook?

  • Create shell scripts in your_repo/.git/hooks
  • Git will launch them at the right time
  • It's code. So keep it under git control!
    • (Yes, keeping git hooks in git made my head hurt, too. Work through it, you’ll thank me!)

Shell Script? Seriously?

This is BostonRB, not BostonBourne!

How about a shell script that invokes Ruby?

Creating a Ruby-based Git Hook

  • Invoke Ruby at a shell script's hashbang
  • Run your code
  • puts the reasons (if any) for failure
  • exit 1 to fail, otherwise pass

Example Shell Script Pre-Commit

My pre-commit file

My pre-commit Looks For...

  • "Bad content" in lines I'm changing
  • Ensuring relationships between files
    • If adding one of x, make sure that y is touched
  • Bad Syntax (almost, I'll get back to that)

What Makes Content "Bad?"

  • For me, that’s code that I probably don't want to check in.
  • Again: not really bad, just code that I probably don't want to check in.
  • Pre-commit is an easily-overridable, local check
  • Doesn’t have to be exact
    • The whole point is to save me time and embarrassment.

Woah, that Seems Imprecise!

  • That's OK, it's super-easy to override.
    • Do everything in your app, then
    • If app fails to commit, git commit -m "My Message" --no-verify
    • Resume in your app.

Things I Check for

Merge Conflict Markers

  • We all eventually check in git merge conflicts.
  • So why not look for strings like
    • <<<<<<<<< or
    • >>>>>>>>> or
    • =========
  • If this was server-side, I'd be pedantic about line endings, etc. But it's not.

Debugger/Logger Calls

  • console.debug, console.log
  • binding.pry, binding.remote-pry

TextExpander-Generated Debugging Markers

  • I never type in logger lines "by hand," I use TextExpander macros for that.
    • boblogd expands into:
    • Rails.logger.debug "\n\nTMP_DEBUG <insertion_point>\n\n"
    • Thanks for making that generic, Jonathan!
  • So, my pre-commit searches for TMP_DEBUG

Private Key Giveaways

  • PRIVATE_KEY
  • ssh-rsa
  • God No!

Other Things I Probably Don’t Want to Commit

  • alert
    • Sometimes I do mean to commit a call to alert.
    • But for me this catches more mistakes than it flags "valid" calls. So, awesome!

Slightly More Advanced

If One File is Added, Make Sure Another Changes

  • "Main" work project requires changes to production.rb when a JavaScript or CSS asset is added.
  • Ensure that if .js, .coffee, .css, .scss, etc. is added, that production.rb is committed.
  • Again, not foolproof, but who cares?

Toolchain Integration

Hint: Easy-Peasy

(Mostly) Usable in Tools

  • Tools that use git (GitBox, Github, etc.) call client-side hooks "for free."
  • Unfortunate idiosyncrasies. Example:
    • If a commit from GitBox fails because of a pre-commit hook, the commit message is deleted from the prompt :-(
    • So, I'm in the habit of Command-A, Command-C before I commit.

A Bad Flaw When Using Tools

  • Mac OS X Apps don't know rbenv (or rvm) from Adam.
  • So, which version of Ruby does you favorite App run?
  • Yeah. So...
    • Ruby version used to run the shell script?
    • Ruby grammar used to validate files?
  • There's probably some .plist-based solution.

Git for Git

Keep Your Hooks Under Git Control

  • Keep a separate "master" repo for your git hooks.
  • symlink them into your working repos.
  • See the setup.sh file
  • Keep your symlinking script in the git hook repo, too.
  • Oww, my head!

By the Way...

  • There is no way that you can use these git hook on the git-hooks repo.
  • Think about it. Every violation will appear in that file!

Per-Repo Customization

  • Some repo's (like my main work repo) have weird requirements.
  • Q: How do I reconcile that with the "one master copy" philosophy?
  • A: Define constants in per-project /git/config files.
  • See the git config doc, then look at my script to see it in use.

Questions?

Contact Me:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment