Skip to content

Comparison

GitHooks, GrumPHP and CaptainHook all manage git hooks for PHP projects and can run the same QA tools. They differ mainly in how they are distributed and configured — design choices that are unlikely to change, unlike individual features, which all three projects add over time.

Note

This page compares structural design, not a feature-by-feature scorecard (those age badly and rarely decide a real choice). Written against GitHooks 3.4, GrumPHP 2.x and CaptainHook 5.x — verify the current state of each project before deciding.

Structural differences

GitHooks GrumPHP CaptainHook
Distribution Standalone .phar Composer dependency Composer dependency
Dependency isolation The .phar bundles its own dependencies, so they never clash with your project's Shares your project's Composer dependencies Shares your project's Composer dependencies
Configuration PHP file, declarative (type + keywords) YAML, task-based JSON, with PHP action classes or shell commands
Git events All events Pre-commit oriented All events
Extensibility Built-in tool types + a custom type that runs any command Plugin/extension ecosystem PHP action classes + plugins

The headline structural choice is the first row: GitHooks ships as a standalone .phar that embeds its own dependencies, while GrumPHP and CaptainHook install as Composer dev-dependencies of your project. That single decision drives the dependency-isolation difference and most of the trade-offs below.

What's distinctive about GitHooks

Beyond distribution, these are the capabilities GitHooks is built around. They are described here as design intent, not as a checklist against the others:

  • Execution modesfull, --fast (staged files), --fast-branch (branch diff) and --fast-dirty (the unified working tree, useful for AI agentic hooks). See Execution Modes.
  • Thread budgetprocesses is an absolute core ceiling distributed across tools that support internal parallelism, with optional per-job reservations and flow-level time / memory budgets. See Parallel execution.
  • Declarative flows — group jobs into named flows with intra-flow dependencies (needs), per-branch execution (on) and per-entry admission rules (only-files / exclude-files), so the flow declaration carries the policy instead of the CI YAML. See Flows.
  • Structured output — JSON v2, JUnit, SARIF 2.1.0 and Code Climate, with multi-report in a single run, for CI dashboards and automation. See Output formats.

Choosing between them

Choose GitHooks when dependency isolation matters (the .phar never touches your composer.json resolution), when you want a single declarative config that drives both local hooks and CI, or when you need the execution modes / thread budgeting / structured output above.

Consider GrumPHP when you rely on its plugin ecosystem — it ships extensions for commit-message conventions, file-size checks, security audits and more. If a specific extension covers your need out of the box, that is a real convenience. (GitHooks' custom type can run any command, so most gaps are bridgeable, but you write the glue.)

Consider CaptainHook when your hooks need sophisticated PHP logic. CaptainHook actions are PHP classes, which gives you the full language for conditions and side effects — more than a declarative config or a shell command expresses comfortably.

All three are mature and actively maintained; none is a wrong choice. The deciding factor is usually the distribution model (isolated .phar vs Composer dependency) and the configuration style that fits your team.

Migration guides

If you are moving from one of the others: