Certain tasks like updating dependencies or migrating a database must be done after pulling code or checking out a branch. Other tasks such as re-indexing our ctags improve our development experience. Both kinds of tasks are easy to forget to do and are therefore error-prone. To address the problem, we’ve recently added a standard, extensible set of git hooks to our dotfiles in order to automate necessary, but annoying tasks.

Git has a commonly under-utilized feature: hooks. You can think of a hook as an event that gets triggered before and after various stages of revision control process. Some hooks of note are:

prepare-commit-msg - Fires before the commit message prompt.

- Fires before the commit message prompt. pre-commit - Fires before a git commit .

- Fires before a . post-commit - Fires after a git commit .

- Fires after a . post-checkout - Fires after changing branches.

- Fires after changing branches. post-merge - Fires after merging branches.

- Fires after merging branches. pre-push - Fires before code is pushed to a remote.

Our dotfiles’ convention for extension is to place our custom hooks in {pre,post}-$EVENT files within our ~/.git_template.local/hooks directory. Now, anything we add to those hook files will be automatically executed, running tasks that we normally would forget.

I forget to re-index my ctags !

Lucky for you, we’ve set up git to re-index your ctags after each git command.

I always forget to run bundle install after switching branches!

Automatically install new gems:

# ~/.git_template.local/hooks/post-checkout # use `hookup` gem if it's installed if command -v hookup > /dev/null ; then hookup post-checkout " $@ " else # otherwise, do it yourself [ -f Gemfile ] && bundle install > /dev/null & fi

I never remember to run pending migrations!

Automatically run your migrations:

# ~/.git_template.local/hooks/post-checkout # use `hookup` gem if it's installed if command -v hookup > /dev/null ; then hookup post-checkout " $@ " else # otherwise, do it yourself [ -f db/schema.rb ] && bin/rake db:migrate > /dev/null & fi

I document my API with fdoc, but I forget to generate the pages!

Automatically generate the HTML docs:

# ~/.git_template.local/hooks/post-checkout bin/fdoc convert ./spec/fixtures --output = ./html > /dev/null &

I really like Go’s commitment to a standard code format, but I constantly forget to format my files!

Run go fmt before you commit:

# ~/.git_template.local/hooks/pre-commit gofiles = $( git diff --cached --name-only --diff-filter = ACM | grep '.go$' ) [ -z " $gofiles " ] && exit 0 function checkfmt () { unformatted = $( gofmt -l $gofiles ) [ -z " $unformatted " ] && return 0 echo > &2 "Go files must be formatted with gofmt. Please run:" for fn in $unformatted ; do echo > &2 " gofmt -w $PWD / $fn " done return 1 } checkfmt || fail = yes [ -z " $fail " ] || exit 1 exit 0

I want my extensive network of friends to know when I’m merging code!

Send out a Yo every time you merge a branch:

# ~/.git_template.local/hooks/post-merge curl --data "api_token= $YO_API_TOKEN " https://api.justyo.co/yoall/ > /dev/null &

When we aggressively simplify and automate the tedious parts of the development process, we can focus on what’s important: getting things done.

If you found this useful, you might also enjoy: