Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/bkuhlmann/git-lint
A command line interface for linting Git commits.
https://github.com/bkuhlmann/git-lint
Last synced: 2 days ago
JSON representation
A command line interface for linting Git commits.
- Host: GitHub
- URL: https://github.com/bkuhlmann/git-lint
- Owner: bkuhlmann
- License: other
- Created: 2020-06-13T18:43:57.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2024-04-23T12:55:33.000Z (7 months ago)
- Last Synced: 2024-05-01T23:13:55.547Z (6 months ago)
- Language: Ruby
- Homepage: https://alchemists.io/projects/git-lint
- Size: 868 KB
- Stars: 48
- Watchers: 3
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.adoc
- Funding: .github/FUNDING.yml
- License: LICENSE.adoc
- Citation: CITATION.cff
Awesome Lists containing this project
README
:toc: macro
:toclevels: 5
:figure-caption!::ascii_doc_link: link:https://docs.asciidoctor.org/asciidoc/latest[ASCII Doc]
:git_rebase_workflow_link: link:https://alchemists.io/articles/git_rebase[Git Rebase Workflow]
:markdown_link: link:https://daringfireball.net/projects/markdown[Markdown]= Git Lint
Git Lint is a command line interface for linting Git commits by ensuring you maintain a clean, easy
to read, debuggable, and maintainable project history. Having a consistent commit history leads to
improved code reviews and is a perfect companion to tools like
link:https://alchemists.io/projects/milestoner[Milestoner] for versioning and producing
automated release notes of your deploys.toc::[]
== Features
* Enforces a {git_rebase_workflow_link}.
* Enforces a clean and consistent Git commit history.
* Supports Git default branch configuration.
* Provides a customizable suite of analyzers.
* Provides Git Hook support for local use.
* Provides Continuous Integration (CI) support.== Requirements
. link:https://git-scm.com[Git]
. link:https://www.ruby-lang.org[Ruby]== Setup
To install _with_ security, run:
[source,bash]
----
# 💡 Skip this line if you already have the public certificate installed.
gem cert --add <(curl --compressed --location https://alchemists.io/gems.pem)
gem install git-lint --trust-policy HighSecurity
----To install _without_ security, run:
[source,bash]
----
gem install git-lint
----== Usage
=== Command Line Interface (CLI)
From the command line, type: `git-lint --help`
image:https://alchemists.io/images/projects/git-lint/screenshots/usage.png[Usage,width=588,height=353,role=focal_point]
To check if your Git commit history is clean, run: `git-lint analyze --branch`. It will exit with a failure if at least one issue with error severity is detected.
This gem does not check commits on your default branch (i.e. `main`). This is intentional as you
would, generally, not want to rewrite or fix commits on the `main` branch. This gem is best used on
feature branches as it automatically detects all commits made since creation of the feature branch.Here is an example workflow, using gem defaults with issues detected:
[source,bash]
----
cd example
git checkout -b test
touch text.txt
git add --all .
git commit --message "This is a bogus commit message that is also terribly long and will word wrap"
git-lint analyze --branch
----Output:
....
Running Git Lint...83dbad531d84a184e55cbb38c5b2a4e5fa5bcaee (Brooke Kuhlmann, 0 seconds ago): This is a bogus commit message that is also terribly long and will word wrap.
Commit Body Presence Warning. Use minimum of 1 line (non-empty).
Commit Subject Length Error. Use 72 characters or less.
Commit Subject Prefix Error. Use: /Fixed/, /Added/, /Updated/, /Removed/, /Refactored/.
Commit Subject Suffix Error. Avoid: /\./, /\?/, /\!/.1 commit inspected. 4 issues detected (1 warning, 3 errors).
....=== Configuration
This gem can be configured via a global configuration:
....
$HOME/.config/git-lint/configuration.yml
....It can also be configured via link:https://alchemists.io/projects/xdg[XDG] environment
variables. The default configuration is:[source,yaml]
----
commits:
author:
capitalization:
enabled: true
severity: error
email:
enabled: true
severity: error
name:
enabled: true
severity: error
minimum: 2
body:
bullet_capitalization:
enabled: true
severity: error
includes:
- "\\-"
- "\\*"
bullet_delimiter:
enabled: true
severity: error
includes:
- "\\-"
- "\\*"
bullet_only:
enabled: true
severity: error
includes:
- "\\-"
- "\\*"
leading_line:
enabled: true
severity: warn
line_length:
enabled: false
severity: error
maximum: 72
paragraph_capitalization:
enabled: true
severity: error
phrase:
enabled: true
severity: error
excludes:
- "absolutely"
- "actually"
- "all intents and purposes"
- "along the lines"
- "at this moment in time"
- "basically"
- "blacklist"
- "each and every one"
- "everyone knows"
- "fact of the matter"
- "furthermore"
- "however"
- "in due course"
- "in the end"
- "last but not least"
- "matter of fact"
- "obviously"
- "of course"
- "really"
- "simply"
- "things being equal"
- "whitelist"
- "would like to"
- "\\beasy\\b"
- "\\bjust\\b"
- "\\bquite\\b"
- "as\\sfar\\sas\\s.+\\sconcerned"
- "of\\sthe\\s(fact|opinion)\\sthat"
presence:
enabled: true
severity: warn
minimum: 1
tracker_shorthand:
enabled: true
severity: error
excludes:
- "(f|F)ix(es|ed)?\\s\\#\\d+"
- "(c|C)lose(s|d)?\\s\\#\\d+"
- "(r|R)esolve(s|d)?\\s\\#\\d+"
word_repeat:
enabled: true
severity: error
signature:
enabled: false
severity: error
includes:
- Good
subject:
length:
enabled: true
severity: error
maximum: 72
prefix:
enabled: true
severity: error
delimiter: " "
includes:
- Fixed
- Added
- Updated
- Removed
- Refactored
suffix:
enabled: true
severity: error
excludes:
- "\\."
- "\\?"
- "\\!"
word_repeat:
enabled: true
severity: error
trailer:
collaborator_capitalization:
enabled: true
severity: error
collaborator_email:
enabled: true
severity: error
collaborator_key:
enabled: true
severity: error
collaborator_name:
enabled: true
severity: error
minimum: 2
duplicate:
enabled: true
severity: error
format_key:
enabled: true
severity: error
format_value:
enabled: true
severity: error
includes:
- asciidoc
- markdown
issue_key:
enabled: true
severity: error
issue_value:
enabled: true
severity: error
includes:
- "[\\w-]+"
milestone_key:
enabled: true
severity: error
milestone_value:
enabled: true
severity: error
includes:
- major
- minor
- patch
order:
enabled: true
severity: error
reviewer_key:
enabled: true
severity: error
reviewer_value:
enabled: true
severity: error
includes:
- clickup
- github
- jira
- linear
- shortcut
- tana
signer_capitalization:
enabled: true
severity: error
signer_email:
enabled: true
severity: error
signer_key:
enabled: true
severity: error
signer_name:
enabled: true
severity: error
minimum: 2
tracker_key:
enabled: true
severity: error
tracker_value:
enabled: true
severity: error
includes:
- "[\\w\\-\\s]+"
----==== Enablement
By default, most analyzers are enabled. Accepted values are `true` or `false`. If you wish to
disable a analyzer, set it to `false`.==== Severity
By default, most analyzers are set to `error` severity. If you wish to reduce the severity level of
a analyzer, you can set it to `warn` instead. Here are the accepted values and what each means:* `warn`: Will count as an issue and display a warning but will not cause the program/build to
fail. Use this if you want to display issues as reminders or cautionary warnings.
* `error`: Will count as an issue, display error output, and cause the program/build to fail. Use
this setting if you want to ensure bad commits are prevented.==== Regular Expressions
Some analyzers support _include_ or _exclude_ lists. These lists can consist of strings, regular
expressions, or a combination thereof. Regardless of your choice, all lists are automatically
converted to regular expression for use by the analyzers. This means a string like `"example"`
becomes `/example/` and a regular expression of `"\\AExample.+"` becomes `/\AExample.+/`.If you need help constructing complex regular expressions for these lists, try launching an IRB
session and using `Regexp.new` or `Regexp.escape` to experiment with the types of words/phrases you
want to turn into regular expressions. _For purposes of the YAML configuration, these need to be
expressed as strings with special characters escaped properly for internal conversion to a regular
expression._=== Analyzers
The following details the various analyzers provided by this gem to ensure a high standard of
commits for your project.==== Commit Author Capitalization
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | none
|===Ensures author name is properly capitalized. Example:
....
# Disallowed
jayne cobb
dr. simon tam# Allowed
Jayne Cobb
Dr. Simon Tam
....==== Commit Author Email
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | none
|===Ensures author email address exists. Git requires an author email when you use it for the first time
too. This takes it a step further to ensure the email address loosely resembles an email address.....
# Disallowed
mudder_man# Allowed
[email protected]
....==== Commit Author Name
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | minimum: 2
|===Ensures author name consists of, at least, a first and last name. Example:
....
# Disallowed
Kaylee# Allowed
Kaywinnet Lee Frye
....==== Commit Body Bullet Capitalization
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: `["\\*", "\\-"]`
|===Ensures commit body bullet lines are capitalized. Example:
....
# Disallowed
- an example bullet.# Allowed
* An ASCII Doc bullet.
* link:https://demo.com[Demo]
* link:https://demo.com[demo]
- A Markdown bullet.
- [Demo](https://demo.com)
- [demo](https://demo.com)
....In general, using {ascii_doc_link} or {markdown_link} syntax directly after a bullet will cause capitalization checks to be ignored because there can be valid reasons for wanting to avoid capitalization in those situations.
==== Commit Body Bullet Delimiter
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: `["\\*", "\\-"]`
|===Ensures commit body bullets are delimited by a space. Example:
....
# Disallowed
-An example bullet.# Allowed
- An example bullet.
....==== Commit Body Bullet Only
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: `["\\*", "\\-"]`
|===Ensures a single bullet is never used when a paragraph could be used instead. Example:
....
# Disallowed- Pellentque morbi-trist sentus et netus et malesuada fames ac turpis egestas. Vestibulum tortor
quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu_libero sit amet quam.# Allowed
Pellentque morbi-trist sentus et netus et malesuada fames ac turpis egestas. Vestibulum tortor
quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu_libero sit amet quam.
....==== Commit Body Leading Line
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | none
|===Ensures there is a leading, empty line, between the commit subject and body. Generally, this isn't
an issue but sometimes the Git CLI can be misused or a misconfigured Git editor will smash the
subject line and start of the body as one run-on paragraph. Example:....
# DisallowedCurabitur eleifend wisi iaculis ipsum.
Pellentque morbi-trist sentus et netus et malesuada fames ac turpis egestas. Vestibulum tortor
quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu_libero sit amet quam
egestas semper. Aenean ultricies mi vitae est. Mauris placerat's eleifend leo. Quisque et sapien
ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, orn si amt wit.# Allowed
Curabitur eleifend wisi iaculis ipsum.
Pellentque morbi-trist sentus et netus et malesuada fames ac turpis egestas. Vestibulum tortor
quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu_libero sit amet quam
egestas semper. Aenean ultricies mi vitae est. Mauris placerat's eleifend leo. Quisque et sapien
ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, orn si amt wit.
....==== Commit Body Line Length
[options="header"]
|===
| Enabled | Severity | Defaults
| false | error | maximum: 72
|===Ensures each line of the commit body doesn't extend beyond the maximum column limit.
==== Commit Body Paragraph Capitalization
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | none
|===Ensures each paragraph of the commit body is capitalized. Example:
....
# Disallowed
curabitur eleifend wisi iaculis ipsum.# Allowed
Curabitur eleifend wisi iaculis ipsum.
....{ascii_doc_link} and {markdown_link} code blocks are ignored since a paragraph that only consists of a code block is common practice. For ASCII Doc, this includes the following to be separate paragraphs if desired:
* link:https://docs.asciidoctor.org/asciidoc/latest/macros/audio-and-video[Audio and video links]
* link:https://docs.asciidoctor.org/asciidoc/latest/macros/images[Image links]
* link:https://docs.asciidoctor.org/asciidoc/latest/macros/links[Links]
* link:https://docs.asciidoctor.org/asciidoc/latest/macros/xref[Cross references]==== Commit Body Phrase
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | excludes: (see configuration)
|===Ensures non-descriptive words/phrases are avoided in order to keep commit message bodies informative
and specific. The exclude list is case insensitive. Detection of excluded words/phrases is case
insensitive as well. Example:....
# DisallowedObviously, the existing implementation was too simple for my tastes. Of course, this couldn't be
allowed. Everyone knows the correct way to implement this code is to do just what I've added in
this commit. Easy!# Allowed
Necessary to fix due to a bug detected in production. The included implementation fixes the bug
and provides the missing spec to ensure this doesn't happen again.
....==== Commit Body Presence
[options="header"]
|===
| Enabled | Severity | Defaults
| true | warn | minimum: 1
|===Ensures a minimum number of lines are present within the commit body. Lines with empty characters
(i.e. whitespace, carriage returns, etc.) are considered to be empty.Automatically ignores _fixup!_ commits as they are not meant to have bodies.
==== Commit Body Tracker Shorthand
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | excludes: (see configuration)
|===Ensures commit body doesn't use issue tracker shorthand. The exclude list defaults to GitHub Issues
but can be customized for any issue tracker.There are several reasons for excluding issue tracker links from commit bodies:
. Not all issue trackers preserve issues (meaning they can be deleted). This makes make reading
historic commits harder to understand why the change was made when the reference no longer works.
. When disconnected from the internet or working on a laggy connection, it's hard to understand why
a commit was made when all you have is a shorthand issue reference with no supporting context.
. During the course of a repository's life, issue trackers can be replaced (rare but does happen).
If the old issue tracker service is no longer in use, none of the commit body shorthand will
be of any relevance.Instead of using tracker shorthand syntax, take the time to write a short summary as to _why_ the
commit was made. Doing this will make it easier to understand _why_ the commit was made, keeps the
commit self-contained, and makes learning about/debugging the commit faster.==== Commit Body Word Repeat
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures commit bodies don't contain repeated words. Example:
....
# Disallowed
Necessary to to fix production error.# Allowed
Necessary to fix production error.
....==== Commit Signature
[options="header"]
|===
| Enabled | Severity | Defaults
| false | error | includes: `["Good"]`
|===Ensures all commit signatures are properly signed for improved security and validity of code being committed by various authors. By default, only "Good" signatures are allowed but you can expand this list if desired (although not recommended for security reasons). Valid options are:
* *Bad* (_B_)
* *Error* (_E_)
* *Good* (_G_)
* *None* (_N_)
* *Revoked* (_R_)
* *Unknown* (_U_)
* *Expired* (_X_)
* *Expired Key* (_Y_)All of the above obtained when using the pretty formats as provided by link:https://git-scm.com/docs/git-log#Documentation/git-log.txt-emGem[Git Log].
==== Commit Subject Length
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | maximum: 72
|===Ensures the commit subject length is no more than 72 characters in length. This default is more
lenient than the link:http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[50/72
rule] as it gives one the ability to formulate a more descriptive subject line without being too
wordy or suffer being word wrapped.Automatically ignores _fixup!_ or _squash!_ commit prefixes when calculating subject length.
==== Commit Subject Prefix
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: (see below)
| | | delimiter: " "
|===Ensures each commit subject uses consistent prefixes that explain _what_ is being committed. The
`includes` are _case sensitive_ and default to the following prefixes:* *Fixed* - Identifies what was fixed. The commit should be as small as possible and consist of
changes to implementation and spec only. In some cases this might be a single line change. The
important point is the change is applied to existing code which corrects behavior that wasn't
properly implemented earlier.
* *Removed* - Identifies what was removed. The commit should be as small as possible and consist
only of removed lines/files from the existing implementation. This might also mean breaking
changes requiring the publishing of a _major_ version release in the future.
* *Added* - Identifies what was added. The commit should be as small as possible and consist of
implementation and spec. Otherwise, it might be a change to an existing file which adds new
behavior.
* *Updated* - Identifies what was updated. The commit should be as small as possible and _not add
or fix_ existing behavior. This can sometimes be a grey area but is typically reserved for updates
to documentation, code comments, dependencies, etc.
* *Refactored* - Identifies what was refactored.
link:https://thoughtbot.com/blog/lets-not-misuse-refactoring[_Refactoring is for changing code
structure without changing observable behavior_]. The commit should be as small as possible and
not mix multiple kinds of changes at once. Refactored code should never break existing
implementation behavior or corresponding specs because, if that happens, then one of the other
four prefixes is what you want to use instead.In practice, it is quite rare to need a prefix other than what has been detailed above to explain
_what_ is being committed. These prefixes are not only short and easy to remember but also have the
added benefit of categorizing the commits for building release notes, change logs, etc. This becomes
handy when coupled with another tool,
link:https://alchemists.io/projects/milestoner[Milestoner], for producing consistent project
milestones and Git tag histories. For a deeper dive on subject prefixes and good commit messages in
general, please read about link:https://alchemists.io/articles/git_commit_anatomy[commit anatomy
] to learn more. 🎉Each prefix is delimited by a space which is the default setting but can be customized if desired.
Whatever you choose for a delimiter will not affect Git's special bang prefixes as described in the
tip below.💡 This analyzer automatically ignores _amend!_, _fixup!_, or _squash!_ commit prefixes when used as
a Git Hook in order to not disturb interactive rebase workflows.==== Commit Subject Suffix
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | excludes: `["\\!", "\\.", "\\?"]`
|===Ensures commit subjects are suffixed consistently. The exclude list _is_ case sensitive and prevents
the use of punctuation. This is handy when coupled with a tool, like
link:https://alchemists.io/projects/milestoner[Milestoner], which automates project milestone
releases.==== Commit Subject Word Repeat
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures commit subjects don't contain repeated words. Example:
....
# Disallowed
Added specs specs# Allowed
Added specs
....==== Commit Trailer Collaborator Capitalization
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | none
|===Ensures collaborator name is properly capitalized. Example:
....
# Disallowed
shepherd derrial book# Allowed
Shepherd Derrial Book
....==== Commit Trailer Collaborator Email
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | none
|===Ensures collaborator email address is valid for commit trailer.
....
# Disallowed
Co-authored-by: River Tam# Allowed
Co-authored-by: River Tam
....==== Commit Trailer Collaborator Key
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures collaborator trailer key is correct format.
....
# Disallowed
co-authored-by: River Tam# Allowed
Co-authored-by: River Tam
....==== Commit Trailer Collaborator Name
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | minimum: 2
|===Ensures collaborator name consists of, at least, a first and last name. Example:
....
# Disallowed
Co-authored-by: River# Allowed
Co-authored-by: River Tam
....==== Commit Trailer Duplicate
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | minimum: 2
|===Ensures commit trailer keys are not duplicated. Example:
....
# Disallowed
Co-authored-by: Shepherd Derrial Book
Co-authored-by: Shepherd Derrial Book# Allowed
Co-authored-by: Malcolm Reynolds
Co-authored-by: Shepherd Derrial Book
....==== Commit Trailer Format Key
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures format trailer key is correct format.
....
# Disallowed
format: markdown# Allowed
Format: markdown
....==== Commit Trailer Format Value
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: `["asciidoc", "markdown"]`
|===Ensures format trailer value is a valid value.
....
# Disallowed
Format: plain# Allowed
Format: asciidoc
....==== Commit Trailer Issue Key
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures issue trailer key is correct format.
....
# Disallowed
issue: 123# Allowed
Issue: 123
....==== Commit Trailer Issue Value
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: `["[\\w-]+"]`
|===Ensures issue trailer value is correct format.
....
# Disallowed
Issue: 123+45# Allowed
Issue: 123
....==== Commit Trailer Milestone Key
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures milestone trailer key is correct format.
....
# Disallowed
milestone: patch# Allowed
Milestone: patch
....==== Commit Trailer Milestone Value
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: `[major, minor, patch]`
|===Ensures milestone trailer value is correct format for link:https://semver.org[semantic versioning] purposes.
....
# Disallowed
Milestone: bogus# Allowed
Milestone: patch
....==== Commit Trailer Order
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures milestone trailers are alphabetically sorted.
....
# Disallowed
Issue: 123
Milestone: patch
Format: asciidoc# Allowed
Format: asciidoc
Issue: 123
Milestone: patch
....==== Commit Trailer Reviewer Key
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures reviewer trailer key is correct format.
....
# Disallowed
reviewer: tana# Allowed
Reviewer: tana
....==== Commit Trailer Reviewer Value
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: `[clickup, github, jira, linear, shortcut, tana]`
|===Ensures reviewer trailer value is correct format for linking/referencing the code review system.
....
# Disallowed
Reviewer: bogus# Allowed
Reviewer: tana
....==== Commit Trailer Signer Capitalization
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | none
|===Ensures commit signer trailer name is properly capitalized.
....
# Disallowed
Signed-off-by: jayne cobb# Allowed
Signed-off-by: Jayne Cobb
....==== Commit Trailer Signer Email
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | none
|===Ensures commit signer trailer email is properly capitalized.
....
# Disallowed
Signed-off-by: Jayne Cobb# Allowed
Signed-off-by: Jayne Cobb
....==== Commit Trailer Signer Key
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures signer trailer key is correct format.
....
# Disallowed
signed-off-by: Jayne Cobb# Allowed
Signed-off-by: Jayne Cobb
....==== Commit Trailer Signer Name
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | minimum: 2
|===Ensures signer name consists of, at least, a first and last name.
....
# Disallowed
Signed-off-by: Jayne# Allowed
Signed-off-by: Jayne Cobb
....==== Commit Trailer Tracker Key
[options="header"]
|===
| Enabled | Severity
| true | error
|===Ensures tracker trailer key is correct format.
....
# Disallowed
tracker: linear# Allowed
Tracker: linear
....==== Commit Trailer Tracker Value
[options="header"]
|===
| Enabled | Severity | Defaults
| true | error | includes: `["[\\w\\-\\s]+"]`
|===Ensures tracker trailer key is correct format.
....
# Disallowed
Tracker: *ACME$# Allowed
Tracker: ACME Issues
....=== Git
==== Default Branch
Your default branch configuration is respected no matter if it is set globally or locally. If the
default branch is _not set_ then Git Lint will fall back to `master` for backwards compatibility.
When the next major version is released, the default branch fallback will change from `master` to
`main`. You can set your default branch at any time by running the following from the command line:[source,bash]
----
git config --add init.defaultBranch main
----💡 When setting your default branch, ensure you use a consistent Git configuration across all of
your environments.==== Hooks
This gem supports link:https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks[Git Hooks].
It is _highly recommended_ you manage Git Hooks as global scripts as it'll reduce project
maintenance costs for you. To configure global Git Hooks, add the following to your
`$HOME/.gitconfig`:....
[core]
hooksPath = ~/.git_template/hooks
....Then you can customize Git Hooks for all of your projects.
link:https://github.com/bkuhlmann/dotfiles/tree/main/home_files/.config/git/hooks[Check out these
examples].If a global configuration is not desired, you can add Git Hooks at a per project level by editing
any of the scripts within the `.git/hooks` directory of the repository.===== Commit Message
The _commit-msg_ hook -- which is the best way to use this gem as a Git Hook -- is provided as a
`--hook` option. Usage:[source,bash]
----
git-lint --hook PATH
----As shown above, the `--hook` command accepts a file path (i.e. `.git/COMMIT_EDITMSG`) which
is provided to you by Git within the `.git/hooks/commit-msg` script. Here is a working example of
what that script might look like:[source,bash]
----
#! /usr/bin/env bashset -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'if ! command -v git-lint > /dev/null; then
printf "%s\n" "[git]: Git Lint not found. To install, run: gem install git-lint."
exit 1
figit-lint --hook "${BASH_ARGV[0]}"
----Whenever you attempt to add a commit, Git Lint will check your commit for issues prior to saving it.
===== Post Commit
The _post-commit_ hook is possible via the `analyze` command. Usage:
[source,bash]
----
git-lint analyze --commit SHA
----The _post-commit_ hook can be used multiple ways but, generally, you'll want to check the last
commit made. Here is a working example which can be used as a `.git/hooks/post-commit` script:[source,bash]
----
#! /usr/bin/env bashset -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'if ! command -v git-lint > /dev/null; then
printf "%s\n" "[git]: Git Lint not found. To install, run: gem install git-lint."
exit 1
figit-lint analyze --commit $(git log --pretty=format:%H -1)
----Whenever a commit has been saved, this script will run Git Lint to check for issues.
=== Rake
You can add Rake support by adding the following to your `Rakefile`:
[source,ruby]
----
begin
require "git/lint/rake/register"
rescue LoadError => error
puts error.message
endGit::Lint::Rake::Register.call
----Once required and registered, the following tasks will be available (i.e. `bundle exec rake -T`):
....
rake git_lint
....=== Continuous Integration (CI)
This gem automatically configures itself for known CI build servers (see below for details). If you
have a build server that is not listed, please log an issue or provide an implementation with
support.Calculation of commits is done by analyzing all feature branch commits ahead of the default branch (i.e. "main"). In other words, `git log --oneline main..your_feature_branch`.
==== link:https://circleci.com[Circle CI]
Detection and configuration happens automatically by checking the `CIRCLECI` environment variable.
No additional setup required!==== link:https://docs.github.com/en/free-pro-team@latest/actions[GitHub Actions]
Detection happens automatically by checking the `GITHUB_ACTIONS` environment variable as supplied by
the GitHub environment. The only configuration required is to add a `.github/workflows/git_lint.yml`
to your repository with the following contents:[source,yaml]
----
name: Git Linton: pull_request
jobs:
run:
runs-on: ubuntu-latest
container:
image: ruby:latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{github.head_ref}}
- name: Install
run: gem install git-lint
- name: Analyze
run: git-lint --analyze
----The above will ensure Git Lint runs as an additional check on each Pull Request.
==== link:https://www.netlify.com[Netlify CI]
Detection and configuration happens automatically by checking the `NETLIFY` environment variable. No
additional setup required!== Style Guide
In addition to what is described above and automated for you, the following style guide is also
worth considering:=== General
* Use a {git_rebase_workflow_link} instead of a Git Merge Workflow.
* Use `git commit --amend` when fixing a previous commit, addressing code review feedback, etc.
* Use `git commit --fixup` when fixing an earlier commit, addressing code review feedback, etc., and
don't need to modify the original commit message.
* Use `git commit --squash` when fixing an earlier commit, addressing code review feedback, etc.,
and want to combine multiple commit messages into a single commit message. _Avoid using squash to
blindly combine multiple commit messages without editing them into a single, coherent message._
* Use `git rebase --interactive` when cleaning up commit history, order, messages, etc. This should
be done prior to submitting a code review or when code review feedback has been addressed and
you are ready to rebase onto `main`.
* Use `git push --force-with-lease` instead of `git push --force` when pushing changes after an
interactive rebasing session.
* Avoid checking in development-specific configuration files (add to `.gitignore` instead).
* Avoid checking in sensitive information (i.e. security keys, passphrases, etc).
* Avoid "WIP" (a.k.a. "Work in Progress") commits and/or code review labels. Be confident with your
code and colleagues' time. Use branches, stashes, etc. instead -- share a link to a feature branch
diff if you have questions/concerns during development.
* Avoid using link:https://git-scm.com/book/en/v2/Git-Tools-Submodules[Git Submodules]. This
practice leads to complicated project cloning, deployments, maintenance, etc. Use separate
repositories to better organize and split out this work. Sophisticated package managers, like
link:https://bundler.io[Bundler], exist to manage these dependencies better than what multiple Git
Submodules can accomplish.
* Avoid using link:https://git-lfs.github.com[Git LFS] for tracking binary artifacts/resources.
These files are not meant for version control and lead to large repositories that are time
consuming to clone/deploy. Use storage managers like link:https://git-annex.branchable.com[Git
Annex], link:https://aws.amazon.com/s3[Amazon S3], or link:https://lakefs.io[LakeFS] which are
better suited for binary assets that don't change often.=== Security
Ensure signed commits, pushes, and tags are enabled within your global Git Configuration to reduce
an
link:https://blog.gruntwork.io/how-to-spoof-any-user-on-github-and-what-to-do-to-prevent-it-e237e95b8deb[attack
vector]. Run the following commands to enable:[source,bash]
----
git config --global commit.gpgSign true
git config --global push.gpgSign true
git config --global tag.gpgSign true
----⚠️ GitHub, unfortunately, doesn't support signed pushes so you might need to leave that
configuration disabled.=== Commits
* Use a commit subject that explains _what_ is being committed.
* Use a commit message body that explains _why_ the commit is necessary. Additional considerations:
** If the commit has a dependency to the previous commit or is a precursor to the commit that will
follow, make sure to explain that.
** Include links to dependent projects, stories, etc. if available.
* Use small, atomic commits:
** Easier to review and provide feedback.
** Easier to review implementation and corresponding tests.
** Easier to document with detailed subjects (especially when grouped together in a pull request).
** Easier to reword, edit, squash, fix, or drop when interactively rebasing.
** Easier to combine together versus tearing apart a larger commit into smaller commits.
* Use logically ordered commits:
** Each commit should tell a story and be a logical building block to the next commit.
** Each commit should, ideally, be the implementation plus corresponding test. Avoid committing
changes that are a jumble of mixed ideas as they are hard to decipher and a huge insult not only
to the reviewer but your future self.
** Each commit, when reviewed in order, should be able to explain _how_ the feature or bug fix was
completed and implemented properly.
* Keep refactored code separate from behavioral changes. This makes the review process easier
because you don't have to sift through all the line and format changes to figure out what is new
or changed.=== Branches
* Use feature branches for new work.
* Maintain branches by rebasing upon `main` on a regular basis.=== Tags
* Use tags to denote link:https://alchemists.io/projects/milestoner[milestones]/releases:
** Makes it easier to record milestones and capture associated release notes.
** Makes it easier to compare differences between versions.
** Provides a starting point for debugging production issues (if any).=== Rebases
* Avoid rebasing a shared branch. If you must do this, clear communication should be used to warn
those ahead of time, ensure that all of their work is checked in, and that their local branch is
deleted first.=== Hooks
* Use hooks to augment and automate your personal workflow such as checking code quality, detecting
forgotten debug statements, etc.
* Use hooks globally rather than locally per project. Doing this applies the same functionality
across all projects automatically, reduces maintenance per project, and provides consistency
across all projects. This can best be managed via your
link:https://github.com/bkuhlmann/dotfiles/tree/main/home_files/.config/git/hooks[Dotfiles].
* Avoid forcing global or local project hooks as a team-wide mandate. Hooks are a personal tool much
like editors or other tools one choose to do their work. For team consistency, use a continuous
integration build server instead.=== Code Reviews
For an in depth look at how to conduct code reviews, please read my
link:https://alchemists.io/articles/code_reviews[article] on this subject to learn more.== Development
To contribute, run:
[source,bash]
----
git clone https://github.com/bkuhlmann/git-lint
cd git-lint
bin/setup
----You can also use the IRB console for direct access to all objects:
[source,bash]
----
bin/console
----== Tests
To test, run:
[source,bash]
----
bin/rake
----== link:https://alchemists.io/policies/license[License]
== link:https://alchemists.io/policies/security[Security]
== link:https://alchemists.io/policies/code_of_conduct[Code of Conduct]
== link:https://alchemists.io/policies/contributions[Contributions]
== link:https://alchemists.io/policies/developer_certificate_of_origin[Developer Certificate of Origin]
== link:https://alchemists.io/projects/git-lint/versions[Versions]
== link:https://alchemists.io/community[Community]
== Credits
* Built with link:https://alchemists.io/projects/gemsmith[Gemsmith].
* Engineered by link:https://alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].