entireio / entireio/cli

Re-install discards another tool's newer hook and chains to a stale .pre-entire backup

Open
#2,237 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
5.1k
Forks
475
Avg merge
1d 11h
Merged PRs (30d)
178

Description

What happened?

When another tool that manages git hooks reinstalls its hook at a name Entire wraps (commit-msg, prepare-commit-msg, post-commit, pre-push, post-rewrite), the next Entire hook install discards that tool's new hook and chains to the old copy in <hook>.pre-entire. Git then runs the stale copy on every commit. The only signal is one stderr line, which is invisible when the reinstall happens through the agent-hook self-heal path (EnsureSetup on user-prompt-submit) rather than an interactive entire enable.

Where it comes from (cmd/entire/cli/strategy/hooks.go, InstallGitHook, at fce049c):

if existingErr == nil && !strings.Contains(string(existing), entireHookMarker) {
    if !backupExists {
        os.Rename(hookPath, backupPath)          // first install: back up the foreign hook
    } else {
        fmt.Fprintf(os.Stderr, "[entire] Warning: replacing %s (backup %s%s already exists from a previous install)\n", ...)
        // the foreign hook now at hookPath is overwritten below and never saved
    }
    backupExists = true
}

TestInstallGitHook_DoesNotOverwriteExistingBackup pins this: the backup is never refreshed once it exists. That protects the first backup, but it means the file at the hook name, which is the other tool's current hook, is the one that gets lost. The chain then runs whatever the other tool installed at the time of the first Entire install, forever.

This is the mirror image of #1349: there, the other tool reclaims the name and Entire's wrapper is lost; here, Entire reclaims the name and the other tool's newer hook is lost, silently replaced by an older version of itself.

Steps to reproduce
git init -q -b main repro && cd repro
git commit -q --allow-empty -m init

# another tool installs its hook (v1)
printf '#!/bin/sh\necho "tool A v1 ran" >> "$(git rev-parse --git-dir)/hook-log"\n' > .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

entire enable --agent claude-code --no-github --local
# -> "[entire] Backed up existing commit-msg to commit-msg.pre-entire"   (correct)

# the other tool reinstalls a newer hook (v2), replacing Entire's wrapper
printf '#!/bin/sh\necho "tool A v2 ran" >> "$(git rev-parse --git-dir)/hook-log"\n' > .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

entire enable --force --agent claude-code --no-github --local
# -> "[entire] Warning: replacing commit-msg (backup commit-msg.pre-entire already exists from a previous install)"

tail -1 .git/hooks/commit-msg.pre-entire   # still v1
git commit -q --allow-empty -m probe
cat .git/hook-log                           # "tool A v1 ran"  <- v2 is gone

Expected: after the second install, the chain runs v2 (the hook that was actually at the name), or Entire refuses to overwrite a foreign hook while a backup exists and says what to do.

Suggested fix, either of:

  • When the file at the hook name has no Entire marker and differs from the existing backup, replace the backup with it before installing the wrapper (the backup should hold the most recent foreign hook, not the first one ever seen). Keep the current behaviour only when the two are byte-identical.
  • Or: never overwrite a foreign hook while a backup exists; print the warning and skip that name, so nothing is lost and the user can resolve it.

Also worth surfacing in entire doctor / entire status: "hook <name> is chained to a backup that no longer matches what another tool last installed".

Entire CLI version

Entire CLI 0.10.3

OS and architecture

Darwin 25.6.0 arm64

Additional context

Reproduced with the exact commands above on a fresh repository; nothing project-specific is involved. Git 2.50.1.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in cmd/entire/cli/strategy/hooks.go at InstallGitHook and run TestInstallGitHook_DoesNotOverwriteExistingBackup, then reproduce the two-install sequence from the issue with a foreign commit-msg hook. Done means a newer foreign hook is not silently discarded: the chain runs the hook currently at the name, or installation refuses that name with clear guidance.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, go
Domain
cli, devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.