Writing commit messages - ULJ-Yale/qunexsdk GitHub Wiki
[TOC]
Clear commit history and messages are key for enabling efficient code review and clear code history. They provide invaluable information on what and why was done. They record the relevant context "on paper", enable sharing the knowledge with the reviewer and document it for the rest of the team.
To support clear development history, writing commit messages has to be part of the following three rules of managing commits:
-
Make atomic commits
Each commit should encapsulate a single related change to the code base. In practice, (i) do not combine multiple unrelated code changes (e.g. a code fix and a new feature) into a single commit, (ii) join multiple code changes that are necessary to implement the same code fix or change in functionality in a single commit (e.g. a change in the function name in function definition, all calls of the function, and related in-line documentation). -
Write good commit messages
The commit message should communicate succintly what and why was done and provide the relevant context. The exact structure and content of the commit messages is described further below. -
Revise development history before sharing
During development process it is often difficult to maintain a development history that would tell a clear "story". E.g. after a commit, a typo is discovered or a method name change is requested. In those cases, to keep up with the first rule, it is advantageous to amend the latest commit or add code changes usinggit commit --ammend
, or to revise the development history usinggit rebase --interactive
to remove, reorder, edit, merge and split commits and generate a clear development progression. Do note that these steps should be done before sharing the code / pushing it to the joint repository.
Following the Conventional Commits specification, the commit message should have the following structure:
<type>[(<scope>)]: <description>
[optional body]
[optional footer(s)]
The commit message title is the part of the commit message that is visible in the git log
output. It has to clearly describe the changes introduced in the commit. It consists of three parts:
-
type
of commit
The commit type denotes what was the nature of the commit. Use one of the following commit types:-
feat
... commit adds a new feature -
fix
... commit provides a bug fix -
docs
... commit updates the documentation without changing the code -
style
... commit updates the code formatting without changing the code -
refactor
... commit refactors production code -
test
... commit adds test(s) without changing the production code -
chore
... commit updates versioning, configurations, setup tasks without changing the production code
-
-
scope
of commit
To provide additional context, thetype
of commit can be optionally followed by specification of the scope of the commit.scope
has to immediately followtype
and is provided in the parentheses. -
description
of commit
Thedescription
of the commit is separated fromtype
and optionalscope
using a colon (:
). It has to provide specific, succint information about the content of the commit. It should start with a lowercase, use an imperative tone and end without a period.
When writing commit message title, adhere to the following additional rules:
- The commit title should not exceed 72 characters in length.
- In cases when a commit introduces a breaking change, that has to be indicated by an exclamation point (
!
) immediately before the colon (:
).
Note that the commit message title clearly relates to semantic versioning. Specifically:
- a commit of type
fix
corresponds toPATCH
change in semantic versioning, - a commit of type
feature
corresponds toMINOR
change in semantic versioning, - a commit that introduces breaking change corresponds to
MAJOR
change in semantic versioning.
Commit that introduces a bug fix:
fix: remove race condition in parallel processing of bold images
Commit that introduces a new feature:
feat: add full file checking to validation of processing results
Commit that introduces a breaking change:
refactor!: change study folder structure to support EEG processing
The body of the commit message provides additional context and explanation relevant for the commit. Not all commits are complex enough to warrant additional explanation, so the body is optional, however, strongly encouraged.
The commit body has to be separated from the commit title with an empty line. It is free-form and it may consist of any number of empty line separated paragraphs. Each line of the body should not exceed 72 characters in length.
The message body should provide:
- context and motivation (why) for the change,
- a description of what the change does,
- a discussion of context, impact and alternatives.
The commit body explains what and why was done. It describes the motivation for the change. It provides further detail about what the change accomplishes. It explains how the change fits in the larger context and relates it to previous and/or future changes. It provides information that enables understanding the code at a future date.
When writing the commit message body, follow the following guidelines:
- use consistent terminology,
- be as transparent as possible,
- reread the code and detail what you did,
- provide as much context as you can,
- describe tradeofs and choices guiding implementation,
- use standard markup format (use of markdown is encouraged).
To provide additional information and references to other sources one or more footers may be provided. The footer(s) have to be separated from the body or title by a blank line. They must consist of a word token that is followed by either :<space>
or <space>#
separator, followed by a string value. With the exception of BREAKING CHANGE
, a footer's token must use -
in place of whitespace characters. A footer's value may contain spaces and newlines.
If included as a footer, breaking change must consist of uppercase BREAKING CHANGE
followed by a colon (:
), space and description, e.g., BREAKING CHANGE: sessionsfoldername parameter now has to be provided explicitly when running run_turnkey
The footer(s) can be used to provide information about the issue / bug report ID, the name of the person that reviewed the code, etc.
Note that the information provided in the linked sources (e.g. forum bug report) might not be available at a future date, so do not use footer references as a replacement for detailed commit message body.
Recording issue number of the Discourse forum bug report and reviewer:
Discourse-issue: 69
Reviewed-by: AA
In this example, a code fix was performed in the nitools
module. The commit message for the change to nitools
was:
fix: Replaced spaces with underscores in g_ExtractGLMVolumes saveoption
When calling commands through connector, spaces within parameter values
are not processed correctly. Also, by convention, individual parameter
/ option values (i.e. not lists or arbitrary strings) should not have
spaces. For this reason spaces in `by effect`, `by session`, and
`effect files` options for the saveoption parameter were replaced with
underscores in documentation.
In code itself the change was implemented by replacing underscores with
spaces (line 86), so that new parameter values with underscores are
converted to old expected values and used correctly in the rest of the
code that remains unchanged. In this way saveoption values can still be
used in without change when printing verbose reports (e.g. lines 179,
186). Additionally this also provides backward compatibility for any
code that passes the options with spaces instead of underscores.
Additional issues were identified and fixed in testing:
1/ If effects parameter was specified using an empty string (''), no
effects were extracted. The code now checks whether the effects
parameter is an empty string (line 102) so that the empty parameter
is used correctly when calling img_ExtractGLMEstimates and all effects
are exported.
2/ Code incorrectly checked for `by estimate` saveoption when it should
check for `by effect`, and the appropriate sorting was skipped
(line 156).
3/ A check for correct saveoption parameter was added. The function now
warns if an invalid option is used and exits (line 87).
trello-card: https://trello.com/c/oEGstAhK
When this commit was integrated into the main QuNex repository, the change was committed without repeating the full body of the commit. Instead the original commit title was used with added scope:
fix(nitools): Replaced spaces with underscores in g_ExtractGLMVolumes saveoption
Consult the following resources for further information and guidelines:
- https://www.conventionalcommits.org
- https://youtu.be/1NoNTqank_U
- https://dhwthompson.com/2019/my-favourite-git-commit
- https://www.freecodecamp.org/news/writing-good-commit-messages-a-practical-guide/
- https://www.freecodecamp.org/news/a-beginners-guide-to-git-how-to-write-a-good-commit-message/
- https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit
- https://chris.beams.io/posts/git-commit/
- https://medium.com/compass-true-north/writing-good-commit-messages-fc33af9d6321
- https://backlog.com/blog/git-commit-messages-bold-daring/
- https://blog.mocoso.co.uk/talks/2015/01/12/telling-stories-through-your-commits/
- https://medium.com/sitewards/git-tips-the-memoir-of-commit-messages-7d15ed2205ac
- https://medium.com/@andrewhowdencom/anatomy-of-a-good-commit-message-acd9c4490437
- https://deniseyu.io/2020/05/23/habits-of-high-performing-teams.html
- https://alistapart.com/article/the-art-of-the-commit/