Lintje is an opinionated linter for Git.

Related tags

Utilities lintje
Overview

Lintje

Lintje is an opinionated linter for Git. It lints commit messages based on a preconfigured set of rules focussed on promoting communication between people. The idea is to write commits meant for other people reading them during reviews and debug sessions 2+ months from now.

  • No configuration. Don't spend time configuring your Git commit linter and instead adopt a preconfigured set of rules.
  • Portable. Lintje is a Rust project built for several Operating Systems and has no dependencies. Drop it into your project and it works.

Table of Contents

Example

Given the last commit in a project is this:

Fix bug

When running lintje to lint the last commit, the output will be:

$ lintje
6162010: Fix bug
  SubjectCliche: Reword the subject to explain what bug was fixed.
  MessagePresence: Add a message body to provide more context about the change
    and why it was made.

1 commit inspected, 2 violations detected

For more usage examples, see the usage section.

Installation

macOS

To install Lintje on macOS use the Homebrew tap.

brew tap tombruijn/lintje
brew install lintje

Whenever a new version comes out run the following:

brew update
brew upgrade lintje

Or install it manually by downloading the archive from the latest release on the releases page for the appropriate system. See the list of installation targets.

Once downloaded extract it to a directory in your $PATH so the lintje executable is available in any directory from the command line.

Linux

Please see the installation guide for more information about Debian installation packages.

For other systems, that do not have installation packages yet, follow the instructions below.

To install Lintje on Linux download the archive from the latest release on the releases page for the appropriate system. See the list of installation targets.

Once downloaded extract it to a directory in your $PATH so the lintje executable is available in any directory from the command line.

Microsoft Windows

To install Lintje on Microsoft Windows download the archive from the latest release on the releases page for the appropriate system. See the list of installation targets.

Once downloaded extract it to a directory in your PATH so the lintje.exe executable is available in any directory from the command line.

Cargo install

If Rust is installed on your system it's also an option to install the Lintje crate using the command below. It's not guaranteed to work on any system Rust runs on, but please create an issue if you run into any problems.

cargo install lintje

Supported Operating Systems

  • Apple macOS:
    • x86 64-bit (x86_64-apple-darwin)
    • ARM 64-bit (aarch64-apple-darwin) (Apple Silicon)
  • Linux GNU (most distributions like Ubuntu, Debian, etc.):
    • x86 64-bit (x86_64-unknown-linux-gnu)
    • ARM 64-bit (aarch64-unknown-linux-gnu)
  • Alpine Linux musl:
    • x86 64-bit (x86_64-unknown-linux-musl)
    • ARM 64-bit (aarch64-unknown-linux-musl)
  • Microsoft Windows:
    • x86 64-bit (x86_64-pc-windows-gnu)

Is your favorite Operating System not in this list? Please create an issue with what Operating System you want to use Lintje on.

Usage

# Lint the most recent commit on the current branch:
lintje
# Is the same as:
lintje HEAD
# Lint a specific commit:
lintje 3a561ef766c2acfe5da478697d91758110b8b24c

# Lintje multiple commits
# Lint the last 5 commits:
lintje HEAD~5..HEAD
# Lint the difference between two branches:
lintje main..develop

It's recommended to add Lintje to your CI setup to lint the range of commits added by a Pull Request or push.

See also the examples page for more usage examples.

Exit codes

Lintje will exit with the following status codes in these situations:

  • 0 (Success) - No violations have been found. The commit is accepted.
  • 1 (Failure) - One or more violations have been found. The commit is not accepted.
  • 2 (Error) - An internal error occurred and the program had to exit. This is probably a bug, please report it in the issue tracker.

Git hook

To lint the commit locally immediately after writing the commit message, use a Git hook. To add it, run the following:

echo "lintje --hook-message-file=\$1" >> .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

If Lintje fails the commit is aborted. The message you entered is available in .git/COMMIT_EDITMSG and you can restart your commit message with:

git commit --edit --file=.git/COMMIT_EDITMSG

Personally I don't like how it fails the commit process and makes the commit message harder to reach to use again. It also makes making fixup commits really difficult. Instead I prefer not failing the commit hook and amending the commit afterwards to fix any issues that came up. The example below will have Lintje output the issues it found, but still make the commit. You can then amend the commit to fix any issues it found afterwards.

echo "lintje --hook-message-file=\$1 || echo \"\\\nLintje failure\"" >> .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

Git alias

It's possible to set up an alias with Git to use git lint as the command instead, or any other alias you prefer.

Set up your alias with the following line.

git config --global alias.lint '!lintje'

You'll then be able to call it like the examples below and any other methods listed in usage.

git lint
git lint main..develop

Rules

For more information on which rules are validated on, see the rules docs page.

Configuration

Lintje does not have a configuration file where you can enable/disable/configure certain rules for an entire project.

Instead it's possible to ignore specific rules per commit.

Ignoring rules per commit

It's possible to ignore certain rules for a commit, but this be used very infrequently. If you think Lintje should handle a certain scenario better, please create an issue explaining your use case.

To ignore a rule in a specific commit, use the magic lintje:disable comment.

Start a new line (preferably at the end of the commit message) that starts with lintje:disable and continue specifying the rule you want to ignore, such as: lintje:disable SubjectPunctuation.

Example commit with multiple ignored rules:

This is a commit subject!!

This is a commit message line 1.
Here is some more content of the commit message is very long for valid reasons.

lintje:disable SubjectPunctuation
lintje:disable MessageLineTooLong

(The above is a bad commit, please don't use the disabling of rules this way.)

Getting help

Need help with Lintje? Found a bug or have a question?

Reach out to me through the issue tracker, discussions, on Twitter @tombruijn (DMs are open) or on any Slack team you can find me on.

Development

Setup

Make sure Rust is installed before continuing.

cargo build

Testing

cargo test

Building

Docker is required to build all the different target releases using cross.

To build all different targets, run the build script:

rake build

The build output can be found in the dist/ directory.

Releases

Before release all the supported targets will be build. See Building for more information about the build step.

To release all different targets, run the release script:

rake release

The release will be pushed to GitHub.

Finally update the Lintje Homebrew tap.

Code of Conduct

This project has a Code of Conduct and contributors are expected to adhere to it.

Comments
  • Work nicely together with `commit --verbose`

    Work nicely together with `commit --verbose`

    I often use git commit --verbose to have a last check to not commit rubbish (or at least unintentional rubbish).

    Lintje is assessing the lines after the magic comment line as if they're part of the commit message.

    Notice that the lines underneath line 17 in the example, do not actually make it into the commit, they're meant as 'FYI these are the changes you're committing'. The lines themselves aren't commented out, they're just below the magic comment line

    Steps to reproduce:

    1. Create a commit with long lines in the code changes
    2. Commit the change from the cli with EDITOR=vim commit -v (other editors may break/work, but I want you to be able to reproduce for sure)
    3. run lintje on the commit (in the example it was run from a non-breaking hook according to the README)

    Example output from a commit

    The commit window is as follows:

      1 Let's mention our streaming sponsor on our website
      2
      3 We have the streaming partner sponsor package, this amends that work to
      4 also mention our sponsor on our amsrb.org page. May (but prolly will
      5 not) boost their SEO ranking (but will deffo boost their ego 😇 )
      6
      7 # Please enter the commit message for your changes. Lines starting
      8 # with '#' will be ignored, and an empty message aborts the commit.
      9 #
     10 # On branch streaming-sponsor
     11 # Your branch is behind 'origin/streaming-sponsor' by 1 commit, and can be fast-forwarded.
     12 #   (use "git pull" to update your local branch)
     13 #
     14 # Changes to be committed:
     15 #┊      modified:   sponsorships/index.html
     16 #
     17 # ------------------------ >8 ------------------------
     18 # Do not modify or remove the line above.
     19 # Everything below it will be ignored.
     20 diff --git a/sponsorships/index.html b/sponsorships/index.html
     21 index 3d21fb0..03d32f7 100644
     22 --- a/sponsorships/index.html
     23 +++ b/sponsorships/index.html
     24 @@ -13,19 +13,20 @@ title: Sponsorships
     25    <p>All sponsors are required to read and adhere to our <a href="https://amsrb.org/code-of-conduct/">Code of Condu
     26
     27    <h2>Streaming partner - € 250</h2>
     28 -
     29 +
     30    <p>As we're looking at virtual-only events a <em>little</em> while longer, we're looking for parties that'd like
     31 -
     32 +
     33    <p>In return you'll receive:</p>
     34
     35    <ul>
     36      <li>Mention in the general channel on Slack</li>
     37      <li>Mention on meetup.com</li>
     38 +    <li>Mention on amsrb.org</li>
     39      <li>1 slide, and a shoutout during the meetup’s intro</li>
     40      <li>Optional: instead of the slide, you can submit a 1 minute-long, recorded pitch</li>
     41      <li>(@)mention on Twitter</li>
     42    </ul>
     43 -
     44 +
     45    <h2>Location sponsor</h2>
     46
     47    <p>Hosting an Amsterdam.rb means your location is (wheelchair) accessible, and you have the following on-site:</p
    ~
    

    When I exit the commit message editor (saving the message for commit), Lintje responds with raised eyebrows:

    MessageLineLength: Line 17 in the message body is longer than 72 characters
      0000000:17:73: Let's mention our streaming sponsor on our website
         |
      17 |    <p>As we're looking at virtual-only events a <em>little</em> while longer, we're looking for parties that'd like to help us cover our costs.</p>
         |                                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Shorten line to maximum 72 characters
    
    MessageLineLength: Line 27 in the message body is longer than 72 characters
      0000000:27:73: Let's mention our streaming sponsor on our website
         |
      27 |      <li>Optional: instead of the slide, you can submit a 1 minute-long, recorded pitch</li>
         |                                                                         ^^^^^^^^^^^^^^^^^^^^ Shorten line to maximum 72 characters
    
    MessageLineLength: Line 34 in the message body is longer than 72 characters
      0000000:34:73: Let's mention our streaming sponsor on our website
         |
      34 |    <p>Hosting an Amsterdam.rb means your location is (wheelchair) accessible, and you have the following on-site:</p>
         |                                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Shorten line to maximum 72 characters
    
    1 commit and branch inspected, 3 violations detected
    
    Lintje failure
    [streaming-sponsor d609231] Let's mention our streaming sponsor on our website
     1 file changed, 4 insertions(+), 3 deletions(-)
    
    opened by arnoFleming 4
  • Changing only the CHANGELOG.md file doesn't trigger the MessageSkipBuildTag rule

    Changing only the CHANGELOG.md file doesn't trigger the MessageSkipBuildTag rule

    Not sure what happens here:

    $ lintje --version
    lintje 0.8.0
    
    $ lintje 
    [DEBUG] No issues found for commit '8c166d5c75dcc74ed2d93d97d467b16ee53dac3f' in rule 'MessageSkipBuildTag'
    [DEBUG] Commits: [Commit { long_sha: Some("8c166d5c75dcc74ed2d93d97d467b16ee53dac3f"), short_sha: Some("8c166d5"), email: Some("[email protected]"), subject: "URL detection ticket references is a addition", message: "\nIn the CHANGELOG mark the URL detection and better detection for the\nrepo shorthands as a new feature rather than a change. It does more now.\n", file_changes: ["CHANGELOG.md"], issues: [Issue { type: Hint, rule: MessageTicketNumber, message: "The message body does not contain a ticket or issue number", position: MessageLine { line: 6, column: 1 }, context: [Context { type: Plain, line: Some(4), content: "repo shorthands as a new feature rather than a change. It does more now.", range: None, message: None }, Context { type: Plain, line: Some(5), content: "", range: None, message: None }, Context { type: Addition, line: Some(6), content: "Fixes #123", range: Some(0..10), message: Some("Consider adding a reference to a ticket or issue") }] }], ignored: false, ignored_rules: [] }]
    
    bug 
    opened by tombruijn 1
  • Differentiate between ticket number and version number in branch name

    Differentiate between ticket number and version number in branch name

    https://lintje.dev/docs/rules/branch/#branchnameticketnumber

    For branch names like library-1.1 it gets recognized as a ticket number, which is wrong, but the branch name is too. Instead it can say something like rule "branch name version number" failed. Because what do you do with a branch name with the format library-<version number>? Update it, remove it, sync it?

    Name it update-library-1.1 instead.

    enhancement 
    opened by tombruijn 1
  • Add rule to check if only text files are edited and suggest a

    Add rule to check if only text files are edited and suggest a "skip ci" build tag

    When I change only the README.md it's a waste to run the CI build for the latest change. Suggest to use a [skip ci] tag in this case.

    Only for text files that don't require a build. Avoid also suggesting this for static sites.

    enhancement 
    opened by tombruijn 1
  • Add hint system

    Add hint system

    Not everything Lintje can detect should be an error.

    I can add an hint system to show messages with suggestions like in #23 for adding links to issues, which is not a hard requirement.

    enhancement 
    opened by tombruijn 1
  • Add rule to check message body for only links or references

    Add rule to check message body for only links or references

    Don’t allow commits with only “close # 124” message bodies. Or with full links to an issue.

    It can also give a hint if no links to issues are present, to promote linking to issues. This was added in version 0.7.0.

    Accepted link types:

    • full link to something GitHub/GitLab/etc. (Or just any link?)
    • references like #123 (any other systems use other formats?)
    • references like JIRA-123
    enhancement 
    opened by tombruijn 1
  • MergeCommit violation should ignore SubjectLength rule

    MergeCommit violation should ignore SubjectLength rule

    If a commit has a MergeCommit violation, skip the SubjectLength rule.

    MergeCommit: A remote merge commit was found
      0a672b3:1:1: Merge branch 'develop' of github.com/org/repo into develop
        |
      1 | Merge branch 'develop' of github.com/org/repo into develop
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Rebase on the remote branch, rather than merging the remote branch into the local branch
    
    SubjectLength: The subject of `58` characters wide is too long
      0a672b3:1:51: Merge branch 'develop' of github.com/org/repo into develop
        |
      1 | Merge branch 'develop' of github.com/org/repo into develop
        |
    
    enhancement 
    opened by tombruijn 1
  • GitHub Action

    GitHub Action

    Try and make a GitHub Action for Lintje.

    I can make this work with the payload.before...payload.after combination of SHAs from the GitHub push action. The problem is that the "checkout" action by default only checks out the first commit. This makes it not possible to query Git itself unless you specify fetch-depth: X where X is arbitrary. I can't find a way to select a number of commits based on the event payload.

    So I should probably fetch the commit message through the GitHub API in the action. That means lintje needs to support reading from STDIN to read the commits from there.

    // Pseudo code: this should probably be done in the GitHub action nodejs script
    gh commits fetch ... > commits
    cat commits | lintje
    

    This in a GitHub action does not work unfortunately:

    - uses: actions/checkout@v2
      with:
        fetch-depth: ${{ github.context.payload.commits.length + 1 }} # Fetch enough commits to test on
    

    To do

    • Check if you can add an additional rule in the action that every commit on the PR should have a successful build? If not, fail lintje.
    enhancement 
    opened by tombruijn 1
  • Check commit contents to see if it's empty or not

    Check commit contents to see if it's empty or not

    Add a rule that checks if the commit contains file changes. If it doesn't contain file changes, add a violation like DiffEmpty.

    $ git log --shortstat -n 2 --pretty="------------------------ COMMIT >! ------------------------%n%H%n%ae%n%B%n------------------------ BODY >! ------------------------"
    

    Commit with changes output:

    ------------------------ COMMIT >! ------------------------
    6830b1ed45d00283cc9fc70943a649eef165f917
    [email protected]
    Add README
    
    ------------------------ BODY >! ------------------------
    
     1 file changed, 1 insertion(+)
    

    Empty command output:

    ------------------------ COMMIT >! ------------------------
    6e4f783a837244afd60511dc9ae3f994e4ace825
    [email protected]
    Hello there
    
    ------------------------ BODY >! ------------------------
    
    enhancement 
    opened by tombruijn 1
  • Better handling of Git not being found

    Better handling of Git not being found

    When the Git command cannot be found I currently see no output in a test setup:

    $ git
    bash: git: command not found
    $ lintje
    0 commits inspected, 0 violations detected
    

    It should fail with an error that Git could not be found.

    This is on the ubuntu:latest docker image.

    enhancement 
    opened by tombruijn 1
  • Skip certain rules if some violations have already been found

    Skip certain rules if some violations have already been found

    For example, the SubjectCliche rule for a "WIP" commit shouldn't also trigger the SubjectLength rule. It creates noise, and people may be confused which violation to focus on first.

    • Cliche?
      • skip length
    • needs rebase?
      • skip capitalization and messagepresence
    enhancement 
    opened by tombruijn 1
  • Check for

    Check for "Update filename.ext" commits

    These commits don't say much, but they do usually have a message body so they pass. The message body is the co-author of the suggestion in a GitHub code review.

    enhancement 
    opened by tombruijn 1
  • Configure Clippy to be pedantic

    Configure Clippy to be pedantic

    This prints a lot more warning about things I should maybe look at.

    // src/main.rs
    #![warn(clippy::pedantic)]
    

    Note that clippy::pedantic contains some very aggressive lints prone to false positives. https://github.com/rust-lang/rust-clippy

    See also https://rust-lang.github.io/rust-clippy/master/ for a list of rules (search by pedantic).

    chore 
    opened by tombruijn 1
  • Rule BranchNameCapitalization - check for capitalization in branch names

    Rule BranchNameCapitalization - check for capitalization in branch names

    Add a BranchNameCapitalization rule to now allow any capitalization. Does that make sense? Or is there a use case for capitalization, other than ticket numbers? (JIRA-123-feature).

    Extracted from #1.

    enhancement 
    opened by tombruijn 0
  • Improve MergeCommit rule to focus on remote and non-base branches

    Improve MergeCommit rule to focus on remote and non-base branches

    This build should not have failed for merging develop into the main branch: https://appsignal.semaphoreci.com/jobs/a4882761-bd18-4b28-8b1e-afbb13ce7d05

    ba5fe03: Merge branch 'develop'
      MergeCommit: Rebase branches on the base branch, rather than merging the base branch with a merge commit.
    

    Can I add some accepted branch names that are accepted? Can I find out what is the base branch? Or should the rule be limited now on merge commits made by git pull

    bug 
    opened by tombruijn 0
Releases(v0.11.2)
Owner
Tom de Bruijn
Organizer @rubynl @amsrb. Senior developer and writer. Gundam 🤖 pilot. he/him
Tom de Bruijn
An opinionated, practical color management library for games and graphics.

colstodian An opinionated color management library built on top of kolor. Introduction colstodian is a practical color management library for games an

Gray Olson 27 Dec 7, 2022
Membrane is an opinionated crate that generates a Dart package from a Rust library. Extremely fast performance with strict typing and zero copy returns over the FFI boundary via bincode.

Membrane is an opinionated crate that generates a Dart package from a Rust library. Extremely fast performance with strict typing and zero copy returns over the FFI boundary via bincode.

Jerel Unruh 70 Dec 13, 2022
An opinionated Rust library for interacting with AWS DynamoDB single-table designs.

Modyne An opinionated library for interacting with AWS DynamoDB single-table designs. † Motive Modyne follows the precepts laid out for effective sing

Marcus Griep 14 Jun 8, 2023
Simple git/hg tui client focused on keyboard shortcuts

verco A simple Git/Hg tui client focused on keyboard shortcuts Screenshots Platforms This project uses Cargo and pure Rust stable and works on latest

Matheus Lessa Rodrigues 214 Dec 26, 2022
🌌⭐ Git tooling of the future.

❯ Glitter Git tooling of the future. ❯ ?? Features Config files Fast Easy to use Friendly errors ❯ ?? Documentation For proper docs, see here ❯ ✋ What

Milo 229 Dec 22, 2022
Estimate the amount of time spent working on a Git repository

jikyuu (時給) A tool to estimate the amount of time spent working on a Git repository. It is a direct port of git-hours, written in Node.js, because the

null 18 Nov 16, 2022
A small tool to clone git repositories to a standard location, organised by domain name and path.

A small tool to clone git repositories to a standard location, organised by domain name and path. Runs on BSD, Linux, macOS, Windows, and more.

Wesley Moore 68 Dec 19, 2022
Stacked branch management for Git

git-stack Stacked branch management for Git Dual-licensed under MIT or Apache 2.0 Documentation About Installation Getting Started Reference FAQ Compa

Ed Page 1 Jul 18, 2022
Replay git history with some tweaks

Git-replay Overview Git-replay is a simple tool that replays the history of a Git repository but with some tweaks (i.e., it can change the author name

Tak-gun Na 3 Mar 22, 2022
GRM — Git Repository Manager

GRM helps you manage git repositories in a declarative way. Configure your repositories in a TOML file, GRM does the rest.

Hannes Körber 32 Dec 30, 2022
A git hook to manage derivative files automatically.

git-derivative A git hook to manage derivative files automatically. For example if you checked out to a branch with different yarn.lock, git-derivativ

Sung Jeon 3 Oct 30, 2022
Simple and fast git helper functions

Simple and fast git helper functions

LongYinan 126 Dec 11, 2022
Verbump - A simple utility written in rust to bump and manage git semantic version tags.

Verbump - A simple utility written in rust to bump and manage git semantic version tags.

Sarat Chandra 6 May 6, 2022
A git prepare-commit-msg hook for authoring commit messages with GPT-3.

gptcommit A git prepare-commit-msg hook for authoring commit messages with GPT-3. With this tool, you can easily generate clear, comprehensive and des

Roger Zurawicki 3 Jan 19, 2023
Original Version Management System based on Git

nss (noshishi) Original Version Management System based on Git. Learning git and rust for good developer. Usage Install cargo install nssi how to nss

nopeNoshishi 4 Feb 13, 2023
Easily add emojis to your git commit messages 😎

gimoji A CLI tool that makes it easy to add emojis to your git commit messages. It's very similar to (and is based on) gitmoji-cli but written in Rust

Zeeshan Ali Khan 12 May 29, 2023
Command palette-style Git client for blazing-fast commits.

?? About Commit Commit is the world's simplest Git client. Open it with a keyboard shortcut, write your commit, and you're done! Commit will automatic

Miguel Piedrafita 190 Aug 18, 2023
Verify that registry crates in your Cargo.lock are reproducible from the git repository

cargo-goggles Verify that registry crates in your Cargo.lock are reproducible from the git repository. This cargo subcommand analyzes the following pr

M4SS - Industrial IoT Solutions 36 Jul 16, 2024
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
Opinionated, zero-config linter for JavaScript monorepos

Sherif: Opinionated, zero-config linter for JavaScript monorepos About Sherif is an opinionated, zero-config linter for JavaScript monorepos. It runs

Tom Lienard 219 Oct 10, 2023