This post explains how to write good git commit messages and how NOT to write bad git commit messages. Also, you will learn some more best practices related to committing your code changes to Git.
TLDR;
- Use the imperative mood in the subject line
- Capitalize the first letter in the subject line and do not end the subject line with a period
- Limit the subject line to 50 characters
- Separate subject from body with a blank line and wrap at 72 chars
- Use git hooks to link to the task ticket
- Make atomic commits
- Commit often
Use the imperative mood in the subject line ( break at ~50 characters in commit subject )
Imperative mood means "written as if you are giving a command or an instruction"
Example: Close the window, Clean your plate, etc
Start the subject line with a capital letter and do not use a period at the end of the commit message.
A properly formed Git commit subject line should always be able to complete the following sentence:
If applied, this commit will
For example:
- If applied, this commit will Remove deprecated packages
- If applied, this commit will Update core/cloud documentation
- If applied, this commit will Release version 3.1.0
Write descriptive commit messages ( wrap at 72 characters in commit body )
The commit messages should say the context of what is changed. One word commit messages does not say anything. If you cannot convey what you want to say in a ~50 characters subject, the changes probably should not be in a single commit.
If you have to explain why the change is done and want to write the limitations in detail, write in the commit body. The body should be wrapped at 72 characters.
Ideal descriptive commit message with subject and body looks like this:
Change authorization method in frontend from cookies to tokens
The change in API was causing the failure of login to
frontend. So, login will not work anymore if we use
cookie for auth. Now the auth tokens are used with the
API request for the login.
If it is not necessary to write the body of the commit message in your case, make sure to write a clear and descriptive subject line.
Use the git hooks
In the project repository, in .git/hooks you will find the sample files to set up git hooks. Rename the commit-msg.sample file to commit-msg.
If your branch name is PROJECT-1245-feature-xyz, with the below commit-msg hook, every commit message will have the ticket ID in the prefix.
NOTE: In serious projects, it is always a best practice to name the branch starting with the ticket ID.
Example commit messages with the hook:
- PROJECT-1245: Remove deprecated packages
- PROJECT-1245: Release version 1.0
content of the hook commit-msg:
if [ -z "$BRANCHES_TO_SKIP" ]; then
BRANCHES_TO_SKIP=(main)
fi
BRANCH_NAME=$(git symbolic-ref --short HEAD)
BRANCH_NAME="${BRANCH_NAME##*/}"
BRANCH_ID="$(cut -d'-' -f2 <<<"$BRANCH_NAME")"
BRANCH_EXCLUDED=$(printf "%s\n" "${BRANCHES_TO_SKIP[@]}" | grep -c "^$BRANCH_NAME$")
BRANCH_IN_COMMIT=$(grep -c "\[$BRANCH_NAME\]" $1)
if [ -n "$BRANCH_NAME" ] && ! [[ $BRANCH_EXCLUDED -eq 1 ]] && ! [[ $BRANCH_IN_COMMIT -ge 1 ]]; then
sed -i.bak -e "1s/^/PROJECT-$BRANCH_ID: /" $1
fi
This might be useful because if you see any commit in the future, you can easily trace it back to the ticket and get more information on why it is done. However, this should not be an excuse to write short commit messages.
Commit often
Whenever you have something that works and does not break anything for anyone else, do a commit. If you make a LOT of changes and commit once, it might be harder to track what went wrong and where.
TIP: If you have a Pull Request ( PR ) pipeline set up, you can raise a draft PR. PR pipeline is run for every commit you make, and you exactly know what commit broke the pipeline.
Atomic commits
The atomic commit is a small commit that can't be broken up any further.
Three main features of atomic commits:
- single irreducible unit
- everything still works
- clear and concise
Advantages:
- spending a LOT less time in solving merge conflicts.
- can review the code commit by commit.
- reading commits will tell a story about what is done.
- If your local git gets corrupted, uncommitted changes are not lost
Bad vs Good commit messages
bad | what's wrong | good |
---|---|---|
update | short, does not say anything | Update getting started documentation |
renamed variables | non-imperative mood | Rename variable cloud_host to cloudHost in API calls |
bug fix | Does not say what bug | Fix bug of not changing to in-use status when some user is streaming |
More changes | says nothing | Refactor service ABC for better readability |
typo | says nothing | Fix a typo in the error message of service ABC's save function |
Fix a bug in frontend and refactor database-fetch file and add unit test | long and non-atomic | Commit 1: Fix a bug in frontend button disable issue Commit 2: Refactor database-fetch file for better readability Commit 3: Add unit test for testing enable_connection |