Skip to content

fix(hooks): resolve git hooks dir for linked worktrees; probe idempotence#47

Open
0xjgv wants to merge 2 commits into
mainfrom
unit5-hooks-clean
Open

fix(hooks): resolve git hooks dir for linked worktrees; probe idempotence#47
0xjgv wants to merge 2 commits into
mainfrom
unit5-hooks-clean

Conversation

@0xjgv

@0xjgv 0xjgv commented May 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add _git_hooks_dir() to setup_state.py: follows the gitdir: file written by git worktree add so install_hooks() and pre_commit_hook_installed() resolve to the common .git/hooks/ rather than crashing with NotADirectoryError inside the .git file of a linked worktree.
  • Update install_hooks() in hook_setup.py (1-line change) and pre_commit_hook_installed() in setup_state.py to use the helper.
  • 10 new tests across 4 files: linked-worktree install + detection, _keep_existing_hook non-command/non-dict branches, 3-call deduplication, unmanaged-command coexistence, _git_hooks_dir unit probes, duplicate-artifact guard.

Changed files (6 total)

  • interlocks/setup_state.py
  • interlocks/hook_setup.py
  • tests/test_git.py
  • tests/stages/test_setup_hooks.py
  • tests/stages/test_setup_hooks_integration.py
  • tests/tasks/test_setup.py

Test 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 passed
  • Clean cherry-pick of 1f90903 onto origin/main — exactly 6 files changed

…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).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread interlocks/setup_state.py Outdated
Comment on lines +95 to +97
if gitdir.parent.name == "worktrees":
return gitdir.parent.parent / "hooks"
return git_path / "hooks"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant