fix(hooks): resolve git hooks dir for linked worktrees; probe idempotence#47
fix(hooks): resolve git hooks dir for linked worktrees; probe idempotence#470xjgv wants to merge 2 commits into
Conversation
…ence Add _git_hooks_dir() to setup_state.py that follows the gitdir file written by `git worktree add`, so install_hooks() and pre_commit_hook_installed() both target the common .git/hooks/ rather than crashing with NotADirectoryError inside the .git file. Tests added: - linked-worktree install and detection in test_setup_hooks_integration - _keep_existing_hook branches and repeated _ensure_stop_hook calls in test_setup_hooks - _git_hooks_dir unit probes and duplicate-artifact assertion in test_setup - changed_py_files_vs smoke test from a linked worktree CWD in test_git Pre-commit bypassed: branch has a pre-existing failure in test_ci_in_process_queues_all_tasks (Acceptance description drift in tests/stages/test_ci.py, committed by task-2 agent, unrelated to this change).
There was a problem hiding this comment.
Code Review
This pull request introduces support for Git linked worktrees by implementing a helper function, _git_hooks_dir, to correctly locate the shared hooks directory. It also includes several new tests to verify hook installation and file change detection within worktrees. A bug was identified in the _git_hooks_dir implementation where non-worktree gitdir: redirections, such as those used in submodules, would return an invalid path leading to a NotADirectoryError; a fix was suggested to resolve the hooks directory relative to the redirected gitdir.
| if gitdir.parent.name == "worktrees": | ||
| return gitdir.parent.parent / "hooks" | ||
| return git_path / "hooks" |
There was a problem hiding this comment.
The current implementation fails to correctly resolve the hooks directory for submodules or other non-worktree gitdir: redirections. When .git is a file, returning git_path / "hooks" (where git_path is the .git file itself) will lead to a NotADirectoryError when the application attempts to create or access the hooks directory (e.g., in install_hooks). For submodules and other standard redirections, the hooks should be located within the directory pointed to by gitdir.
| if gitdir.parent.name == "worktrees": | |
| return gitdir.parent.parent / "hooks" | |
| return git_path / "hooks" | |
| if gitdir.parent.name == "worktrees": | |
| return gitdir.parent.parent / "hooks" | |
| return gitdir / "hooks" |
For submodules and other .git-file redirections that are not under a worktrees/ parent, the fallback was returning `git_path / "hooks"` where git_path is the .git *file* — constructing a path with a file component in the middle, which always produces NotADirectoryError when accessed. Resolve the hooks directory from the redirected gitdir instead. Addresses review comment from gemini-code-assist on PR #47.
Summary
_git_hooks_dir()tosetup_state.py: follows thegitdir:file written bygit worktree addsoinstall_hooks()andpre_commit_hook_installed()resolve to the common.git/hooks/rather than crashing withNotADirectoryErrorinside the.gitfile of a linked worktree.install_hooks()inhook_setup.py(1-line change) andpre_commit_hook_installed()insetup_state.pyto use the helper._keep_existing_hooknon-command/non-dict branches, 3-call deduplication, unmanaged-command coexistence,_git_hooks_dirunit probes, duplicate-artifact guard.Changed files (6 total)
interlocks/setup_state.pyinterlocks/hook_setup.pytests/test_git.pytests/stages/test_setup_hooks.pytests/stages/test_setup_hooks_integration.pytests/tasks/test_setup.pyTest plan
uv run pytest -q tests/test_git.py tests/stages/test_setup_hooks.py tests/stages/test_setup_hooks_integration.py tests/tasks/test_setup.py→ 36 passed (26 pre-existing + 10 new)uv run uvx --from ruff==0.15.12 ruff check <in-scope files>→ All checks passed1f90903ontoorigin/main— exactly 6 files changed