Developer friendly commits - 07/05/2024
A brief guide into how your organization can use conventional commit messages to create developer friendly Git logs.
Friendly commits with conventional commits messages 💨
For some time now I have been using conventional commits at work to try to keep our repositories form turning into complete and utter chaos. For some background information. Paraphrasing from the website; A Conventional Commit is a specification layer for adding human and machine readable meaning to commit messages. It’s often used in combination with automation systems to generate clear and consistent changelogs for software systems.
As per the website documentation itself:
The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of.
My team and I use a version that’s been adjusted for our own needs, but AFAIK still within the Conventional Commit specification. Our version of the conventional commits consists of the following structure.
The default structure:
# Example structure
<conventional type>: <ticket number> <commit message>
# Actual implementation example
feature: RAND-7634 enabled configurable environment via .env
The commit type should be pre-defined in your process. initially we used the default version on the conventional commits website. After some experimentation we decided it was better to adjust the types to suite our team better. This is the set of prefixes in our team.
feature:
bugfix:
hotfix:
chore:
tests:
refactor:
release:
This works great for us, we can directly see what a commit is trying to do and which ticket it’s linked to. At its core this is a great idea and should work flawlessly for improving your commit history and repository structure without being too intrusive.
In reality however, people being people, will always find a way to bypass, break or change this structure. I can’t tell you that this will also work for you, but I can show you how we do it in our team and show you what worked for us.
Taking a look at a sample Git History
Now that I’ve talked about the methods we’re using, lets take a look what that looks like in reality.
NOTE:
Ticket numbers and private information have been replace with random input, but are still relative to what we actually have in our Git log
.
First of all lets take a look into what the situation was before we implemented conventional commits. These are all actual commit messages, nothing needed to be hidden, or removed for security reasons because they contained no information AT ALL.
me dumb
fix
fix for app crashing...
released new version
updated azure pipelines
updated azure pipelines
updated azure pipelines
updated readme
Side note:
me dumb
resonates with me so much and it is probably my favorite commit messages that I’ve seen in a codebase. Purely because its something I think most developers have done and experienced before and committed to a codebase out of pure frustration.
Moving on to a few weeks later, we managed to introduce conventional commits in the team. Things drastically improved when we implemented conventional commits and managed to actual adhere to the standard. I made a selection of the better commit messages as an example, note that at that time we had no system in place for verifications of these messages so it was the wild west where some would adhere to the standard and others wouldn’t.
feature: RAND-9784 ability to load save file by drag and drop
bugfix: RAND-1202 file association not created on install
chore: RAND-1232 removed commented code
bugfix: RAND-3231 broken install
bugfix: RAND-1233 unbreak help page
feature: RAND-1234 converted to markdown
release: new version
It’s also important to note that while the structure improved the commit messages did not. But we did have something in place to at least get enough information regarding this commit, namely, a ticket number and the type of the ticket.
Now hopefully if you’re on the path to standardizing commits you also have a ticket system in place and following some sort of process to be able to described what you’re trying to make and track changes. If you don’t things might get ugly later down the line when the project gets complex.
Including conventional in your pull-request
For making changes we use pull-requests in my team. This is a great moment to enforce certain aspects of your process since the whole point behind a code review is to review a unit of work.
The following bit can also be moved a step earlier to your development stage, by using a commit linter, Git pre-commit hooks etc. At the time we felt that wasn’t necessary for us.
We enforce conventional commits by using pull-request templates in Azure DevOps. Pull request templates lets us create a markdown contribution document where contributors have to click through some steps to make sure the pull-request is according to expectations. This sounds like a lot but its a one time creation of the template and it automatically gets added to your ull-requests. Walking through the checklist is as easy as it’s just checking items off so we can have some sense of accountability when merging a unit of work.
Example Pull Request Template
# Description
Thank you for your contribution to the {{project_name}} repo.
Before submitting this pull request make sure you've read and checked off the checklist.
âš¡Pull-request Checklist
- [ ] Does your commit message adhere to the <type>:<ticket> <description> structure?
- [ ] Is your commit message descriptive and clearly show the commit purpose?
- [ ] All build pipelines are passing successfully
- [ ] All tests are passing successfully
If this is a frontend change, please attach a screenshot of the changes.
## Commits
Each developer making a contribution has to checkoff the list or else the pull-request won’t be handled or someone will leave a comment for them the check through the list.
Getting great history using limited merge types
Now that we have the commits under control, we can look at how to have them also appear correctly for your main/development branches. This is very subjective and highly dependant on your own Git strategies, so beware of that fact.
We personally use a variation of the Github Flow branching strategy. Only instead of Merging branches directly into master, in our case we merge back to develop, and when we think we have a set of changes we want to release. We merge those changes into master. Master in our case only contains releases and is always stable.
This strategy is highly effective (for us) and may not be suitable for other teams. To ensure we can stick to the process, we also have some policies in places in Azure DevOps for limiting certain merge types for our pull-request.
Since we branch from develop into a <type>
-branch name. When we create a pull request for that feature-branch. We only allow rebased commits to be merged into the develop branch. And once a release has to be made, its first created from develop containing the relevant commits and merged to master by squashing the needed commits. This leaves us with a very straight forward history.
What does the history look like now?
An example of our git log --online
output using conventional commits.
feature: RAND-1 created smart-combo-box as shared component
feature: RAND-2 vehicles can now be linked to customers
feature: RAND-3 created smart-options-box as shared component
feature: RAND-4 added tasktype enum for tasks
feature: RAND-5 added new logo to header and foorter
feature: RAND-6 added momentjs utilities using angular pipes
feature: RAND-8 vehicles can now be updated
So now I’ve showed you how we use conventional commits to get better insights into our Git history. Honestly conventional commits help us really get a clear view into what we are doing, creating change logs and when things go wrong it makes reverting to previous commits immensely helpful.
All of this is made possible by 3 simple steps:
- Have a system in place for clear commit messages (Conventional Commits)
- Enforce good commit messages using pull-requests or other tooling
- Enforce clear merging and commit messages by limiting merge types on pull-requests or process
Some of these steps are still done manually, so we can certainly improve them with automated actions such as commit linters, git hooks and Azure build pipelines. So there are still improvements to be made in our process, but this is a terrific start.
So at this point you would also have an idea on how to create a process and a set of rules to be able to adhere to good commit messages. This will take some time to get used to, but once you do, its smooth sailing. Next steps for example can be adding automated tooling on top of your commit messages to be able to automatically generate amazing change logs for your project.
Helpful tooling
Helpful links for some of the tooling and items mentioned in this post.