Theory
Theory: A Commit is Immutable; Messages are for Humans and Machines
Once written, a commit object is byte-for-byte fixed. --amend and rebase do not edit it; they write a new object and slide a name. That is why hashes change and why shared history is a social problem.
Invariants
- Commit hash = hash of (tree, parents, author, committer, message). Change any field → new hash.
- Author and committer can differ (rebase, cherry-pick).
- Conventional Commits are a convention, not a Git feature. Hooks and forges can enforce them.
- Unstaging moves a path from index toward
HEAD; it does not delete working-tree bytes.
amend
A ← B ← C main C has message "stuff"
A ← B ← C' main C' new object; C remains in reflog
Why messages matter
git log --grep '^fix' only works if subjects are structured. Changelog generators and feat!: breaking-change scanners parse the same text. The object store does not care; your future self and CI do.
What can break
- Amending a commit already on
origin/main. - Empty subject or
WIPon a branch you intended to merge. - Trailers with the wrong spelling (
Co-authored-byis magic for some forges).
How to read this chapter
Anatomy, Conventional Commits, amend, unstage, lab; then templates, split/empty, trailers/mailmap, git show.