I'm obsessed with writing good commit messages, for a few reasons.

(1) Documentation is important, and comes in a few major forms: docs, code comments, commits, and tests. Docs and code comments are good for initial, high level understanding. Most "bad" documentation appears in the form of code comments and external docs, because they are most likely to drift out of date with the code. Tests do not have this problem (assuming they all pass) because they are in sync with the code, and provide a nice way to understand interfaces and implementations (the "what"). Similarly, commit messages, by their very nature, cannot drift out of date with the code, and provide an opportunity to document the "why". Therefore, commit messages are at least as important as tests, comments, and docs and should be treated with the same respect.

(2) Often the "why" of a particular implementation touches multiple files around the codebase; in many cases you want to document the "why" in comments, but that only helps when it applies to a single section of code. A commit message is an opportunity to document the "why" of an implementation that touches multiple parts of a codebase.

(3) Writing good commit messages forces you to keep the code contents of a commit tightly related to its message, lest the message be inaccurate.

(4) Because good commits are groups of closely related files, you can understand the subtle interactions of a codebase by looking at which files change in the same commit.

(5) A good commit log tells a story and can often provide reasoning behind what may seem like the madness of a legacy codebase. If you don't understand why a file does what it does, just search the history for all commits to that file and you will have a much better idea. There is a cool tool called Gource [0] which visualizes commits to a git repo in a way that can tell such a "story."

Some of the rules I follow:

(A) A short message with an imperative mood documents the "what". A longer body, in list form, documents the "why" and/or the "how." Always include the body unless its a tiny commit with an obvious why/how.

(B) A pull request should follow the same idea as commits, in that it documents the how/why. It should also document the "how" of using any new features it introduces. If possible, it should include screenshots/videos/links of the changes so QA engineers / managers can quickly read it for high level expectations of the next release. Other commenters in this thread have mentioned that pull requests are where the documenting should happen. But good pull requests are just as important as good commit messages; they are not mutually exclusive. A pull request is just a higher level commit.

(C) Before submitting a pull request, use `git rebase -i` against the development/master branch to squash, reorder and fixup commits. For example, sometimes one commit is "solve problem A using method X," but you change your mind in a subsequent commit "actually, solve problem A using method Y". In that case, the two commits should be squashed together if they are in the same pull request. In general, do not be afraid to aggressively reorder and regroup commits in a pull request, if it improves clarity of the pull request as a whole. For this, I like to use a tool called rebase-editor [1] that makes interactive rebasing easy and satisfying.

[0] https://gource.io/

[1] https://github.com/sjurba/rebase-editor