entire and lefthook fight over the pre-push hook; session push gets silently disabled
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 5.1k
- Forks
- 475
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 178
Description
What happened?
In a repo that also uses lefthook to manage git hooks, entire and lefthook fight over .git/hooks/pre-push. After any change to lefthook.yml, lefthook silently reclaims the hook and entire's session-log-on-push stops working — with no error — until someone manually re-wraps it.
How the conflict arises
- lefthook installs and manages
pre-push. Its installed hooks self-sync on every run, gated by a checksum oflefthook.ymlstored in.git/info/lefthook.checksum. entire enable/entire configure --forcewraps the existing hook: it renames the currentpre-pushtopre-push.pre-entireand installs its own wrapper that runs the entire handler then chains down:
At this point both run on push — entire pushes session logs, then chains to lefthook. 👍# Entire CLI hooks if command -v entire >/dev/null 2>&1; then entire hooks git pre-push "$1" || true; else :; fi # Chain: run pre-existing hook "$(dirname "$0")/pre-push.pre-entire" "$@"- But whenever
lefthook.ymlchanges, lefthook's checksum goes stale. Its next self-sync (at the top of any lefthook-managed hook, e.g. the next commit'spre-commit) sees thatpre-pushis no longer its hook, backs entire's wrapper up topre-push.old, and reinstalls its own bare hook. entire's session push is now silently gone. - On the next
lefthook.ymlchange after that, lefthook also emits a recurring warning, because its earlier backup collides:sync hooks: ❌ could not replace the hook: can't rename pre-push to pre-push.old - file already exists
Why there is no clean user-side fix (verified on 0.7.3)
The natural fix — make lefthook the sole owner of pre-push and run entire's push as a lefthook job/script — is blocked:
entire configure --forcere-installs entire's pre-push wrapper even withpush_sessions: false→ you cannot stop entire owning the hook.entire hooks git pre-push <remote>is itself gated bypush_sessions(no-ops when off) → you cannot disable the wrapper and still call the handler from a lefthook script.entire configure --forcere-wraps whatever is atpre-pushwith no detection — if lefthook reclaimed it, entire silently wraps lefthook's bare hook again, with no idempotency check or "another manager owns this" warning.
The only local mitigation is a self-heal step that re-wraps after each re-sync, which still can't cover a push that happens with no intervening commit.
Proposed fixes (any one resolves it)
- Idempotent / manager-aware install — if
pre-pushalready chains topre-push.pre-entire(or contains entire's wrapper), don't blindly re-wrap; detect known managers (lefthook, husky, pre-commit,core.hooksPath). - Decouple handler from install — an option to install the handler behavior without owning the
pre-pushfile, so managers like lefthook can invokeentire hooks git pre-pushas a job/script. (Today--skip-push-sessionsdisables the handler too, defeating this.) - Register via the host manager — when lefthook is detected, register entire's push as a lefthook script (lefthook scripts receive the hook's
$@, including the remote) instead of taking the file. - Self-repair marker — let entire re-assert/repair its wrapper automatically so a reclaim heals without manual
entire configure --force.
Steps to reproduce
- A repo using lefthook with a
pre-push:section; runlefthook install. entire enable(wrapspre-push, chaining to lefthook).- Edit
lefthook.yml(any change) and make a commit or push. - lefthook's self-sync reclaims
pre-push; entire's session push silently stops (no error). Confirm withhead .git/hooks/pre-push— the entire wrapper is gone.
Entire CLI version
Entire CLI 0.7.3
OS and architecture
macOS 26.5, arm64 (Darwin 25.5.0)
Agent
claude code
Terminal
ghostty
Logs / debug output
Additional context
- lefthook 2.0.12;
.entire/settings.jsoncommitted (team-wide setup), so this affects every macOS dev on the team using entire. - The 0.7.3 pre-push wrapper added a
command -v entireguard (no-ops cleanly when entire is off-PATH) — good, but it does not address this ownership conflict. - Also reproduces across git worktrees, which share a single
.git/hooksdir. - No log output to attach: the failure is silent (entire's hook is simply removed; nothing is logged).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the hook installation behavior around .git/hooks/pre-push, entire enable, and entire configure --force, then reproduce the conflict using lefthook.yml and lefthook install. Trace how the existing hook is renamed and chained, and verify that a lefthook sync preserves Entire's session push without backup collisions or silent removal.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100