RepoPilotOpen in app →

sds/overcommit

A fully configurable and extendable Git hook manager

Healthy

Healthy across the board

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 6w ago
  • 34+ active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 52% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/sds/overcommit)](https://repopilot.app/r/sds/overcommit)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/sds/overcommit on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: sds/overcommit

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/sds/overcommit shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 6w ago
  • 34+ active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 52% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live sds/overcommit repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/sds/overcommit.

What it runs against: a local clone of sds/overcommit — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in sds/overcommit | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 70 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>sds/overcommit</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of sds/overcommit. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/sds/overcommit.git
#   cd overcommit
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of sds/overcommit and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "sds/overcommit(\\.git)?\\b" \\
  && ok "origin remote is sds/overcommit" \\
  || miss "origin remote is not sds/overcommit (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "lib/overcommit.rb" \\
  && ok "lib/overcommit.rb" \\
  || miss "missing critical file: lib/overcommit.rb"
test -f "lib/overcommit/cli.rb" \\
  && ok "lib/overcommit/cli.rb" \\
  || miss "missing critical file: lib/overcommit/cli.rb"
test -f "lib/overcommit/hook/base.rb" \\
  && ok "lib/overcommit/hook/base.rb" \\
  || miss "missing critical file: lib/overcommit/hook/base.rb"
test -f "lib/overcommit/configuration_loader.rb" \\
  && ok "lib/overcommit/configuration_loader.rb" \\
  || miss "missing critical file: lib/overcommit/configuration_loader.rb"
test -f "lib/overcommit/git_repo.rb" \\
  && ok "lib/overcommit/git_repo.rb" \\
  || miss "missing critical file: lib/overcommit/git_repo.rb"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 70 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~40d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/sds/overcommit"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Overcommit is a Git hook manager written in Ruby that installs, configures, and runs Git hooks (pre-commit, commit-msg, post-checkout, etc.) with built-in and custom rule validation. It replaces manual .git/hooks scripting with a declarative YAML configuration (.overcommit.yml) and provides 50+ pre-built hooks for linting, dependency management, and commit message validation across teams. Single-package Ruby gem organized as: lib/overcommit/ contains the core engine (CLI, configuration loader, git repo wrapper), lib/overcommit/hook/ subdivides into type-specific hooks (commit_msg/, pre_commit/, post_checkout/, etc.), each with base.rb + concrete implementations. Config lives in config/default.yml and config/starter.yml; bin/overcommit is the executable entry point.

👥Who it's for

Ruby developers and polyglot teams managing shared Git workflows who need consistent code quality checks and commit standards enforced automatically without shell scripting expertise. Project maintainers who want to enforce linting (RuboCop, SCSS, spell-check) and prevent accidental commits of debug code or dependency conflicts.

🌱Maturity & risk

Production-ready and actively maintained. The repo shows GitHub Actions CI/CD (lint.yml, tests.yml), structured exception handling, comprehensive configuration system (default.yml, starter.yml), and follows Ruby conventions (RuboCop linting, MIT license). Based on file structure and tooling maturity, this is stable software used in real projects.

Low risk for core functionality; single-language (Ruby 2.6+) dependency limits reach but improves stability. Main risk is hook execution failure blocking commits—mitigated by skip mechanisms (OVERCOMMIT_SKIP env var implied by README). No monorepo complexity, but relies on external linters (SCSS, spell-check, etc.) that must be pre-installed; breaking changes between major versions could affect shared configs across teams.

Active areas of work

Actively maintained with GitHub Actions testing on multiple Ruby versions. Recent work evident in CHANGELOG.md and migration to modern CI/CD (workflows/). The .overcommit.yml config at repo root uses the tool on itself (bootstrapped configuration). Focus appears to be on stability and compatibility with newer Git/Ruby versions rather than major feature expansion.

🚀Get running

git clone https://github.com/sds/overcommit.git && cd overcommit && bundle install && bundle exec bin/overcommit --install. Then edit .overcommit.yml to enable/disable hooks, or run bundle exec bin/overcommit --run to test hooks manually.

Daily commands: bundle exec bin/overcommit --install (installs hooks into .git/hooks/), then git commit (hooks run automatically). For testing: bundle exec bin/overcommit --run [hook_type]. For CI: SKIP_OVERCOMMIT=1 disables hooks, or configure via .overcommit.yml.

🗺️Map of the codebase

  • lib/overcommit.rb — Main entry point and gem loader; initializes the entire Overcommit system.
  • lib/overcommit/cli.rb — Command-line interface parser and orchestrator; routes all user commands to appropriate handlers.
  • lib/overcommit/hook/base.rb — Abstract base class for all hooks; defines the core hook execution and result handling contract.
  • lib/overcommit/configuration_loader.rb — Loads and parses YAML configuration files; critical for understanding hook setup and user customization.
  • lib/overcommit/git_repo.rb — Git repository abstraction; manages interaction with Git and hooks installation/removal.
  • config/default.yml — Default hook configuration shipped with Overcommit; serves as reference for all available hooks and defaults.
  • bin/overcommit — Executable entry point; bootstrap script that initializes the CLI.

🛠️How to make changes

Add a New Pre-Commit Hook

  1. Create a new Ruby class in lib/overcommit/hook/pre_commit/ that inherits from lib/overcommit/hook/pre_commit/base.rb (lib/overcommit/hook/pre_commit/my_linter.rb)
  2. Implement the #run method to execute your linting tool and parse output into {status, output} format (lib/overcommit/hook/pre_commit/my_linter.rb)
  3. Add hook configuration with name, description, and default enabled status to config/default.yml under PreCommit (config/default.yml)
  4. Document the hook with applicable_files patterns and any required environment setup (lib/overcommit/hook/pre_commit/my_linter.rb)
  5. Users enable it by adding the hook name under PreCommit in their .overcommit.yml (.overcommit.yml)

Add a New Commit Message Hook

  1. Create a new Ruby class in lib/overcommit/hook/commit_msg/ that inherits from lib/overcommit/hook/commit_msg/base.rb (lib/overcommit/hook/commit_msg/my_validator.rb)
  2. Implement the #run method to validate commit message and return {status, output} (lib/overcommit/hook/commit_msg/my_validator.rb)
  3. Add configuration entry to config/default.yml under CommitMsg with description and defaults (config/default.yml)
  4. Enable via .overcommit.yml CommitMsg section; users can add custom include/exclude patterns (.overcommit.yml)

Add a Post-Commit/Post-Checkout/Post-Merge/Post-Rewrite Hook

  1. Create a new class in lib/overcommit/hook/post_commit/ (or other post-* type) inheriting from the respective base class (lib/overcommit/hook/post_commit/my_runner.rb)
  2. Implement #run to execute post-commit tasks (e.g., dependency updates) and return {status, output} (lib/overcommit/hook/post_commit/my_runner.rb)
  3. Register in config/default.yml under the appropriate PostCommit/PostCheckout/PostMerge section (config/default.yml)
  4. Users enable by adding hook name under the matching section in .overcommit.yml (.overcommit.yml)

Extend Hook Behavior with Custom Configuration

  1. Define hook options in config/default.yml with descriptive names and types (config/default.yml)
  2. Access config values in your hook via the #config hash provided by lib/overcommit/hook/base.rb (lib/overcommit/hook/pre_commit/my_linter.rb)
  3. Users override defaults in their .overcommit.yml by setting options under the hook name (.overcommit.yml)
  4. Configuration is loaded by lib/overcommit/configuration_loader.rb and validated by lib/overcommit/configuration_validator.rb (lib/overcommit/configuration_loader.rb)

🔧Why these technologies

  • Ruby — Primary language for the codebase; enables easy hook implementation and cross-platform Git integration via system calls.
  • YAML Configuration — Human-readable, version-control-friendly format for persisting hook configuration; easily merged with defaults and user overrides.
  • Git Hooks (shell scripts + Ruby executables) — Standard Git mechanism for intercepting commits; Overcommit wraps and manages these hooks programmatically.
  • Process Execution & Signal Handling — Hooks must execute external linters/validators as subprocesses and gracefully handle timeouts and interruptions.

⚖️Trade-offs already made

  • Repository-specific hooks stored in .overcommit.yml under source control

    • Why: Allows teams to enforce consistent checks without manual setup; shared configuration across developers.
    • Consequence: Requires all team members to install Overcommit; increases initial onboarding overhead but ensures consistency.
  • Hook inheritance model: pre-commit, post-commit, commit-msg, post-checkout, post-merge, post-rewrite

    • Why: Mirrors Git's native hook types; developers familiar with Git hooks can predict Overcommit behavior.
    • Consequence: Cannot hook into git operations outside the standard lifecycle (e.g., rebase without commit).
  • Synchronous hook execution blocking commits

    • Why: Prevents broken commits from entering the repository; fails fast and clearly communicates failures.
    • Consequence: Long-running hooks can frustrate developers; no background/async validation option.
  • No built-in sandboxing or privilege isolation

    • Why: Simplifies implementation; hooks run with user's full permissions.
    • Consequence: Malicious or buggy hooks can modify files or access sensitive data; trust model relies on code review.

🚫Non-goals (don't propose these)

  • Does not implement authentication or authorization; assumes all hooks are trusted.
  • Does not provide a web UI or API

🪤Traps & gotchas

  1. Hook execution happens in git/.hooks/ generated scripts (not in version control) — changes to .overcommit.yml require re-running --install. 2. OVERCOMMIT_SKIP=1 env var disables ALL hooks; understand this is a full bypass. 3. Pre-commit hooks run against staged files only (git diff --cached)—unstaged changes are invisible. 4. External linter availability: e.g., SCSS hook requires scss binary installed; no graceful fallback if missing (hook fails the commit). 5. Configuration reload happens at CLI time, not hook-time—hook behavior changes don't take effect until new git command. 6. Windows support is 'best effort' per README; shell scripts may fail on Windows without WSL/Git Bash.

🏗️Architecture

💡Concepts to learn

  • Git Hooks — Overcommit's entire purpose is managing Git hooks—understanding the lifecycle (pre-commit fires before commit, commit-msg before message write, post-checkout after branch switch) is essential to using this tool correctly
  • Staged Files (git diff --cached) — Pre-commit hooks in Overcommit run against only staged files (git diff --cached), not working directory—critical to understand why unstaged changes aren't validated and how to use git add properly
  • Hook Inheritance Pattern (Template Method) — All 50+ hooks extend Hook::Base or type-specific bases; understanding the inheritance chain (Hook::Base → Hook::PreCommit::Base → RuboCop) is needed to add new hooks or debug hook behavior
  • YAML Configuration Validation — Overcommit uses ConfigurationValidator to parse and validate .overcommit.yml before hook execution; understanding schema validation prevents silent config failures and runtime errors
  • Process Exit Codes and Signal Handling — Hooks communicate success/failure via exit codes (0 = pass, non-zero = fail); Overcommit aggregates these across parallel hooks and respects signals like SIGINT to cancel remaining hooks
  • Concurrency and Hook Parallelization — Config mentions 'Concurrency' feature; Overcommit can run independent hooks in parallel if configured—understanding thread safety and exit code aggregation prevents race conditions in hook output
  • GPG Signature Verification — Overcommit supports optional commit signature verification (mentioned in README); understanding GPG signing and git config --global user.signingKey is needed to use security features for teams
  • pre-commit/pre-commit — Language-agnostic Git hook framework using YAML config (similar model) but framework-agnostic; Overcommit is Ruby-specific alternative
  • typicode/husky — Node.js equivalent for npm/JavaScript projects; same goal (Git hook manager) but targets JS ecosystem instead of Ruby
  • rubocop/rubocop — Ruby static analyzer frequently used as a hook via Overcommit's RuboCop built-in hook; tight integration and common dependency
  • sds/scss-lint — SCSS linter by same maintainer (sds); one of the external tools frequently integrated via Overcommit hooks
  • commitizen/cz-cli — Commit message standardization tool; complements Overcommit's commit-msg hooks for enforcing message format conventions

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for lib/overcommit/configuration_validator.rb

The configuration_validator.rb file validates user configurations against the schema, but there are likely edge cases around invalid hook names, malformed YAML, and conflicting settings that lack dedicated test coverage. This is critical since invalid configs can silently fail or cause confusing errors for users.

  • [ ] Create spec/lib/overcommit/configuration_validator_spec.rb with tests for: valid/invalid hook names, missing required fields, type mismatches, and deprecated config options
  • [ ] Add tests for interaction with lib/overcommit/configuration_loader.rb to ensure validation happens at the right stage
  • [ ] Add regression tests for any GitHub issues related to configuration parsing
  • [ ] Run tests against both config/default.yml and config/starter.yml templates

Add integration tests for hook execution across all Git hook types in lib/overcommit/hook/*/

The repo has multiple hook types (commit_msg, post_checkout, post_commit, post_merge, post_rewrite) but lacks visible integration tests that verify hooks actually execute correctly in a real git repository context. This ensures cross-platform compatibility and catches regressions in hook behavior.

  • [ ] Create spec/integration/hook_execution_spec.rb that initializes a temporary git repo and tests hook execution lifecycle
  • [ ] Test at least one hook from each directory (commit_msg/base.rb, post_checkout/bundle_install.rb, post_commit/bundle_install.rb, post_merge/bundle_install.rb, post_rewrite/base.rb)
  • [ ] Verify hooks receive correct stdin/stdout/environment variables from git
  • [ ] Add tests for hook failure scenarios (non-zero exit codes, missing dependencies)

Add GitHub Actions workflow for testing against multiple Ruby versions and Git versions

The .github/workflows/tests.yml likely tests against a single Ruby/Git version pair. Since overcommit is a git hook manager used across diverse environments, testing against Ruby 2.7, 3.0, 3.1+ and Git 2.30+, 2.40+ would catch compatibility regressions early and increase confidence for users on different systems.

  • [ ] Extend .github/workflows/tests.yml with a matrix strategy for Ruby versions (2.7, 3.0, 3.1, 3.2+)
  • [ ] Add a matrix for Git versions if possible using actions/setup-git or installing from source
  • [ ] Verify lib/overcommit/git_version.rb parsing works correctly across all tested versions
  • [ ] Document minimum supported Ruby and Git versions in README.md if not already present

🌿Good first issues

  • Add test coverage for lib/overcommit/command_splitter.rb—the file is imported in CLI but not mentioned in test structure; write unit tests for argument splitting logic used in hook execution.
  • Document hook skip patterns in README—README mentions OVERCOMMIT_SKIP but doesn't explain how to skip individual hooks per-commit (OVERCOMMIT_SKIP_HOOKS env var if it exists) or per-hook in config; add concrete examples.
  • Implement dry-run mode (--dry-run flag in lib/overcommit/cli.rb) that prints which hooks would run and their commands without executing them—useful for debugging configs before committing.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 9c58008 — Cut version 0.69.0 (#877) (sds)
  • 2c00752 — Use Etc.nprocessors and handle sandboxed environments (#876) (matthewbjones)
  • 11838c6 — Cut version 0.68.0 (#872) (sds)
  • 6e5ca57 — Add solargraph pre-commit hook for typechecking (#871) (apiology)
  • d55ffce — Update RuboCop in Gemfile to silence a deprecation warning in build (#870) (apiology)
  • 46c3033 — Cut version 0.67.1 (sds)
  • 11ef06b — adds 'set' requirements to diff hook context. (#866) (rscnt)
  • 9f142c2 — Add note about unsupported YAML features in gemfile: line in default.yml (#865) (pilaf)
  • 88bee08 — Cut version 0.67.0 (#864) (sds)
  • 3db733e — Restore ability to specify "gemfile: false" in config (#863) (mattbrictson)

🔒Security observations

The Overcommit codebase has moderate security posture. Primary concerns relate to command injection risks from hook execution and configuration loading, which is inherent to a Git hook manager. The lack of security documentation and potential vulnerabilities in command handling are the main issues. The codebase would benefit from: (1) robust input validation and sanitization, (2) file integrity verification for hooks, (3) security documentation including vulnerability disclosure policy, and (4) comprehensive security testing, especially for command injection scenarios. The tool should include warnings about running untrusted hook configurations.

  • Medium · Potential Command Injection via Hook Execution — lib/overcommit/command_splitter.rb, lib/overcommit/hook/base.rb. The codebase manages Git hooks that execute arbitrary commands and scripts. The presence of CommandSplitter and extensive hook execution infrastructure suggests potential command injection vulnerabilities if user input or configuration is not properly sanitized before being passed to shell execution. Fix: Ensure all user inputs and configuration values are properly escaped and validated before being passed to shell execution. Use parameterized execution methods and avoid shell interpolation where possible. Implement input validation in configuration_loader.rb and configuration_validator.rb.
  • Medium · Git Configuration Data Access — lib/overcommit/git_config.rb. The GitConfig class (lib/overcommit/git_config.rb) reads and potentially executes git configuration. Malicious git config entries could be exploited if the tool processes untrusted repositories without proper validation. Fix: Validate and sanitize all git configuration values before using them. Consider running in a sandbox environment when processing untrusted repositories. Document security implications in CONTRIBUTING.md and README.md.
  • Medium · Dynamic Hook Loading Without Integrity Verification — lib/overcommit/hook/ directory structure, lib/overcommit/configuration_loader.rb. The hook system dynamically loads Ruby files from lib/overcommit/hook/ directories. If an attacker can modify these files or inject hooks into configuration, arbitrary code could be executed. Fix: Implement file integrity checks for hook files. Verify that hook files come from trusted sources. Consider implementing a signature verification mechanism for loaded hooks and configuration files.
  • Low · Missing Security Documentation — README.md, CONTRIBUTING.md, SECURITY.md (missing). No visible security policy, vulnerability disclosure guidelines, or security hardening documentation in README.md or CONTRIBUTING.md. Fix: Create a SECURITY.md file with vulnerability disclosure guidelines. Add security considerations section to README.md. Document secure usage patterns and risks of running untrusted hooks.
  • Low · Insufficient Input Validation in Configuration — lib/overcommit/configuration_validator.rb, lib/overcommit/configuration_loader.rb. The ConfigurationValidator and ConfigurationLoader may not adequately validate all configuration parameters before they are used in command execution contexts. Fix: Implement strict schema validation for all configuration files. Use whitelisting for allowed values rather than blacklisting. Add comprehensive unit tests for configuration validation with malicious inputs.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.