hooks: never overwrite an existing hook without a backup; explain chaining

Commit

peyton-alt4d ago

When entire enable (or EnsureSetup on an agent turn) found a foreign hook while <hook>.pre-entire already existed, it overwrote the hook with only a warning. A hook restored by git checkout, edited by the user, or rewritten by a hook manager was lost, and the chain kept running the stale backup.

Now the current hook becomes the backup and the previous backup is kept as <hook>.pre-entire.<timestamp>. Identical content is replaced without rotation. When pre-commit keeps Entire's previous hook as <hook>.legacy, rotation is skipped: it would chain that copy into pre-commit's own wrapper and fail every commit. A backup carrying Entire's marker is never chained to (it would call itself), and the source is re-checked before each rename to guard against concurrent installs.

The backup message now says the user's hook still runs, where it went, and the order. entire disable --uninstall reports which hooks it restored and which older copies it left. README gains an "Existing git hooks" section and no longer says plain disable removes the hooks; enable/disable help and the filesystem-safety reference describe the behaviour.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com Entire-Checkpoint: 01M3XBY4G4NWAHA3G88DK39VMA

Checkpoints

Investigate Entire-Hosted and Agent Integration Issues

Claude CodeOpus 5.5
View session
Checkpoint 1