skip to content

questions

4

How should a Git commit message be structured, and what is the 50/72 convention?

level: juniorimportance: must knowfreq 66%

answer

  1. three parts, one of them empty
  2. the empty part is what Git parses
  3. two numbers, one for each of two parts
  4. the log indents, so leave room
  5. write it as a command, not a report

basics

~20 s

A Git commit message is a short subject line, a blank line, then an optional body. The convention keeps the subject under about 50 characters and wraps body lines at 72. The blank line is the part Git itself depends on.

solid answer

~50 s

Write one summary line, leave a **blank line**, then the body. That blank line is not cosmetic: Git treats everything before the first blank line as the subject, which is what `git log --oneline`, `git shortlog` and `git format-patch` use — the last as an email subject. Omit it and your entire first paragraph becomes the subject. The 50/72 habit is convention, not enforcement: about 50 characters keeps one-line log output readable in a terminal, and wrapping the body at 72 leaves room for the four-space indent `git log` adds, staying inside 80 columns. Write the subject in the imperative mood — "Fix null check in parser", not "Fixed" — matching Git's own generated messages. The body is where the *why* goes: the problem, the reason for this approach, and consequences a reader six months from now cannot reconstruct from the diff.

code

text · 9 lines
text
Fix off-by-one in retry backoff

The backoff loop ran attempts+1 times because the counter was
checked after the increment, so a 3-attempt policy issued 4
requests and doubled load during the incident on the payments
service.

Chose a pre-check over resetting the counter to keep the loop
readable; behaviour for attempts=0 is unchanged.

go deeper

for a junior

Recall the shape: a short summary line, a blank line, then an optional body, with the summary written as a command. Know that the blank line is what Git actually parses.

for a middle

Explain which Git output consumes the subject — log --oneline, shortlog, format-patch, %s and %b — and where the 50 and 72 numbers come from, including the four-space indent git log adds.

for a senior

Argue from experience: describe reading history during a bisect or an incident and what a good body gave you that the diff could not, then name how you would make it a team habit.

for a principal

Decide what history is for in your organisation and what that costs to sustain — which knowledge lives in commit messages versus tickets and design docs, and how you avoid duplicating one in the other.

## The shape ``` Short summary in the imperative, about 50 chars A body paragraph explaining why the change was needed, what the previous behaviour was, and anything a future reader could not work out from the diff. Wrapped at 72 columns. More paragraphs as needed. ``` Three parts: subject, blank line, body. Only the blank line has mechanical meaning to Git. ## Why the blank line is load-bearing Git's notion of a "subject" is purely positional: everything up to the first blank line. That definition feeds a lot of output. `git log --oneline` prints the subject. `%s` in a pretty format is the subject and `%b` the body. `git shortlog` groups subjects by author. `git format-patch` puts the subject in the `Subject:` header of the generated email and the body below it. If you write four lines with no blank line, all of those treat the whole block as one long subject and your `--oneline` view becomes unreadable. ## Why 50 and why 72 Neither number is enforced by Git; no built-in check rejects a long line. They are ergonomics. **50 for the subject**: `git log --oneline` prefixes an abbreviated SHA, and graph views and terminal columns eat more. Around 50 characters keeps the summary intact rather than wrapped or elided in a narrow view. The number also forces a useful discipline: if you cannot summarise the change in 50 characters, the commit may be doing more than one thing. **72 for the body**: Git does not wrap message text when displaying it, and `git log` indents the message by four spaces. 72 + 4 = 76, comfortably inside an 80-column terminal. Long unwrapped lines look fine in your editor and terrible in the log. ## Imperative mood "Add retry to the client", not "Added" or "Adds". Two reasons. It matches what Git generates itself — `Merge branch 'topic'`, `Revert "Add retry to the client"` — so history reads consistently. And it reads naturally as a description of what applying the commit does: *if applied, this commit will* add retry to the client. It is a convention, so the real value is uniformity across a repository rather than grammar for its own sake. ## What belongs in the body The diff already states what changed, line by line, and it is authoritative. What the diff cannot record is everything around the change: what was broken and how it showed up, why this approach was chosen over an obvious alternative, what was deliberately left out, which behaviour changes for callers, and any ticket or incident the change belongs to. That is what makes a body worth reading during a bisect or a blame six months later, when the author has forgotten and possibly left. A short mechanical change may need no body at all. A subtle one-line fix often needs a long one. ## Mechanics worth knowing - `git commit` without `-m` opens your editor; `git commit -v` additionally puts the staged diff below the message so you can review while writing. - Lines beginning with the comment character (`#` by default, configurable via `core.commentChar`) are stripped from the final message. That is how the template comments Git shows you disappear. - `--cleanup=<mode>` controls that stripping: `strip`, `whitespace`, `verbatim` and `scissors` behave differently about comments and trailing whitespace. - Repeated `-m` arguments create separate paragraphs, so `git commit -m "Subject" -m "Body"` produces a correct subject/body split from the command line. ## Why interviewers ask This is a culture probe more than a trivia question. Anyone can memorise "50/72". What the interviewer is listening for is whether you have ever *read* history under pressure — during an incident, a bisect, or a blame on unfamiliar code — and therefore write for that reader. A candidate who says "the body explains why, because the diff already says what, and I have needed that during a bisect" has clearly been on the receiving end.

  • What breaks if you omit the blank line between subject and body?
    Git defines the subject as everything before the first blank line, so without one the whole opening paragraph becomes the subject. `git log --oneline` prints an unreadable wall of text, `git shortlog` groups by that long string, and `git format-patch` puts it all in the email `Subject:` header. Nothing errors — the output just becomes useless.
  • Why the imperative mood rather than past tense?
    It matches the messages Git generates itself, such as `Merge branch 'topic'` and `Revert "..."`, so history reads in one consistent voice. It also reads as what applying the commit does: *if applied, this commit will* fix the parser. The concrete benefit is uniformity across a repository; consistency is worth more than the specific choice.
  • Does Git enforce the 50 and 72 limits?
    No. Git stores the message verbatim and no built-in check rejects long lines. Teams that want enforcement add a `commit-msg` hook or a lint step. The limits exist so `git log --oneline` stays readable and so the body, which `git log` indents by four spaces, still fits an 80-column terminal.

saying these in an interview costs you the question

  • Thinks Git enforces the 50 and 72 limits
  • Omits the blank line between subject and body
  • Writes bodies that restate the diff line by line
  • Says the message does not matter because the diff is there
  • Treats -m one-liners as sufficient for every commit

context

open as a page

In a Conventional Commits message, what do the type, scope, and trailing ! mean?

level: middleimportance: should knowfreq 50%

basics

~20 s

Conventional Commits shapes the subject as type(scope)!: description. The type classifies the change, the optional scope names the affected area, and a ! before the colon marks a breaking change. It makes commit history machine-readable for versioning and changelogs.

open as a page

What are Git commit trailers, and how do Signed-off-by and Co-authored-by get added?

level: middleimportance: should knowfreq 38%

basics

~20 s

Trailers are Token: value lines in the last paragraph of a commit message, giving it machine-readable metadata. git commit -s adds a Signed-off-by line from your committer identity, and git interpret-trailers or git commit --trailer adds arbitrary ones such as Co-authored-by.

open as a page

What does Git's commit.template setting do, and how far can it enforce a convention?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

commit.template names a file whose contents pre-fill the editor when you run git commit. It is a prompt, not a check: the author can delete every line, -m skips it entirely, and the setting lives in local config that a clone does not carry.

open as a page