Git 2.54: Config-Based Hooks Replace Husky and Pre-Commit

Canonical version: Git 2.54: Config-Based Hooks Replace Husky and Pre-Commit.

Git 2.54 ships config-based hooks — the single most practical improvement in years for teams that care about code quality gates. If you've been managing Husky config files, pre-commit YAML, or manually copying hook scripts across repos, this replaces all of it.

What changed

Previously, git hooks lived only as executable scripts inside .git/hooks/. That folder is not tracked, not shareable, and not composable. Every tool in the ecosystem (Husky, pre-commit, Lefthook, etc.) existed to paper over this limitation.

Git 2.54 introduces configuration-based hooks. Define hooks in any git config file:

[hook "linter"]
  event = pre-commit
  command = ~/bin/linter --cpp20

This works in:

  • ~/.gitconfig — applies to every repo on your machine
  • /etc/gitconfig — system-wide, for all users
  • The repo's local .git/config or any included config file

Multiple hooks for the same event are supported and run in config-file order. The legacy hook scripts in .git/hooks/ still work and run last, so nothing breaks.

Management commands

# See all hooks configured for an event and where they come from
git hook list pre-commit

# Disable a hook without deleting it
git config hook.linter.enabled false

The git hook list output shows each hook's source (global, local, system), so you know exactly what runs and why.

What this replaces

  • Husky: npm package that installs hook shims into .git/hooks/. Requires package.json, runs only in Node projects.
  • pre-commit: Python-based hook manager with its own YAML config format and plugin ecosystem. Works across languages but requires Python + pip.
  • Lefthook, Overcommit, and every other third-party hook manager: all workarounds for the same underlying limitation.

With config-based hooks, you get the same capability with zero extra dependencies and zero extra config formats. A single ~/.gitconfig stanza and every repo on your machine benefits.

Practical setup

Enable a linter for every project without touching a single repo:

# ~/.gitconfig
[hook "style-check"]
  event = pre-commit
  command = ~/.local/bin/my-linter

[hook "security-scan"]
  event = pre-push
  command = ~/.local/bin/secret-scanner

To opt a specific repo out of the global hook:

# .git/config (repo-local)
[hook "security-scan"]
  enabled = false

Other notable changes in 2.54

  • git history (experimental): git history reword <commit> and git history split <commit> for targeted history rewriting without interactive rebase.
  • Geometric repacking by default: git maintenance run now uses the geometric strategy, avoiding expensive full repacks.
  • git add -p improvements: shows previous hunk decisions; adds --no-auto-advance flag.
  • git replay upgrades: atomic reference updates, --revert mode, root commit support.
  • HTTP 429 handling: new http.retryAfter config for rate-limited servers.
  • git log -L + pickaxe: -L now works with -S, -G, and other diff filters.

References


About Sébastien

Ready to get to the next level?

Found this valuable? Share it with someone who needs it.

Join 6,000+ readers. Get practical systems for knowledge & AI. Free.

Subscribe ✨

Free: Knowledge System Checklist

A clear roadmap to building your own knowledge system. Subscribe and get it straight to your inbox.

6,000+ readers. No spam. Unsubscribe anytime.

Subscribe