Git: Commit Messages Guide
Complete guide to writing effective Git commit messages using conventional commits format for better collaboration and automation.
Table of Contents
Overview
Writing clear and consistent commit messages is essential for maintaining a clean Git history and enabling automated tooling. This guide covers two approaches:
Normal Git Commit Messages - Free-form, casual approach
Formatted Git Commit Messages - Structured conventional commits format
Reference Documentation
Normal Git Commit Messages
Normal commit messages are free-form and casual, with no specific structure or rules.
Example
Added product helper
Characteristics
Free-form and casual
No rules or structure
Typically short, not standardized
Harder to automate parsing or generate changelogs
Pros
Quick and easy for solo or small projects
No learning curve
Cons
Lacks consistency across commits
Doesn’t communicate purpose clearly (is it a fix, a feature, or a refactor?)
Hard to automate tooling (like changelogs or semantic versioning)
Formatted Git Commit Messages (Conventional Commits)
Conventional Commits is a specification that provides a standardized format for commit messages, making them easier to read, parse, and automate.
Commit Message Format Structure
The commit message consists of three parts:
Header (mandatory)
Body (optional)
Footer (optional)
Syntax
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
Rules
The header is mandatory and the scope is optional
Any line of the commit message cannot be longer than 100 characters
This allows the message to be easier to read on GitHub as well as in various git tools
Header Structure
The header has a special format that includes a type, an optional scope, and a subject:
<type>(<scope>): <subject>
Type
The type defines what kind of change is this. See Commit Types for complete list.
Scope
The scope is optional but helpful! It defines what part of the codebase the change affects.
Examples:
feat(cart): add discount coupon logic
fix(product): wrong price calculation
chore(deps): update composer packages
Subject
The subject is required and should follow these rules:
Use imperative mood (like giving a command): “add” not “added”
Keep it under 50-70 characters
Capitalize the first word
No period at the end
Good Example:
feat(checkout): add scan credit card button
Bad Example:
Added scan credit card button.
Body
The body is optional but great for providing context.
Use it to explain:
Why the change was made
How it solves a problem
Any additional context
Example:
This adds a modal popup to scan the user's credit card using the webcam.
We're using BlinkCard SDK and filling values via JS for UX improvement.
Commit Types
Common commit types and their purposes:
Type |
Description |
|---|---|
|
A new feature |
|
A bug fix |
|
Documentation only changes |
|
Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc) |
|
A code change that neither fixes a bug nor adds a feature |
|
A code change that improves performance |
|
Adding missing tests |
|
Changes to the build process or auxiliary tools and libraries, such as documentation generation |
Examples
Type 1: feat - A New Feature
feat(user-auth): implement two-factor authentication
Added support for two-factor authentication (2FA) in the login process. Users can now enable 2FA via their account settings.
- Integrated with Google Authenticator
- Requires users to enter a 6-digit code after entering their password
Closes #101
Type 2: fix - A Bug Fix
fix(cart): resolve issue with item quantity not updating correctly
Fixed a bug where the cart quantity did not update when the user modified the quantity through the cart page.
- Updated the cart item model to trigger re-calculation on quantity change
- Added unit tests for this behavior
Fixes #87
Type 3: docs - Documentation Only Changes
docs: update README with setup instructions for local environment
Added instructions for setting up the project on a local machine, including dependencies and configuration steps.
- Added section for Docker setup
- Updated prerequisites for running the project locally
Related to #112
Type 4: style - Code Formatting Changes
style(css): format spacing in main.scss
Reformatted the `main.scss` file to improve readability and consistency in indentation.
- Added consistent indentation (2 spaces)
- Removed unnecessary trailing spaces
No functional changes
Type 5: refactor - Code Refactoring
refactor(auth): simplify login flow and remove deprecated code
Refactored the login module to streamline the user authentication process. Removed old code that was no longer used in the flow.
- Replaced old login validation with newer, more secure method
- Removed legacy methods and imports
BREAKING CHANGE: Removed deprecated methods in `AuthService`
Type 6: perf - Performance Improvements
perf(query): optimize SQL query for fetching recent orders
Improved the performance of the SQL query used to fetch recent orders by indexing the `order_date` column and refactoring the WHERE clause.
- Reduced query execution time from 500ms to 100ms
- Added new index to `order_date` column
Related to performance review task #134
Type 7: test - Adding Tests
test(user-profile): add unit tests for profile update validation
Added unit tests to cover validation logic for the user profile update form.
- Added tests for required fields, email validation, and password strength
- Increased code coverage by 20%
Refs #108
Type 8: chore - Build Process and Tools
chore(deps): upgrade eslint to v7.0
Upgraded `eslint` to version 7.0 and updated associated configuration to meet the new rules.
- Fixed deprecated rule usage in eslint configuration
- Updated `.eslintrc.json` to match the latest recommended settings
BREAKING CHANGE: Projects using older eslint configs may fail linting
Writing Commit Messages
Step-by-Step Process
Stage your changes:
git add .
Start the commit:
git commitThe default editor will open (usually vim or nano)
Write your commit message following the conventional commits format
Save and close the editor
Quick Commit (One-Liner)
For simple commits, you can use the -m flag:
git commit -m "feat(checkout): add scan credit card button"
Multi-Line Commit Message
For detailed commits with body and footer:
git commit -m "feat(checkout): add scan credit card button" \
-m "This adds a modal popup to scan the user's credit card using the webcam." \
-m "We're using BlinkCard SDK and filling values via JS for UX improvement." \
-m "Closes #123"
Or simply use git commit without -m to open the editor and write a multi-line message.
Best Practices
Do’s
Use imperative mood in the subject line (“add” not “added”)
Keep the subject line under 70 characters
Capitalize the first word of the subject
Do not end the subject with a period
Use the body to explain “what” and “why” vs. “how”
Reference issues and pull requests when applicable
Use breaking change notation when appropriate
Don’ts
Don’t write vague commit messages like “fix bug” or “update code”
Don’t mix multiple concerns in a single commit
Don’t write commit messages longer than 100 characters per line
Don’t use past tense (“added feature”) use imperative (“add feature”)
Don’t skip the body when the commit needs explanation
Comparison: Normal vs Formatted Commits
Normal Commits Pros
Quick and easy for solo or small projects
No learning curve
Normal Commits Cons
Lacks consistency across commits
Doesn’t communicate purpose clearly
Hard to automate tooling (like changelogs or semantic versioning)
Formatted Commits Pros
Highly descriptive and consistent
Easier for team collaboration
Allows use of automated tools (e.g., auto-changelog, semantic versioning)
Makes reviewing Git history cleaner
Enables automated release notes generation
Formatted Commits Cons
Slight learning curve
Requires some discipline or tooling (like commit hooks or linters)
Automation Tools
Using conventional commits enables various automation tools:
Semantic Versioning - Automatically determine version bumps
Changelog Generation - Auto-generate changelogs from commits
Release Notes - Generate release notes automatically
Commit Hooks - Validate commit message format
CI/CD Integration - Trigger different workflows based on commit type
Example Tools
commitlint - Lint commit messages
semantic-release - Automated version management
standard-version - Generate changelogs
See Also
Git: First Time Configuration - First time Git configuration
Git: Stash Guide - Git stash guide
Git: Fix Line Ending Issues (CRLF/LF) - Fix Git line ending issues