{"post":{"slug":"how-to-write-a-good-commit-message-2026","title":"How to Write a Good Commit Message in 2026: a practical guide","excerpt":"A good commit message explains why a change was made, not just what changed. Here is a simple, durable format and the habits that make a git history actually useful months later.","category":"code","date":"June 16, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">A</span> good commit message explains why a change was made, in language a teammate or your future self can understand months later. The diff already shows what changed line by line, so your message should not just restate it. Use a short imperative subject line of about 50 characters, leave a blank line, then write a body that gives the reason and any context a reviewer needs. Keep each commit to one logical change. That is the whole discipline, and it pays off every time you read a log or hunt for a regression.\n\n## Why commit messages matter\n\nA commit message is documentation that lives next to the code forever. When a bug appears six months from now and you run `git blame` on the offending line, the message attached to that change is your first and sometimes only explanation. A message like `fix` tells you nothing; a message that says the change works around a race condition in a specific service saves you an hour of guessing.\n\nGood messages also make code review faster, make reverts safe, and make tools like `git bisect` actually work. Bisect finds the commit that introduced a bug by checking out points in history; that only helps if each commit is a single coherent change rather than a grab bag.\n\n## The format that works\n\nThe widely used convention is simple. Write a concise subject in the imperative mood, then a body separated by a blank line.\n\n```\nFix redirect loop on expired sessions\n\nThe session middleware refreshed the cookie after the auth check,\nso an expired session bounced between login and dashboard. Move the\nrefresh before the check and add a regression test.\n\nRefs: TICKET-482\n```\n\nWhy imperative mood? A commit completes the sentence \"If applied, this commit will ...\". So you write `Add retry logic`, not `Added` or `Adds`. It reads oddly at first and becomes second nature fast.\n\n## Subject and body rules\n\n| Rule | Guideline | Reason |\n|---|---|---|\n| Subject length | Around 50 characters, hard cap near 72 | Stays readable in logs and tools |\n| Subject mood | Imperative (Fix, Add, Remove) | Matches git own generated messages |\n| Subject case | Capitalize, no trailing period | Cleaner, consistent history |\n| Blank line | Always between subject and body | Tools treat line one as the title |\n| Body width | Wrap around 72 characters | Readable in terminals without scroll |\n| Body content | Explain why and any trade-offs | The diff already shows the what |\n\nMany teams add a lightweight prefix system called Conventional Commits, where messages start with a type such as `feat:`, `fix:`, or `docs:`. It is optional, but it enables automated changelogs and version bumps, so it is worth adopting on shared projects. If you are still building the muscle for clean changes, our guide on how to [debug code faster](/blog/how-to-debug-code-faster-2026) pairs well, because small commits make bugs easier to isolate.\n\n## How to write one, step by step\n\n1. **Stage one logical change.** Use `git add -p` to stage just the hunks that belong together. Resist bundling an unrelated cleanup into a feature commit.\n2. **Write the subject as a command.** Summarize the change in under 50 characters in the imperative.\n3. **Add a body if the why is not obvious.** Explain the motivation, the approach, and any trade-off you accepted. Skip the body only for truly trivial changes.\n4. **Reference context.** Link the ticket, issue, or discussion so the reasoning is one click away.\n5. **Re-read before committing.** A thirty-second proofread now beats confusion later.\n\n## Common mistakes\n\n- **Vague subjects.** `update`, `fix stuff`, and `wip` are noise. Say what and imply why.\n- **Giant commits.** A 40-file commit titled `refactor` cannot be reviewed or reverted cleanly. Split it.\n- **Restating the diff.** \"Changed line 14\" adds nothing the diff does not already show.\n- **Skipping the body when it matters.** If the reason is not obvious from the code, write it down.\n- **Inconsistent style across a team.** Agree on a convention once and let a linter or template enforce it.\n\n## FAQ\n\n**How long should a commit message be?**\nKeep the subject around 50 characters and under 72. The body can be as long as needed to explain the why, wrapped near 72 characters per line. Trivial changes can skip the body entirely.\n\n**Should I use Conventional Commits?**\nOn a shared or open-source project, yes, because it enables automated changelogs and semantic versioning. On a quick personal script, a plain clear message is enough.\n\n**Why imperative mood?**\nGit own automated messages use it, and a commit reads naturally as \"If applied, this commit will Add X\". Consistency with that convention keeps history uniform.\n\n**Can I rewrite a bad commit message?**\nYes. Use `git commit --amend` for the most recent commit, or an interactive rebase for older ones, but avoid rewriting history that others have already pulled.\n\n## Where to go next\n\n[Debug code faster with a tighter loop](/blog/how-to-debug-code-faster-2026), [learn how to review code effectively](/blog/how-to-review-code-2026), and [understand what a pull request is](/blog/what-is-a-pull-request-2026).","hue":205,"metaTitle":"How to Write a Good Commit Message in 2026","metaDescription":"Learn how to write a good commit message in 2026 with a clear imperative subject, a useful body that explains why, and habits for a readable git history.","keywords":["how to write a good commit message 2026","git commit message format","conventional commits","imperative mood commit","commit message best practices","git history readability","atomic commits","commit subject line length","writing commit messages","git workflow tips 2026"],"tldr":["**Write the why, not the what** — the diff already shows what changed, so the message should explain the reason and context.","**Use a short imperative subject** — around 50 characters, phrased like a command such as Fix login redirect loop.","**Separate subject and body with a blank line** — many git tools rely on this convention to display history cleanly.","**One logical change per commit** — small focused commits are easier to review, revert, and bisect later.","**Skip:** vague messages like fix stuff or update, which make a history useless when you need to track down a regression."],"readTime":"4 min read","wordCount":852},"related":[{"slug":"how-to-write-good-commit-messages-2026","title":"How to write good commit messages in 2026: the standard that sticks","excerpt":"A good commit message is a letter to the next engineer who has to understand why this code exists. This 2026 guide gives the rules and the template.","category":"code","date":"April 6, 2026","author":"ByteLedger Team","readTime":"6 min read","hue":312},{"slug":"git-workflow-best-practices-2026","title":"Git workflow best practices in 2026: keep history clean and shipping","excerpt":"A practical guide to Git workflows in 2026 - branching, commits, pull requests, and the habits that keep history readable and your team unblocked.","category":"code","date":"May 10, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":240},{"slug":"what-is-a-git-commit-2026","title":"What Is a Git Commit in 2026: snapshots explained","excerpt":"A Git commit is a saved snapshot of your project at one moment, paired with a message describing the change, that forms the permanent history you can return to or compare against.","category":"code","date":"June 17, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":210}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"how-to-work-from-home-effectively-2026","title":"How to work from home effectively in 2026: a practical system","excerpt":"Working from home well is mostly about structure, not motivation. Here is how to set up a space, a routine, and boundaries that keep you productive and sane.","category":"guides","date":"June 16, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":150},"older":{"slug":"how-to-write-emails-with-ai-2026","title":"How to Write Emails With AI in 2026: a practical workflow","excerpt":"A simple, repeatable way to write better emails with AI in 2026 without sounding robotic: what to paste in, how to prompt, and what to never automate.","category":"ai","date":"June 16, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":265}}