---
title: 'Writing Commit Messages'
source: 'https://academia.sh/en/courses/introduction-to-version-control/writing-commit-messages'
course: 'Introduction to Version Control'
language: en
updated: '2026-08-17T18:10:47+00:00'
license: 'CC BY-SA 4.0'
---

# Writing Commit Messages

The message structure made up of the subject line, the blank separator, and the body; recording the rationale, and how tools make use of the message format.

Three commits have been written, and all three had a one-line message. This is enough
for small changes; but the reason for a fix, the options tried and abandoned, or the
grounds for a design decision do not fit on one line. This lesson defines the
message's structure.

The **commit message** is not a formality; it is the one free-text field that
determines whether history can be read. *What* a line does is read from the code;
*why* it was written that way is read only from the message.

## The Message's Structure

The message has three parts:

```
Subject line: a summary of the change

Body: the rationale for the change. What the problem was, why this
solution was chosen, and which options were ruled out are written here.

A second paragraph is added if needed.
```

What separates the parts is **the first blank line**, and this separator is a formal
rule: tools read the first line as the subject and everything after the blank line
as the body. If no blank line is inserted, the entire text counts as the subject and
gets squeezed onto a single line in summary listings.

How tools use this distinction can be seen directly. `%s` gives the subject line,
`%b` the body:

```bash
git log -1 --format='%s' 43370ca
```

```
Üç veri yapısı terimi ekle
```

```bash
git log -1 --format='%b' 43370ca
```

```
Ağaç, karma tablosu ve bağlı liste terimleri listede yoktu; bu terimler
sorulduğunda arama betiği boş çıktı veriyordu.

Karşılıklar Veri Yapıları kursunun sözlüğüyle aynı biçimde yazıldı.
```

## The Subject Line

Four rules are settled for the subject line:

1. **Written in the imperative mood.** "Sort the term list," not "Sorted the term
   list" or "I sorted the term list." The reason is formal: tool-generated messages
   are also imperative ("Revert "…"", "Merge …"), so history reads in one
   grammatical mood. Test: the subject line should complete "If applied, this
   commit will: …."
2. **Kept to around fifty characters.** There is no hard limit, but the line gets
   truncated in summary listings and narrow interfaces. A subject line over fifty
   characters is often a sign the commit holds more than one piece of work.
3. **Not ended with a period.** It is a title, not a sentence.
4. **States what changed, not how.** The detail is the body's job.

## The Body

The question the body answers is not "what was done" but **"why it was done."** The
change itself is already visible in the diff; what is not visible in the diff is the
situation that required that change.

A useful body includes:

- **The problem.** Which behavior was wrong, or which need went unmet?
- **The rationale.** Why was this path chosen?
- **Options ruled out.** An approach tried and abandoned, so the same path is not
  retried.
- **Known limits.** Situations the solution does not cover.

Lines are wrapped by hand at around seventy-two characters. The reason is that `git
log`'s output writes the message body with a four-space indent: to avoid overflow in
an eighty-column space, the body itself has to be narrower.

## Example

Three terms are added to the term list, and the message is written in an editor.
When `git commit` is run with no option, the configured text editor opens; once the
file is saved and closed, its content becomes the message. If it is left empty, no
commit is written.

```
Üç veri yapısı terimi ekle

Ağaç, karma tablosu ve bağlı liste terimleri listede yoktu; bu terimler
sorulduğunda arama betiği boş çıktı veriyordu.

Karşılıklar Veri Yapıları kursunun sözlüğüyle aynı biçimde yazıldı.
```

The subject line says what was done; the body records *why* the terms were
considered missing and where the equivalents came from. Both are pieces of
information that cannot be extracted from the code.

A second example belongs to a fix in the search script:

```
Aramayı büyük/küçük harften bağımsız yap

Terimler listede küçük harfle tutuluyor. Kullanıcı "Yığıt" yazdığında
arama boş dönüyor, terim listede olduğu hâlde bulunamıyordu.

grep çağrısına -i seçeneği eklendi; bu seçenek POSIX'te tanımlıdır ve
ek bağımlılık getirmez.
```

This message records more than the one-line diff itself: why the `-i` option was
added, and why another solution — uppercasing the list, say — was not chosen instead.

## What Not to Write

Some message patterns add nothing to history:

- **Subject lines that repeat the content.** "terimler.txt updated" — already
  visible in the diff. Write the work done, not the file name.
- **Status patterns.** "wip," "temporary," "fix." These do not say what the commit
  does and leave no searchable trace.
- **A bare external number, with no context.** A message with only a ticket number
  is empty for a reader without access to that system. A number goes in the body,
  with a one-sentence summary of the problem.
- **Subject lines that count more than one job.** The "and" in "Added X and fixed
  Y" is a sign the commit should be split.

The last item shows how the commit message ties back to the atomic-commit habit:
when a good subject line cannot be written, the problem is most often not in the
message but in the commit's scope.

## Ways to Give the Message

| Way | Use |
|---|---|
| `git commit` | Opens the editor; the usual way for a multi-line message |
| `git commit -m "subject"` | A one-line message |
| `git commit -m "subject" -m "body"` | Each `-m` becomes a paragraph, with a blank line inserted between them |
| `git commit -F file` | The message is read from a file |

The template that opens in the editor has lines starting with `#`; these are
excluded from the message and summarize the current state. Reading this summary
before writing is the cheapest way to notice the wrong files were staged.

## Result

```bash
git log --oneline
```

```
60e13bd Aramayı büyük/küçük harften bağımsız yap
43370ca Üç veri yapısı terimi ekle
3132c78 Biçim örneğindeki yazımı düzelt
546c174 Terim arama betiği ekle
13d31bf Terim listesini ve biçim belgesini ekle
```

Five lines describe the project's five steps in readable form. This readability
comes directly from two habits: every commit holding a single piece of work, and
every subject line summarizing that work in the imperative. Break either one, and
the list loses its value.

## A Message Is a Search Field

Messages are not just read, they are also searched. The subject and body text can be
filtered:

```bash
git log --oneline --grep="arama"
```

```
60e13bd Aramayı büyük/küçük harften bağımsız yap
43370ca Üç veri yapısı terimi ekle
546c174 Terim arama betiği ekle
```

The search is done letter for letter; word stems are not recognized. This detail
stands out in this repository's Turkish commit messages:

```bash
git log --oneline --grep="betik"
```

The command returns no lines, even though history holds the commit "Terim arama
betiği ekle" (Add term search script). The reason is Turkish consonant softening:
when a suffix attaches to "betik" (script), the final `k` softens to `ğ`, so
"betiği" never contains the substring "betik" at all. A shortened pattern does
return a result:

```bash
git log --oneline --grep="beti"
```

```
43370ca Üç veri yapısı terimi ekle
546c174 Terim arama betiği ekle
```

Because `--grep` matches substrings literally rather than recognizing word stems,
this kind of miss can arise in any language whose suffixes alter the stem; Turkish
consonant softening is the case this repository's history happens to show. It makes
choosing subject-line words that resist this kind of alteration a practical
necessity.

## Summary

- The message is made up of a subject line and a body; the first blank line
  separates the two, and tools rely on this separation.
- The subject line is written in the imperative mood, at around fifty characters,
  with no period.
- The body answers "why," not "what": the statement of the problem, the rationale
  for the solution, options ruled out, and known limits.
- Body lines are wrapped at around seventy-two characters; `git log`'s output
  writes the body indented.
- Messages can be searched with `--grep`; this turns writing subject lines
  consistently into a practical necessity.

## Next Step

History has reached five commits and was listed with `git log --oneline`. But
listing is only the simplest form of reading history: commits touching a specific
file, commits adding or removing specific text, and a specific time range can each
be queried separately. The next lesson takes up the tools for reading history.
