Inside Out

Notes on seeking wisdom and crafting software

Semantic commits for git

Table of contents

As a developer, we spend everyday in a plethora of development activities. While the processes (agile, scrum etc.) ensure all of them add business value, I think only a few enrich the product meaningfully. Imagine if we could measure our activities; understand the activities that help with engineering and those that add direct value (bug fix or a feature). Knowing the gaps can make us efficient.

In this post, we will discuss semantic commits as a way to measure our activities.

Let’s start with a few examples of semantic commits and derive a definition.

Semantic commits - definition

The karma test runner defines commit messages in the following schema. type is project independent attribute, whereas scope is dependent on the project and it’s constituent components. This schema helps in generating a readable (noise-free) summary of interesting changes, and with release notes or changelogs.

<type>(<scope>): message

<body>

<footer>
---

type: feat, fix, docs, style, refactor, test, chore
scope: init, runner, watcher etc.

Such annotations can help derive a sense of effort from git logs. For example, given below is a year worth of git commits in karma (master branch).

> cd /tmp/karma
> git log --pretty=oneline --no-merges --since 2017/01/01 --until 2017/12/31 | cut -d " " -f 2 |\
cut -d "(" -f 1 | cut -d ":" -f 1 | sort -r | uniq -c | sort -nr -k1
     39 chore
     28 fix
     23 feat
     15 docs
      6 test
      2 Try
      1 refactor

Using the scope annotation we could further slice and dice this data into questions like which component has most number of bug fixes?.

A slight variation of this approach is recommended by angularjs developers. It doesn’t provide a chore annotation, instead it suggests build and ci. There’s a perf annotation as well.

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
---

type: feat, fix, docs, style, refactor, test, perf, build, ci
scope: animations, common, compiler etc.

Conventional commits takes meaning to next level drawing a relationship with semver. The format is minimal with several optional annotations.

<type>[optional scope]: <description>

[optional body]

[optional footer]
---

type: `fix` corresponds to `PATCH` of semver
type: `feat` corresponds to `MINOR` of semver

body or footer with `BREAKING CHANGE` corresponds to `MAJOR` of semver

Let’s quickly recap the essence of semantic commits.

Why semantic commits?

Semantic commits add meaning to each commit message through annotations. They are primarily used for:

  1. Keeping a changelog of all commits. More at keep a changelog.
  2. Human readable project history
  3. Ease of release and auditing ([semantic] commits -> [semantic] version)
  4. Measuring and classification of effort

These guidelines enable consumers make literate decisions about using a particular app or library. We started this discussion with (4) as the primary motivation and saw an example from karma repository. If we could account for fixes versus chores, and features versus tests; could it help infer a thing or two about productivity as a developer?

May be. I’ve just recently started following this religiously. We will come back to review the question in a few weeks time.

Coming back, how do we enable semantic commits in a developer workflow?

Enabling semantic commits

There are two simple ways to achieve this. Please choose the one that suits you. And do let me know if there’s another better way!

1. Using git commands

Install a few git commands for the specific commit types. Use them with git like git chore "add build scripts for travis..

Follow the instructions at https://github.com/fteem/git-semantic-commits.

2. Using git aliases

Use git aliases feature to provide alias for semantic commits. Add the following to ~/.gitconfig:

# Contents of ~/.gitconfig
# A complete example is at https://github.com/codito/configs/blob/master/.gitconfig
[alias]
    cdo = "!f() { git commit -m \"docs: $1\"; }; f"
    cfe = "!f() { git commit -m \"feat: $1\"; }; f"
    cfi = "!f() { git commit -m \"fix: $1\"; }; f"
    cho = "!f() { git commit -m \"chore: $1\"; }; f"
    clo = "!f() { git commit -m \"localize: $1\"; }; f"
    cre = "!f() { git commit -m \"refactor: $1\"; }; f"
    cst = "!f() { git commit -m \"style: $1\"; }; f"
    cte = "!f() { git commit -m \"test: $1\"; }; f"

Use it like git cho "add build scripts for travis.".

Read more about awesomeness of aliases at git wiki. Have patience and read through the Collection of git aliases section. That’s going to enlighten you if this is your first encounter with aliases ;)

There’s a slightly different approach to alias-based-semantic-commits at http://adrianwong.fun/semantic-commit-messages/.

Bonus

If emojis are your thing, delight yourself with a few of these.

And while we’re talking about git, commits and functionality; be sure to checkout the git extras. We’ll probably do a summary walkthru of extras here in future.

That’s 851 words for today. Namaste and wish you fantastic 2018!