Opinion: VCS Commits

February 2022 · 4 minute read


I have some strongly-held beliefs about commit messages in VCS. For obvious reasons, I tend to use git - but I believe that the core ideas extend to any VCS and are not specific to git.

That being said, I can’t say that I always follow this guide - like any other human, I am prone to mistakes, and some things don’t warrant such care.

Bad examples of commit messages, ahead of time, for transparency:

I know that there are more bad examples, but first let me share what I think looks good.

Commit Message Style

For commit style, I like to follow a similar style to the Linux Kernel guidelines; not strictly, but close to it. My preference looks like the following:

feature or affected pkgs: one-line general description, 80 chars max

Details about what you did and why, rationale behind the changes. If the line
would flow past 80 chars, newline and continue.

If there are multiple things addressed in a single commit, separate with
paragraphs to explain them individually.

refs, fixes or closes [reference to ticket]

A real-world example of this in the go repo:

go/types, types2: fix string to type parameter conversions

Converting an untyped constant to a type parameter results
in a non-constant value; but the constant must still be
representable by all specific types of the type parameter.

Adjust the special handling for constant-to-type parameter
conversions to also include string-to-[]byte and []rune
conversions, which are handled separately for conversions
to types that are not type parameters because those are not
constant conversions in non-generic code.

Fixes #51386.

Rebase Guidelines

Git history is important is pretty important to me. I want to know, at a glance, what was worked on and the general description.

If I use git log or jump into more detailed history (tig), for nontrivial commits, I should see some rationale or details that should give me enough info to understand the problem.

There are several real-world examples of what I disagree with, but I don’t want to call anyone out - and I imagine that you’ve seen things similar to the following:

Something to note here, however, is that some level of this is acceptable during development. Commit early, commit often. That being said, cleanup is a constant process - you don’t clean up your home once a month, clean up messes as you go.

Once this makes it to the master branch, it’s frozen - unless you rewrite history, which I strongly discourage and would frown at.

How to Rebase effectively

Git rebase is very simple to take advantage of and offers a lot of ways to make commit history grokable. This should be done prior to merging into the master branch.

A workflow could look something like this:

To fix this up, we’ll use git rebase, specifically in interactive mode, which is super easy to deal with.

Subsequently, getting a good history:

$ git rebase -i HEAD~6
$ < editor opens >

You’ll see something like the following:


Here, we want to:

Using the nice commands, we use:


We choose:

The resulting history is cleaner in branch ex/rebase than in master.

Another really nice thing about rebase is the ability to re-order commits. In this example, if we had added a commit later to add a new file:


We can now choose to move this add 4 file commit to the relevant section and merge it into the previous commits:


We moved 4fd1aab above the tests so that it’s grouped with others and chose to merge it with those - preventing a “random” example: commit later on ex/rebaseorder.

This isn’t always necessary, mind you. Let’s imagine for a moment that this is a significant commit and we don’t want to merge it with the other examples. In this case, simply reordering it is fine as in ex/rebaseorder2.


Leaving it there would be acceptable.