fix uninstall without -t to remove all pre-commit managed hooks

Previously, `pre-commit uninstall` without `-t` only removed hooks
listed in `default_install_hook_types` from the config. This meant
hooks installed with e.g. `-t pre-push` would not be removed unless
`-t pre-push` was explicitly passed to uninstall.

Now, when `-t` is not specified, uninstall scans all known hook types
and removes any that are managed by pre-commit (via `is_our_script`).

Fixes #364

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daisuke Sato 2026-03-11 19:11:07 +09:00
parent 8416413a0e
commit 16f7c46de5
2 changed files with 29 additions and 1 deletions

View file

@ -8,6 +8,7 @@ import sys
from pre_commit import git from pre_commit import git
from pre_commit import output from pre_commit import output
from pre_commit.clientlib import HOOK_TYPES
from pre_commit.clientlib import InvalidConfigError from pre_commit.clientlib import InvalidConfigError
from pre_commit.clientlib import load_config from pre_commit.clientlib import load_config
from pre_commit.repository import all_hooks from pre_commit.repository import all_hooks
@ -162,6 +163,10 @@ def _uninstall_hook_script(hook_type: str) -> None:
def uninstall(config_file: str, hook_types: list[str] | None) -> int: def uninstall(config_file: str, hook_types: list[str] | None) -> int:
for hook_type in _hook_types(config_file, hook_types): if hook_types is not None:
actual_hook_types = hook_types
else:
actual_hook_types = list(HOOK_TYPES)
for hook_type in actual_hook_types:
_uninstall_hook_script(hook_type) _uninstall_hook_script(hook_type)
return 0 return 0

View file

@ -1102,3 +1102,26 @@ def test_install_uninstall_default_hook_types(in_git_dir, store):
assert not uninstall(C.CONFIG_FILE, hook_types=None) assert not uninstall(C.CONFIG_FILE, hook_types=None)
assert not in_git_dir.join('.git/hooks/pre-commit').exists() assert not in_git_dir.join('.git/hooks/pre-commit').exists()
assert not in_git_dir.join('.git/hooks/pre-push').exists() assert not in_git_dir.join('.git/hooks/pre-push').exists()
def test_uninstall_without_t_removes_all_hooks(in_git_dir, store):
install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
install(C.CONFIG_FILE, store, hook_types=['pre-push'])
assert in_git_dir.join('.git/hooks/pre-commit').exists()
assert in_git_dir.join('.git/hooks/pre-push').exists()
assert not uninstall(C.CONFIG_FILE, hook_types=None)
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
assert not in_git_dir.join('.git/hooks/pre-push').exists()
def test_uninstall_without_t_ignores_non_precommit_hooks(in_git_dir, store):
install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
# write a non-pre-commit hook
in_git_dir.join('.git/hooks/pre-push').write('#!/bin/sh\necho custom\n')
assert in_git_dir.join('.git/hooks/pre-push').exists()
assert not uninstall(C.CONFIG_FILE, hook_types=None)
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
# non-pre-commit hook should be preserved
assert in_git_dir.join('.git/hooks/pre-push').exists()