repowise-dev / repowise-dev/repowise
[Bug] repowise uninstall never removes the post-commit hook that init installs
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 6.7k
- Forks
- 711
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 439
Description
Summary
repowise uninstall does not list or remove the git post-commit hook, although repowise init is one of the two things that installs it.
packages/cli/src/repowise/cli/uninstall/inventory.py:20-34 declares the four groups the plan enumerates:
class Group(StrEnum):
AGENTS = "agents"
REPO_FILES = "repo-files"
INDEX = "index"
GLOBAL = "global"
.git/hooks/post-commit is in none of them. Grepping the module for post-commit returns nothing.
repowise.cli.hooks.uninstall has exactly one caller in the tree:
packages/cli/src/repowise/cli/commands/hook_cmd.py:102
from repowise.cli.hooks import uninstall
which is the explicit repowise hook uninstall. Meanwhile init installs it at packages/cli/src/repowise/cli/commands/init_cmd/_interactive.py:239.
Consequence
A user runs repowise init, accepts the post-commit hook when offered, later runs repowise uninstall --all, and the marker block stays in .git/hooks/post-commit. Nothing in the output mentions it.
The block is inert once the index is gone, because it gates on [ -f "$ROOT/.repowise/state.json" ] (packages/cli/src/repowise/cli/hooks.py:74), so nothing breaks. The problem is the claim rather than the behaviour. The module docstring at inventory.py:1-9 is explicit about what it is for:
The full inventory of what repowise has written, computed without writing. This module is the trust claim. [...] So the plan enumerates every path in every group, present or not, and carries for each either the action a run would take or the reason it would not.
A path that install writes and uninstall neither removes nor names is the one outcome that design rules out. Item already carries a blocked field for exactly the case where a path is listed and deliberately not touched, so the shape for an honest answer is already there.
The pattern this belongs to
Three uninstall paths currently leave behind something their install wrote. The other two are #2470 (the Claude Code target leaves an env pin and two permission rules) and #2471 (hook rewrite uninstall leaves a repo config flag and, on some machines, an AGENTS.md block). They are separate files and separate commands, but a contributor picking up one may want to read the other two, since the question in each case is the same: what did install write that uninstall does not account for?
Done looks like
.git/hooks/post-commit appears in the plan under REPO_FILES, with either the removal a run would perform or the reason it would not. Removing the repowise block while preserving any other hook content is already implemented in hooks.uninstall (hooks.py:366-391, including the "removed (other hook content preserved)" branch), so this is wiring rather than new logic.
Worth deciding in the same pass: whether removal belongs under REPO_FILES or under a group of its own. The hook lives in .git/, which is neither the repo's own tracked files nor .repowise/, and a user who wants the index gone but the auto-sync hook kept is not an obviously wrong user.
Scope note
Verified against current main by reading the inventory groups, grepping for every caller of hooks.uninstall, and confirming init installs it. I did not run repowise uninstall, and I did not check whether the workspace uninstall path differs.
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 packages/cli/src/repowise/cli/uninstall/inventory.py:20-34 and compare its groups with init installation at commands/init_cmd/_interactive.py:239. Read hooks.py:74 and 366-391, plus the hook uninstall caller in commands/hook_cmd.py:102. Done means the post-commit path is represented in the uninstall plan with its removal action or a stated reason it is blocked, while preserving other hook content.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, python
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 74/100