This commit notation allows developers to convey 2 critical pieces of metadata about each commit:
This information is conveyed in the first 3 characters of the commit summary line. That way a receiving developer can quickly scan the commit log in order to determine risk and intent for any incoming change set.
This is particularly useful when:
main
— just the pull request commit summaries to understand the history of changes for a release.Risk Level | Code | Example | Meaning |
---|---|---|---|
Known safe | lowercase letter | r - Extract method Applesauce |
Addresses all known and unknown risks. |
Validated | uppercase letter | R - Extract method Applesauce |
Addresses all known risks. |
Risky | uppercase followed by 2 bangs | R!! Extract method Applesauce |
Some known risks remain unverified. |
(Probably) Broken | uppercase followed by 2 stars | R** Start extracting method with no name |
No risk attestation. |
These developer intentions exist on every project. They are always allowed in commits that use this notation.
Each intention can appear at any of the 4 risk levels. Each intention's full details section includes the potential risks inherent in that kind of change, as well as common approaches to attain each risk level.
Prefix | Name | Intention |
---|---|---|
F | Feature | Change or extend one aspect of program behavior without altering others. |
B | Bugfix | Repair one existing, undesirable program behavior without altering any others. |
R | Refactoring | Change implementation without changing program behavior. |
D | Documentation | Change something which communicates to team members and does not impact program behavior. |
Known Risks
Code | Known Approaches |
---|---|
f - |
None known |
F - |
Meets all of:
|
F!! |
Change includes unit tests for new behavior. |
F** |
No automatic tests, or unfinished implementation. |
A bugfix is a lot like a feature. However, the intention is to change an undesired — and usually unintentional — behavior of the current system. The risk profile is similar but the intention is different, so there are often more operational risks.
Known Risks
Code | Known Approaches |
---|---|
b - |
None known |
B - |
Meets all of:
|
B!! |
Change includes unit tests for new behavior. |
B** |
No automatic tests, or unfinished implementation. |
A Refactoring or Remodeling intends to alter the program in some way without changing any behavior. The risk levels indicate the probability of the commit living up to that intention, based on how the code change was executed.
Known Risks
Code | Known Approaches |
---|---|
r - |
One of: |
R - |
Test-supported Procedural Refactoring3 |
R!! |
Identified single, named refactoring, but executed by editing code or without whole-project test coverage. |
R** |
Remodeled by editing code, even in small chunks. |
Changes that don't impact the code, but do change documentation around the code. Note that this does not include end-user documentation1.
Known Risks
Code | Known Approaches |
---|---|
d - |
Developer-visible documentation, not in a source file, or verified to generate byte-identical compilation. |
D - |
Dev-impacting only, but changes compilation or process. E.g., changing text on a dev-only screen, or changes code-review checklist. |
D!! |
Alters an important process. |
D** |
Trying out a process change that is intended to gain info, not to work. |
The basic intention annotations are comprehensive to describe any kind of change, but it may be useful to extend the notation to your project to provide additional detail that is useful in your context. Read more about Extension Intensions.
If you can get a series of commits that is all lowercase commits, you can deploy without the need for Regression Testing, or lengthy conversations about accepting the pull request to trunk.
A provable refactoring requires a burden of proof. The main methods of proof are
With discipline these can prove bug-for-bug compatibility. They demonstrate safety for unknown bugs, even guaranteeing that you do not accidentally fix a bug you don't know exists (but your customers may be depending on).
All of these recipes use static analysis to demonstrate safety. As such, they work equally well on code that lacks tests. They can be a good way to make code testable. Their downside is that they are language-specific.
These are refactorings with a lower standard of proof:
Note that this can not prove bug-for-bug compatibility. It can only demonstrate that you didn't cause any problems that have been thought of before; it does not demonstrate safety for novel bugs.
Requirement 3 is there because many refactorings can have non-local effects. It is not sufficient to have great tests on the code you are changing. You also need great tests on the code that you are not intending to change, to demonstrate that you didn't. Therefore, until your entire codebase is very highly tested, you will only be able to use the R
commit designation on new code that is uncalled by your product.
End user documentation is a feature, bugfix, or refactoring, depending on its nature. Use those codes (including levels of risk) accordingly.
Features and bug fixes intentionally change behavior. This makes them much riskier than refactorings. It is not possible to prove that they have only the intended effect. However, small changes are much lower risk for three reasons:
Therefore, we treat any feature or bug fix as high risk if it changes more than 8 lines of code in one commit. This includes test changes.
One good approach to enable small features is to refactor until the feature change is easy, then add it. Then add the feature one piece at a time, with a test for each.
We invite you to submit pull requests to help evolve this notation and methodology.