Unconventional git: migrating away from Conventional Commits

I used to be a big fan of Conventional Commits. However, I have recently found them to become a chore (pun intended). I have also come to realise that commits shouldn’t be used for changelogs, for that, I like to use Changesets.

Changesets for consumers, commit history for maintainers.

This is not to say that Conventional Commits aren’t good practice at keeping good git hygiene, but when you aren’t using them for generating changelogs, I find they really aren’t that useful. And personal projects should be fun; writing chore: after chore: starts to become a drag. Was that upgrade you just did really a chore? Or did you enjoy it?

And those prefixes really start to eat-in to the limited subject length. refactor: takes up 10 characters! That’s a fifth of the standard commit length.

So I have decided to stop using Conventional Commits, and am now just following the standard seven rules:

  1. Separate subject from body with a blank line
  2. Limit the subject line to 50 characters (this I do not strictly follow but I do try to keep them short)
  3. Capitalize the subject line
  4. Do not end the subject line with a fullstop
  5. Use the imperative mood in the subject line
  6. Wrap the body at 72 characters
  7. Use the body to explain what and why vs. how

Here’s how I migrated some of my projects away from Conventional Commits. Please note, due to this rewriting every commit in the history, I only recommend doing this on projects that do not have a lot of contributors.

First, install git-filter-repo:

brew install git-filter-repo

This can be used to change every commit. Here’s a command that will remove all Conventional prefixes, and capitalise the first character of the subject.

git filter-repo --commit-callback '
msg = commit.message.decode("utf-8")

def replacer(x):
      scope = ""

      if isinstance(x.group(2), str):
            scope = x.group(2) + ": "

      return scope + str(x.group(4)).upper() + str(x.group(5))

newmsg = re.sub(r\'^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(?:\(([\w\-\.]+)\))?(!)?: (.)(.*)\', replacer, msg)

if newmsg:
      commit.message = newmsg.encode("utf-8")
else:
      commit.message
' --force --dry-run

This doesn’t actually make the changes, it’s just a dry-run. To check you are happy with the changes, run:

git diff --no-index .git/filter-repo/fast-export.original .git/filter-repo/fast-export.filtered

Once you are sure you’d like to rewrite all changes, rerun the filter-repo command but drop the dry-run flag.

The tool will strip your origin settings, so add those back:

git remote add origin https://github.com/UESERNAME/REPO.git

This is your last chance to back out. If you really are happy, push everything back up to origin:

git push origin --force --all