Dependencies
Some hooks have third-party dependencies. For example, to lint your SCSS files, you’re going to need the 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.
If you are using Bundler to manage your Ruby gem dependencies, you’ll likely
want to use the gemfile
option to control which gem versions are
available during your hook runs.
Automatically Install Overcommit Hooks
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.
Skipping Hooks
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
If you would prefer to specify a whitelist of hooks rather than a blacklist, use
the ONLY
environment variable instead.
ONLY=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
attempt to skip it, you’ll see a warning telling you that the hook is required,
and the hook will still run.
Disabling Overcommit
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
Disabling Colorized Output
Overcommit automatically colorizes its output based on whether it is outputting
to a TTY. However, you can manually enable/disable color by setting the
OVERCOMMIT_COLOR
environment variable.
OVERCOMMIT_COLOR=0 git commit
Continuous Integration
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.
Configuration
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 hooks, you can add the following to your repo-specific configuration file:
PreCommit:
RuboCop:
enabled: true
command: ['bundle', 'exec', 'rubocop'] # Invoke within Bundler context
Additionally, you may wish to have repo-specific configurations that are local to your computer that are not part of the shared repo config.
Adding a .local-overcommit.yml
file in the top-level directory of the repository adds another configuration file. This file works the same as .overcommit.yml
.
Adding this to ignored files in a git repo will allow you to have a local configuration per repo.
Hook Categories
Hook configurations are organized into categories based on the type of hook. So
pre-commit
hooks are located under the PreCommit
option, and post-commit
hooks are located under PostCommit
. See the
default configuration for a thorough example.
The ALL
Hook
Within a hook category, there is a special type of hook configuration that
applies to all hooks in the category. This configuration looks like a normal
hook configuration, except it has the name ALL
:
PreCommit:
ALL:
problem_on_unmodified_line: warn
requires_files: true
required: false
quiet: false
SomeHook:
enabled: true
...
The ALL
configuration is useful for when you want to
DRY up your
configuration, or when you want to apply changes across an entire category of
hooks.
Note that array configuration options (like include
/exclude
) in the
special ALL
hook section are not merged with individual hook configurations
if custom ones are defined for the hook.
Any custom configuration option for include
/exclude
will replace the ALL
hook’s configuration. If you want to have a global list of default exclusions
and extend them with a custom list, you can use YAML references, e.g.
PreCommit:
ALL:
exclude: &default_excludes
- 'node_modules/**/*'
- 'vendor/**/*'
MyHook:
exclude:
- *default_excludes
- 'another/directory/in/addition/to/default/excludes/**/*'
Again, you can consult the default configuration for
detailed examples of how the ALL
hook can be used.
Gemfile
You may want to enforce the version of Overcommit or other gems that you use in
your git hooks. This can be done by specifying the gemfile
option in your
.overcommit.yml
.
The gemfile
option tells Overcommit to load the specified file with
Bundler, the standard gem dependency manager for Ruby.
This is useful if you would like to:
- Enforce a specific version of Overcommit to use for all hook runs (or to use a version from the master branch that has not been released yet)
- Enforce a specific version or unreleased branch is used for a gem you want to use in your git hooks
Loading a Bundler context necessarily adds a startup delay to your hook runs
as Bundler parses the specified Gemfile
and checks that the dependencies are
satisfied. Thus for projects with many gems this can introduce a noticeable
delay.
The recommended workaround is to create a separate Gemfile
in the root of
your repository (call it .overcommit_gems.rb
), and include only the gems that
your Overcommit hooks need in order to run. Generate the associated lock file
by running:
bundle install --gemfile=.overcommit_gems.rb
…and commit .overcommit_gems.rb
and the resulting
.overcommit_gems.rb.lock
file to your repository. Set your gemfile
option
to .overcommit_gems.rb
, and you’re all set.
Using a smaller Gemfile containing only the gems used by your Overcommit hooks
significantly reduces the startup delay in your hook runs. It is thus the
recommended approach unless your project has a relatively small number of gems
in your Gemfile
.
Plugin Directory
You can change the directory that project-specific hooks are loaded from via
the plugin_directory
option. The default directory is .git-hooks
.
Quiet Hook Runs
If you prefer to have your hooks be completely silent unless there is a
problem, you can set the top-level quiet
option to true
. Note that if you
have many hooks or slow hooks this may not be desirable, as you don’t get
visual feedback indicating the general progress of the hook run.
Concurrency
Overcommit runs hooks in parallel by default, with a number of concurrent
workers equal to the number of logical cores on your machine. If you know your
particular set of hooks would benefit from higher/lower number of workers, you
can adjust the global concurrency
option. You can define single-operator
mathematical expressions, e.g. %{processors} * 2
, or %{processors} / 2
.
concurrency: '%{processors} / 4'
Note that individual hooks can specify the number of processors they require
with the processors
hook option. See the hook options
section for more details.
Signature Verification
You can disable manual verification of signatures by setting
verify_signatures
to false
. See the Security section for more
information on this option and what exactly it controls.
CommitMsg
commit-msg
hooks are run against every commit message you write before a
commit is created. A failed hook prevents a commit from being created. These
hooks are useful for enforcing policies on your commit messages, e.g. ensuring
a task ID is included for tracking purposes, or ensuring your commit messages
follow proper formatting guidelines.
*
CapitalizedSubject*
EmptyMessage- GerritChangeId
- HardTabs
- MessageFormat
- RussianNovel
*
SingleLineSubject- SpellCheck
*
TextWidth*
TrailingPeriod
PostCheckout
post-checkout
hooks run after a successful git checkout
, or in other words
any time your HEAD
changes or a file is explicitly checked out.
PostCommit
post-commit
hooks run after a commit is successfully created. A hook failing
in this case does not prevent the commit since it has already occurred;
however, it can be used to alert the user to some issue.
- BowerInstall
- BundleInstall
- Commitplease
- ComposerInstall
- GitGuilt
- IndexTags
- NpmInstall
- SubmoduleStatus
- YarnInstall
PostMerge
post-merge
hooks run after a git merge
executes successfully with no merge
conflicts. A hook failing in this case does not prevent the merge since it has
already occurred; however, it can be used to alert the user to some issue.
PostRewrite
post-rewrite
hooks run after a commit is modified by a git commit --amend
or git rebase
. A hook failing in this case does not prevent the rewrite since
it has already occurred; however, it can be used to alert the user to some
issue.
PreCommit
pre-commit
hooks are run after git commit
is executed, but before the
commit message editor is displayed. If a hook fails, the commit will not be
created. These hooks are ideal for syntax checkers, linters, and other checks
that you want to run before you allow a commit to even be created.
PrePush
pre-push
hooks are run during git push
, after remote refs have been updated
but before any objects have been transferred. If a hook fails, the push is
aborted.
- Brakeman
- FlutterTest
- Minitest
- PhpUnit
- Pronto
- ProtectedBranches
- PubTest
- Pytest
- PythonNose
- RakeTarget
- RSpec
- TestUnit
PreRebase
pre-rebase
hooks are run during git rebase
, before any commits are rebased.
If a hook fails, the rebase is aborted.
Repo-Specific hooks
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
specific repository.
For example, you can have a number of simple checks that run
against your code to catch common errors. For example, if you use
RSpec, you can 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.read(file) !~ /^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:
enabled: true
description: 'Checking for missing inclusion of spec_helper'
include: '**/*_spec.rb'
Adding Existing Git Hooks
You might already have hook scripts written which you’d like to integrate with Overcommit right away. To make this easy, Overcommit allows you to include your hook script in your configuration without writing any Ruby code. For example:
PostCheckout:
CustomScript:
enabled: true
required_executable: './bin/custom-script'
So long as a command is given (either by specifying the command
option
directly or specifying required_executable
) a special hook is created that
executes the command and appends any arguments and standard input stream that
would have been passed to the regular hook. The hook passes or fails based
on the exit status of the command.
The script is executed as if Git were calling the hook directly. If you want to understand which arguments are passed to the script depending on the type of hook, see the git-hooks documentation.
Security
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 your configuration and all hook plugin code since the last time it ran. 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.
Community
All major discussion surrounding Overcommit happens on the GitHub issues list.
Changelog
If you’re interested in seeing the changes and bug fixes between each version
of overcommit
, read the Overcommit Changelog.