overcommit
is a tool to manage and configure
Git hooks.
In addition to supporting a wide variety of hooks that can be used across multiple repositories, you can also define hooks specific to a repository (but unlike regular Git hooks, are stored with that repository).
Read more about Overcommit on our engineering blog.
- Requirements
- Installation
- Usage
- Configuration
- Built-In Hooks
- Repo-Specific Hooks
- Security
- Contributing
- Changelog
- License
This project aims to support the following Ruby runtimes:
- MRI 1.9.3 & 2.x
- JRuby 1.7.x
- Rubinius 2.x
Some of the hooks have third-party dependencies. For example, to lint your SCSS files, you're going to need our scss-lint gem.
Depending on the hooks you enable/disable for your repository, you'll need to ensure your development environment already has those dependencies installed. Most hooks will display a warning if a required executable isn't available.
overcommit
is installed as a binary via RubyGems:
gem install overcommit
You can then run the overcommit
command to install hooks into repositories:
mkdir important-project
cd important-project
git init
overcommit --install
If you want to use overcommit
for all repositories you create/clone going
forward, add the following to automatically run in your shell environment:
export GIT_TEMPLATE_DIR=`overcommit --template-dir`
The GIT_TEMPLATE_DIR
provides a directory for Git to use as a template
for automatically populating the .git
directory. If you have your own
template directory, you might just want to copy the contents of
overcommit --template-dir
to that directory.
Once you've installed the hooks via overcommit --install
, they will
automatically run when the appropriate hook is triggered.
The overcommit
executable supports the following command-line flags:
Command Line Flag | Description |
---|---|
-i /--install |
Install Overcommit hooks in a repository |
-u /--uninstall |
Remove Overcommit hooks from a repository |
-f /--force |
Don't bail on install if other hooks already exist--overwrite them |
-l /--list-hooks |
Display all available hooks in the current repository |
-r /--run |
Run pre-commit hook against all tracked files in repository |
-t /--template-dir |
Print location of template directory |
-h /--help |
Show command-line flag documentation |
-v /--version |
Show version |
Sometimes a hook will report an error that for one reason or another you'll want
to ignore. To prevent these errors from blocking your commit, you can include
the name of the relevant hook in the SKIP
environment variable, e.g.
SKIP=rubocop git commit
Use this feature sparingly, as there is no point to having the hook in the first
place if you're just going to ignore it. If you want to ensure a hook is never
skipped, set the required
option to true
in its configuration.
If you have scripts that execute git
commands where you don't want Overcommit
hooks to run, you can disable Overcommit entirely by setting the
OVERCOMMIT_DISABLE
environment variable.
OVERCOMMIT_DISABLE=1 ./my-custom-script
You can run the same set of hooks that would be executed in a pre-commit hook
against your entire repository by running overcommit --run
. This makes it
easy to have the checks verified by a CI service such as
Travis CI, including custom hooks you've written
yourself.
The --run
flag works by creating a pre-commit context that assumes all the
files in your repository have changed, and follows the same rules as a normal
pre-commit check. If any hook fails with an error, it will return a non-zero
exit code.
Overcommit provides a flexible configuration system that allows you to tailor
the built-in hooks to suit your workflow. All configuration specific to a
repository is stored in .overcommit.yml
in the top-level directory of the
repository.
When writing your own configuration, it will automatically extend the default configuration, so you only need to specify your configuration with respect to the default. In order to enable/disable the default hooks, you can add the following to your repo-specific configuration file:
PreCommit:
Rubocop:
enabled: false
Within a configuration file, the following high-level concepts exist:
-
Plugin Directory: allows you to specify the directory where your own Git hook plugins are stored (if you have project-specific hooks)
-
Hook type configuration (
PreCommit
,CommitMsg
, etc.): these categories each contain a list of hooks that are available for the respective hook type. One special hook is theALL
hook, which allows you to define configuration that applies to all hooks of the given type. -
Hook configuration: Within each hook category, an individual hook can be configured with the following properties:
enabled
: if false, this hook will not be enabledrequired
: if true, this hook cannot be skipped via theSKIP
environment variablequiet
: if true, this hook does not display anything unless it failsdescription
: text displayed when the hook is runningrequires_files
: whether this hook should run only if files have been modifiedinclude
: Glob patterns of files that apply to this hook (it will run only if a file matching the pattern has been modified--note that the concept of "modified" varies for different types of hooks)exclude
: Glob patterns of files that are ignored by this hookproblem_on_umodified_line
: How to treat errors reported on lines that weren't modified. Valid values arereport
(report errors/warnings as-is regardless of line location);warn
(report errors as warnings if they are on lines you didn't modify);ignore
(don't display errors/warnings at all if they are on lines you didn't modify--this option is not recommended)on_fail
: Allows you to change the status of a failed hook run to eitherwarn
orpass
(use this with care, as you are potentially hiding important information)on_warn
: Similar toon_fail
, change the status of hooks that return a warning to eitherpass
orfail
required_executable
: Name of an executable that needs to exist in order for the hook to runcommand
: Array of command line arguments to use as the command. How each hook uses this is different, but it ultimately allows hooks to customize how they are run so they can be invoked in a different context, for example runningbundle exec rubocop
instead of justrubocop
so you can use gem versions specified in your localGemfile.lock
flags
: Array of command line arguments to pass as the flags. This is useful for when a newer version of a tool removes/renames existing flags, so you can update the flags via your configuration and not wait on an upstream fix in Overcommitinstall_command
: Command the user can run to install therequired_executable
On top of the above built-in configuration options, each hook can support individual configuration. As an example, the
AuthorEmail
hook allows you to customize the regex used to check emails via thepattern
option, which is useful if you want to enforce developers to use a company email address for their commits.
Currently, Overcommit supports commit-msg
, pre-commit
, and post-checkout
hooks, but it can easily be expanded to support others.
You can see the full list of hooks by checking out the hooks directory, and view their default configuration.
Out of the box, overcommit
comes with a set of hooks that enforce a variety of
styles and lints. However, some hooks only make sense in the context of a given
repository.
At Causes, for example, we have a number of ad hoc Ruby checks that we run
against our code to catch common errors. For example, since we use
RSpec, we want to make sure all spec files contain the
line require 'spec_helper'
.
Inside our repository, we can add the file
.git-hooks/pre_commit/ensure_spec_helper.rb
in order to automatically check
our spec files:
module Overcommit::Hook::PreCommit
class EnsureSpecHelper < Base
def run
errors = []
applicable_files.each do |file|
if File.open(file, 'r').read !~ /^require 'spec_helper'/
errors << "#{file}: missing `require 'spec_helper'`"
end
end
return :fail, errors.join("\n") if errors.any?
:pass
end
end
end
The corresponding configuration for this hook would look like:
PreCommit:
EnsureSpecHelper:
description: 'Checking for missing inclusion of spec_helper'
include: '**/*_spec.rb'
You can see a great example of writing custom Overcommit hooks from the following blog post: How to Write a Custom Overcommit PreCommit Git Hook in 4 Steps
While Overcommit can make managing Git hooks easier and more convenient, this convenience can come at a cost of being less secure.
Since installing Overcommit hooks will allow arbitrary plugin code in your repository to be executed, you expose yourself to an attack where checking out code from a third party can result in malicious code being executed on your system.
As an example, consider the situation where you have an open source project.
An attacker could submit a pull request which adds a post-checkout
hook
that executes some malicious code. When you fetch and checkout this pull
request, the post-checkout
hook will be run on your machine, along with
the malicious code that you just checked out.
Overcommit attempts to address this problem by storing a signature of all hook plugins since the last time it ran the plugin. When the signature changes, a warning is displayed alerting you to which plugins have changed. It is then up to you to manually verify that the changes are not malicious, and then continue running the hooks.
The signature is derived from the contents of the plugin's source code itself
and any configuration for the plugin. Thus a change to the plugin's source
code or your local repo's .overcommit.yml
file could result in a signature
change.
In typical usage, your plugins usually don't change too often, so this warning shouldn't become a nuisance. However, users who work within proprietary repositories where all developers who can push changes to the repository already have a minimum security clearance may wish to disable this check.
While not recommended, you can disable signature verification by setting
verify_plugin_signatures
to false
in your .overcommit.yml
file.
We love getting feedback with or without pull requests. If you do add a new feature, please add tests so that we can avoid breaking it in the future.
Speaking of tests, we use rspec
, which can be run like so:
bundle exec rspec
If you're interested in seeing the changes and bug fixes between each version
of overcommit
, read the Overcommit Changelog.
This project is released under the MIT license.