Git Product home page Git Product logo

fit-commit's Introduction

Fit Commit

A Git hook to validate your commit messages based on community standards.

Example

$ git commit
Adding a cool feature
foobar foobar foobar,
foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar

1: Error: Message must use imperative present tense.
2: Error: Second line must be blank.
3: Error: Lines should be <= 72 chars. (76)

Commit anyway? [y/n/e] ▊

Prerequisites

  • Ruby >= 1.9 (OS X users already have this installed)

Installation

Install the gem:

$ gem install fit-commit

Install the hook in your Git repo:

$ fit-commit install

This creates a .git/hooks/commit-msg script which will automatically check your Git commit messages.

Validations

  • Line Length: All lines must be <= 72 chars (URLs excluded). First line should be <= 50 chars. Second line must be blank.
  • Tense: Message must use imperative present tense: "Fix bug" and not "Fixed bug" or "Fixes bug."
  • Subject Period: Do not end your subject line with a period.
  • Capitalize Subject: Begin all subject lines with a capital letter.
  • Frat House: No offensive content.
  • WIP: Do not commit WIPs to shared branches (disabled by default)

Configuration

Settings are read from these files in increasing precedence: /etc/fit_commit.yml, $HOME/.fit_commit.yml, config/fit_commit.yml, ./.fit_commit.yml.

These are the default settings that can be overridden:

---
Validators/LineLength:
  Enabled: true
  MaxLineLength: 72
  SubjectWarnLength: 50
  AllowLongUrls: true
Validators/Tense:
  Enabled: true
Validators/SubjectPeriod:
  Enabled: true
Validators/CapitalizeSubject:
  Enabled: true
  WarnOnWiplikes: true
Validators/Frathouse:
  Enabled: true
Validators/Wip:
  Enabled: false

The Enabled property accepts multiple formats:

# true/false to enable/disable the validation (branch agnostic)
Validators/Foo:
  Enabled: false
# Array of String or Regex matching each branch it's enabled on
Validators/Bar:
  Enabled:
    - main
    - !ruby/regexp /\Afoo.+bar/

Adding Custom Validators

Create your custom validator as a FitCommit::Validators::Base subclass:

module FitCommit
  module Validators
    class MyCustomValidator < Base
      def validate_line(lineno, text)
        if text =~ /sneak peak/i
          add_error(lineno, "I think you mean 'sneak peek'.")
        end
      end
    end
  end
end

# A validator can also validate the commit message as a whole:
module FitCommit
  module Validators
    class MyCustomValidator < Base
      def validate(lines)
        if lines.none? { |line| line.text =~ /#\d+/ }
          add_warning(lines.last.lineno, "Related issue not referenced.")
        end
      end
    end
  end
end

Require the file and enable the validator in your config:

FitCommit:
  Require:
    - somedir/my_custom_validator.rb
Validators/MyCustomValidator:
  Enabled: true

You can also publish your validator as a gem, and require it that way:

FitCommit:
  Require:
    - my-custom-validator-gem
Validators/MyCustomValidator:
  Enabled: true

If others might find your validator useful, submit it as a Pull Request. If it's not useful for everyone, it can be disabled by default.

FAQ

Can Fit Commit run in all my repos without having to install it each time?

First set your global Git template directory:

$ git config --global init.templatedir '~/.git_template'
$ mkdir -p ~/.git_template/hooks

Now you can copy the hooks you want installed in new repos by default:

# From a repo where Fit Commit is already installed
$ cp .git/hooks/commit-msg ~/.git_template/hooks/commit-msg

To copy your default hooks into existing repos:

$ git init

How can I run this standalone, like part of a CI process?

Fit Commit can be run outside of a Git hook context with a simple shell script:

$ export GIT_BRANCH_NAME=branch_name
$ export COMMIT_MESSAGE_PATH=path/to/message
# Using Bundler
$ bundle exec ruby -e 'require "fit_commit"; FitCommit.run'
# Not using Bundler
$ rbenv exec ruby -rrubygems -e 'require "fit_commit"; FitCommit.run'

It exits with an error code if any errors are present, which will fail a build if it's part of a CI run.

Who decided these rules?

Fit Commit aims to enforce community standards. The two influential guides are:

The Git community has largely (but not completely) coalesced around these standards. Chris Beams and the Pro Git book also provide good summaries on why we have them.

How can I improve Fit Commit?

Fit Commit aims to be useful to everyone. If you can suggest an improvement to make it useful to more people, please open a GitHub Issue or Pull Request. See CONTRIBUTING.md for more info.

Credits

Author: Mike Foley

Inspiration taken from: Tim Pope, Jason Fox, Addam Hardy, pre-commit

Similar projects:

fit-commit's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fit-commit's Issues

Skip Merge commits?

When looking at my git history I get things like:

commit 5e554e17435254f20aa8e1098bd5049726f707fb
Merge: 04d3c52 b200694
Author: Fabien Penso <XXX>
Date:   Tue Aug 24 06:15:05 2021 -0400

    Merge branch 'master' into fabien/be-1556-some-beam-objects-are-not-synced

because our branch names are long (based on linear which likes to create its own branch names). This is failing fit-commit, I think it should skip validation on any merge commits.

Option to reopen text editor

I do my commits in my preferred $EDITOR. When exiting $EDITOR to commit and fit-commit finds an issue I am forced to retype my commit and try the commit again.

My propsed solution would have an option along the lines of

Force commit? [y/n/e] 

With e for edit dropping you back into $EDITOR with the incorrect message to make the changes needed.

I am not no handy in ruby or I would hack away at it myself.

Errors vs Warnings

Hi,

Thanks for your work on making this tool easy to install and use. A colleague and I are planning on using it within our workflow for an upcoming project.

We are running into something really strange -- When I use a bad commit message I see what the Example shows in the readme. Errors and the ability to respond with y/n/e.

But when my colleague attempts to do the same thing - he gets warnings instead and no prompt with y/n/e. And the commit successfully goes through.

Do you have any ideas on what this could be? We are not using a custom config. We've compared versions and they are the same. We've tried uninstalling and reinstalling. We just can't figure out why I am seeing errors and he is seeing warnings.

Thanks!

Capitalize the subject line

Hi, this is an awesome project! Thank you for creating it.

It would be very nice if it also had validation against commit messages not starting with a capital letter though. In my experience, it is usually the thing that is the most inconsistent in other people's commit messages.

It is even recommend as one of the seven rules in the post you linked to: http://chris.beams.io/posts/git-commit/#capitalize

server-side support

It's great having client-side validation, but let's face it some developers will simply forget or be too lazy to set it up, and then they'll submit bad commits for review regardless. So ideally there should be a way to enforce validation server-side. Of course the implementation depends on the server in question, but GitHub might be a good place to start. For example might it be possible to create a GitHub third-party service which runs fit-commit server-side whenever a PR is submitted / updated, and then updates a status check on the PR accordingly?

See also codeclimate/spec#45 (allow analysis of commit messages)

Enable validations on all branches by default

Fit Commit was written with the assumption that feature branches are treated with more leniency than the "shared branches" (master by default). I think this distinction isn't very helpful because people have different workflows, and it's not a big deal to press y to approve lazy messages on non-shared branches.

Unable to use fitcommit with a GUI git client

Using RubyMine, I get the following error when attempting to commit:

Error:.git/hooks/commit-msg: line 38: /dev/tty: Device not configured

This is the same issue as described here:
http://stackoverflow.com/questions/17930805/github-gui-client-dev-tty-device-not-configured
And so it looks like it affects more than just Rubymine.

It would be nice if there was a non-interactive option, either auto-failing or auto-forcing with a warning in the face of an error, that did not make use of /dev/tty.

Apparent hang until hitting enter again

Nice work @m1foley

I've noticed something strange when running under MINGW32.

From the prompt if I commit using git commit -m "Fixes Something" and hit enter I get what appears to be a hang. It's not until I hit enter for a second time I see the results of fit-commit.

Here's a screen after hitting enter
image

Here's a screen after hitting enter for a second time.
image

Is there something prompting for a console input?

Allow more granular configuration overrides

This .pre_commit.yml should work:

---
Validators/LineLength:
  SummaryWarnLength: 72

That currently leads to an error because it expects Enabled to be specified again. Config properties should be merged more intelligently.

No such file or directory

I've installed fit-commit and tried to commit:

/Users/damirsvrtan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/fit-commit-1.0.1/lib/fit-commit/runner.rb:72:in `initialize': No such file or directory @ rb_sysopen -  (Errno::ENOENT)
    from /Users/damirsvrtan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/fit-commit-1.0.1/lib/fit-commit/runner.rb:72:in `open'
    from /Users/damirsvrtan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/fit-commit-1.0.1/lib/fit-commit/runner.rb:72:in `message_text'
    from /Users/damirsvrtan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/fit-commit-1.0.1/lib/fit-commit/runner.rb:68:in `relevant_message_lines'
    from /Users/damirsvrtan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/fit-commit-1.0.1/lib/fit-commit/runner.rb:64:in `lines'
    from /Users/damirsvrtan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/fit-commit-1.0.1/lib/fit-commit/runner.rb:80:in `empty_commit?'
    from /Users/damirsvrtan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/fit-commit-1.0.1/lib/fit-commit/runner.rb:17:in `run'
    from /Users/damirsvrtan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/fit-commit-1.0.1/lib/fit-commit.rb:5:in `run'
    from -e:11:in `<main>'

Adding custom validators

Hi,
ValidatorLoader#all_validators is only loading the files in the validators directory.
It would be great to have another directory to be able to define custom validators.

Why exit(1) if runner.run returns falsy?

  def self.run
    runner.run || exit(1)
  end

either runner.run should return the exit code or it should be more clear here why a falsy return is an error.

I'm happy to make a PR to change it, if you'd like.

rvm gives warning on commit

Whenever I do a commit, I get the following warning:

$ git commit -m 'test'
Warning! PATH is not properly set up, '/Users/$USER/.rvm/gems/ruby-2.2.3/bin' is not at first place,
         usually this is caused by shell initialization files - check them for 'PATH=...' entries,
         it might also help to re-add RVM to your dotfiles: 'rvm get stable --auto-dotfiles',
         to fix temporarily in this shell session run: 'rvm use ruby-2.2.3'.

My path is set up correctly, with the above line appearing first. However, if I echo $PATH from inside the .git/hooks/commit-msg file, i get:

/usr/local/Cellar/git/2.5.0/libexec/git-core:/usr/local/Cellar/git/2.5.0/libexec/git-core:/Users/$USER/.rvm/gems/ruby-2.2.3/bin...

Digging into this a little more, i found someone else had a very similar issue: rvm/rvm#2347

The suggested solution is to use ruby-rvm-env instead of rvm default do ruby as the command. I changed my local commit-msg hook, and it worked! No warning (yey).

If you like, I can submit a pull request to change this in the template.

Warning during rebase

If you make (or amend) any commits during an interactive rebase, you receive the following warning:

fatal: ref HEAD is not a symbolic ref
fit-commit: WARNING: Skipping checks because the Git branch cannot be determined.

Steps to reproduce:

  1. git rebase -i HEAD~1
  2. Change pick to edit for the commit shown
  3. git commit --amend (no need to change anything)
  4. Observe the warning.

It doesn't seem to cause any negative side-effects, aside from not actually catching any invalid commit messages.

Add customizable "business" branches, not just master

We currently disallow WIPs, etc. to master, but what we really mean is a "business" or "public" branch where you're interacting with other people. Not all workflows use master as this branch (e.g., the git-flow process) so it needs to be customizable.

Verb pedantry

Message must use present imperative tense.

Imperative describes a verb's mood, not its tense (present is its tense). However, I propose that what you're referring to is actually a bare infinitive (both have the same form, different functions). The commit message is not commanding someone to make a change—it serves as a description of the change already made—so I propose that something like "Fix bug #1111" is a noun phrase headed by an infinitive rather than being a finite clause.

Thoughts?

Proposed language:

Message must use an infinitive.

gitlint

It seems sir, that we had a very similar idea at a very similar time. I've had this in mind for a while, but started working on gitlint last week: https://github.com/jorisroovers/gitlint.

Still very early stages like fit-commit, but I think we can probably learn from one another and share some ideas/code :)

Line length check breaks on `commit -v`

When you use commit -v it displays the diff in an editor in the format

[commit area]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)
#
# Changes to be committed:
#	modified:   src/someeeeeeeeeeeeeeeeeee/long/__tests__/file-name.ts
#
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
diff --git a/src/someeeeeeeeeeeeeeeeeee/long/__tests__/file-name.ts b/src/someeeeeeeeeeeeeeeeeee/long/__tests__/file-name.ts
index de6616d..773896f 100644
--- a/src/someeeeeeeeeeeeeeeeeee/long/__tests__/file-name.ts
+++ b/src/someeeeeeeeeeeeeeeeeee/long/__tests__/file-name.ts
@@ -6,7 +6,7 @@ import {User} from "../../../services/users"
 import {Blah} from "../../../types/blah"
 
 const x: Blah = {
-  id: "id",
+  id: "something",
 }

fit-commit does not ignore lines below the # Everything below it will be ignored. line

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.