Automate your commit messages
Tags: git, workflow
Published: 2019-09-16 07:28:54

---
title: Automate your commit messages
published: false
tags: git,workflow
canonical_url: https://thomashartmann.dev/blog/automate-your-commit-messages
cover_image: https://thomashartmann.dev/images/automate-commit-msg.svg
published: true
---
<div><p>Git has a lot of inbuilt functionality that you might not use all the time, but which is oh-so-handy when you need it. One such thing is <em>hooks</em>. These can be used to do stuff like formatting your code before committing or running tests before pushing to the remote. Today, though, let’s look at how we can use it to automatically fill in part of your commit messsage.</p>
<h2 id="how-did-this-come-up">How did this come up?</h2>
<p>The team I’m on at work uses a system for commit messages and branch names where they should both start with the issue id of whatever task we’re working on. Using GitLab, they end up looking something like <code>#2 Adds sorting functionality to UI</code> (<em>we can argue about commit message tenses later</em>) and <code>#42/new-sorting-algorithm</code>, respectively.</p>
<p>If you’re like me, your mind should be poking you right about now, saying that that’s a lot of duplication; surely we don’t need all of that? Well, you could argue that with feature branches scoped to issues and no fast-forward merges, the branch name should be enough, but it doesn’t really show up in condensed commit logs etc., so it’s nice to have the issue number available for when you need it.</p>
<p>But not to worry; we can make the computer fill it in for us!</p>
<h2 id="picking-the-right-hook">Picking the right hook</h2>
<p>Git has quite a few hooks available; if you check the <code>.git/hooks</code> directory of a tracked project, you should find a bunch of files named <code>&lt;hook name&gt;.sample</code>. Most of the hook names are fairly descriptive, but you could always <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">look them up</a> if you want to know more.</p>
<p>In our case we’re interested in hooking into the system right before the commit message buffer appears on our screen, so we’re going to go with the <code>prepare-commit-msg</code> hook.</p>
<h2 id="auto-filling-the-message">Auto-filling the message</h2>
<p>Now, my team has a template we use for commits, which starts with <code>#[task number]</code>. Using this knowledge, we can do some fancy shell magic and replace it with the task from the branch name.</p>
<p>The whole script looks like this:</p>
```sh
#!/bin/sh

TASK_NO=$(git rev-parse --abbrev-ref HEAD | cut -d '/' -f 1)
# BSD sed (macOS)
sed -i'' -e "s/#\[task number\]/$TASK_NO/" "$1"

# GNU sed (Linux)
# sed -i -e "s/#\[task number\]/$TASK_NO/" "$1"
```
<div>
<p>Depending on whether you use BSD sed (macOS) or GNU sed (Linux), the <code>sed</code> command will behave slightly differently. For GNU sed, use the commented out line instead of the first one.</p>
<p>There is a slight difference in how you make the two versions of the programs write files in place.</p>
</div>
<p>The <code>git rev-parse --abbrev-ref HEAD</code> command gives you the name of the current branch, which we then split at the first <code>/</code> character using <code>cut</code>.</p>
<p>The next (and last) step is a simple <code>sed</code> replacement, replacing the <code>#[task number]</code> string with the branch’s task number.</p>
<p>The <code>$1</code> variable at the very end of the last line is the name of the commit message file and is something the script receives automatically. We use this to tell <code>sed</code> what file to replace the text in.</p>
<p>And for the curious, these are all the variables you get access to in the <code>pre-commit-msg</code> hook (taken from the <code>pre-commit-msg.sample</code> file):</p>
```sh

COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
```

<h2 id="caveats">Caveats</h2>
<p>There is a pretty significant exception to when this script does what you want it to: when you’re still on the master branch, where commit messages will start with the text <code>master</code>. I considered adding a special case for this, but then realized that it’s actually quite helpful in that it helps me remember when I should branch off, so I decided to keep it for now.</p>
<p>Another drawback is that because the commit message appears different from what git expects to find on disk (presumably), it will assume you put an actual message in and complete the commit. At least that’s what I found when using Vim. A simple workaround is deleting everything in the buffer (<code>dae</code> if you use the awesome <a href="https://github.com/kana/vim-textobj-entire">text-obj-entire</a> plugin) before exiting. Most of the time, though, I use <a href="https://magit.vc/">Magit</a> with Emacs, where canceling the commit works as expected.</p>
<h2 id="alternate-approach">Alternate approach</h2>
<p>While I have opted for modifying the commit message before it’s shown to the user, you could potentially also have the machine add the id automatically in the <code>pre-commit</code> hook.</p>
<p>You would make the system check the message for a pattern and amend the commit with the expected issue id if it’s not present.</p>
<p>This solution doesn’t give you any way to verify whether it’s correct or not, though, so you’d probably want some sort of way to bypass it.</p></div>