Skip to content

ci(hooks): run pre-commit hooks inside git worktrees - #19945

Open
vlad-scherbich wants to merge 3 commits into
mainfrom
vlad/hooks-worktree-hooks-path
Open

ci(hooks): run pre-commit hooks inside git worktrees#19945
vlad-scherbich wants to merge 3 commits into
mainfrom
vlad/hooks-worktree-hooks-path

Conversation

@vlad-scherbich

@vlad-scherbich vlad-scherbich commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Description

This PR does not sit on #19928. It is on main. hooks/autohook.sh install writes into $(git rev-parse --git-common-dir)/hooks instead of $repo_root/.git/hooks (a file in a worktree), and drops a relative core.hooksPath from repo-scoped git config.

Git resolves a relative hooksPath against the worktree root. .git/hooks therefore does not exist in a worktree, so 02-run-mypy never ran and typing failures reached CI.

Testing

hooks/tests/test-autohook-worktree.sh builds a throwaway repo + worktree, sets core.hooksPath=.git/hooks on the common config, runs install from the worktree, and checks the common hooks dir plus the unset. scripts/lint hook-tests is green.

Risks

install unsets only a relative core.hooksPath in repo-scoped config files. Absolute and --global values are left alone.

Additional Notes

No release note: contributor hook install, changelog/no-changelog.

If this PR merges and nothing else lands, worktree commits start running the existing pre-commit hooks after hooks/autohook.sh install.

@vlad-scherbich vlad-scherbich added the changelog/no-changelog A changelog entry is not required for this PR. label Aug 28, 2026
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 10a7991 | Docs | View more details | Give us feedback!

@vlad-scherbich vlad-scherbich changed the title fix(hooks): run pre-commit hooks inside git worktrees ci(hooks): run pre-commit hooks inside git worktrees Aug 28, 2026
@vlad-scherbich
vlad-scherbich requested a lite review from Copilot August 28, 2026 22:31
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codeowners resolved as

Resolved from the full PR diff against main using the target branch CODEOWNERS file.
CODEOWNERS team requests not listed below are not required by the current file set.

hooks/README.md                                                         @DataDog/python-guild
hooks/autohook.sh                                                       @DataDog/python-guild
hooks/tests/test-autohook-worktree.sh                                   @DataDog/python-guild

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the contributor Git hook installer to work correctly from git worktree checkouts by installing hooks into the shared/common Git directory and removing repo-scoped relative core.hooksPath overrides that break hook resolution in worktrees.

Changes:

  • Install hook symlinks into $(git rev-parse --git-common-dir)/hooks so one install covers the main checkout and all worktrees.
  • Remove repo-scoped relative core.hooksPath entries (common + worktree config) to prevent hooks being silently skipped in worktrees.
  • Add a worktree-focused install test script and expand documentation with troubleshooting guidance.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
hooks/autohook.sh Install hooks into the shared Git hooks directory and drop relative core.hooksPath overrides.
hooks/tests/test-autohook-worktree.sh Adds a regression test covering install behavior when executed from a worktree.
hooks/README.md Updates install description and adds troubleshooting for worktree hook skipping.
Suppressed comments (1)

hooks/README.md:202

  • This section explains that .git/hooks won’t exist in a worktree, but other troubleshooting steps in this README still instruct users to inspect .git/hooks/. Adding a pointer to git rev-parse --git-path hooks here helps users find the effective hooks directory from either a main checkout or a worktree.
Make them executable if needed:
```bash
chmod +x hooks/post-merge/*
chmod +x hooks/post-checkout/*
chmod +x hooks/scripts/*

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread hooks/autohook.sh
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 28, 2026

Copy link
Copy Markdown

Circular import analysis

⚠️ Existing circular imports

There are 3 circular imports that already exist on the base branch and have not been changed by this PR.

ddtrace.llmobs -> ddtrace.llmobs._evaluators -> ddtrace.llmobs._evaluators.format -> ddtrace.llmobs._experiment -> ddtrace.llmobs
ddtrace.errortracking._handled_exceptions.bytecode_injector -> ddtrace.errortracking._handled_exceptions.callbacks -> ddtrace.errortracking._handled_exceptions.collector -> ddtrace.errortracking._handled_exceptions.bytecode_reporting -> ddtrace.errortracking._handled_exceptions.bytecode_injector
ddtrace.appsec._asm_request_context -> ddtrace.appsec._iast._iast_request_context_base -> ddtrace.appsec._iast._iast_env -> ddtrace.appsec._iast.reporter -> ddtrace.appsec._exploit_prevention.stack_traces -> ddtrace.appsec._asm_request_context

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 28, 2026

Copy link
Copy Markdown

Dependency direction analysis

⚠️ Existing dependency direction violations

There are 240 dependency direction violations that already exist on the base branch and have not been changed by this PR.

Show existing violations (showing 5 of 240 highest severity)
ddtrace.internal.tracemethods -×-> ddtrace.trace  (internal-core -> product:tracing, score=135)
ddtrace.internal.ci_visibility.git_client -×-> ddtrace.trace  (product:ci_visibility -> product:tracing, score=133)
ddtrace.appsec._contrib.flask -×-> ddtrace.trace  (product:appsec -> product:tracing, score=133)
ddtrace.debugging._exception.replay -×-> ddtrace.trace  (product:debugging -> product:tracing, score=133)
ddtrace.llmobs._integrations.vertexai -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)

To see all violations, download the layers-base.json and layers-pr.json artifacts from this CI job and run:

uv run --script scripts/import-analysis/layers.py compare layers-base.json layers-pr.json

@vlad-scherbich
vlad-scherbich changed the base branch from vlad/py315-current-py-version to main August 28, 2026 22:48
@vlad-scherbich
vlad-scherbich force-pushed the vlad/hooks-worktree-hooks-path branch from 4e27334 to 10a7991 Compare August 28, 2026 22:48
@vlad-scherbich
vlad-scherbich requested a lite review from Copilot August 29, 2026 17:04
@vlad-scherbich
vlad-scherbich marked this pull request as ready for review August 29, 2026 17:04
@vlad-scherbich
vlad-scherbich requested a review from a team as a code owner August 29, 2026 17:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread hooks/autohook.sh
Comment on lines +68 to +75
if [[ $configured == /* ]]
then
echo "core.hooksPath in $scope_file is '$configured'; leaving it alone."
continue
fi
git config --file "$scope_file" --unset-all core.hooksPath
echo "Removed relative core.hooksPath ('$configured') from $scope_file; it never resolves inside a worktree."
done

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 10a79914e2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread hooks/autohook.sh
git_common_dir="$1"
git_dir=$(cd "$(git rev-parse --git-dir)" && pwd)
# Repo-scoped files only; leave absolute / --global hooksPath alone.
for scope_file in "$git_dir/config" "$git_common_dir/config"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Inspect the per-worktree config file

When extensions.worktreeConfig is enabled and core.hooksPath=.git/hooks was set with git config --worktree, Git stores it in $GIT_DIR/config.worktree, as described by the --worktree documentation. This loop instead checks $git_dir/config, so the override survives installation and commits in that worktree continue silently skipping the newly installed common hooks; include config.worktree when removing the broken override.

Useful? React with 👍 / 👎.

Comment thread hooks/autohook.sh
[[ -f $scope_file ]] || continue
configured=$(git config --file "$scope_file" --get core.hooksPath 2>/dev/null) || continue
[[ -n $configured ]] || continue
if [[ $configured == /* ]]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve valid relative hook paths

When a repository intentionally sets a relative path such as core.hooksPath=.githooks, this condition treats it as broken and deletes it, even though Git documents that core.hooksPath may be relative and resolves it relative to the directory where hooks run (githooks documentation). Such a tracked path works across worktrees, so installation now permanently discards a valid custom hook configuration; restrict removal to the known-broken .git/hooks value rather than every non-absolute path.

Useful? React with 👍 / 👎.

Comment thread hooks/autohook.sh
Comment on lines +45 to 47
hooks_dir="$git_common_dir/hooks"
mkdir -p "$hooks_dir"
autohook_linktarget="../../hooks/autohook.sh"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Point shared hooks at the actual worktree script

When the checkout is attached to a bare repository or was created with git init --separate-git-dir—an option documented as placing the Git directory separately from the working tree (git-init documentation)—$git_common_dir is not <worktree>/.git. The symlink installed there still targets ../../hooks/autohook.sh, so it resolves relative to the bare/external Git directory instead of the current worktree and is left dangling; Git then silently skips the hook. Derive the target from the actual worktree root or use an absolute target.

Useful? React with 👍 / 👎.

printf '%s\n' '#!/bin/sh' 'exit 0' > "$REPO/hooks/pre-commit/00-noop"
chmod +x "$REPO/hooks/pre-commit/00-noop"
git -C "$REPO" add hooks
git -C "$REPO" commit -q -m init

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Isolate the setup commit from global Git configuration

When a developer has a global setting such as commit.gpgSign=true without an available test key, or a global core.hooksPath containing a blocking hook, this initial commit reads that configuration and the test exits before reaching any assertions. The later probe commits explicitly set GIT_CONFIG_GLOBAL=/dev/null and GIT_CONFIG_SYSTEM=/dev/null, but setup does not; apply the same isolation to the initial commit (or export it for the whole script) so scripts/lint hook-tests is independent of each developer's Git configuration.

Useful? React with 👍 / 👎.

Comment thread hooks/README.md
Comment on lines +13 to +15
This will create symlinks in the repository's shared hooks directory for all configured
hook types. Running it once covers the main checkout and every `git worktree` created
from it, so it does not need to be repeated per worktree.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update the remaining hook paths for worktrees

After documenting that installation covers linked worktrees, the later “Disabling Hooks Temporarily” and “Hook Not Running” sections still tell users to run chmod or ls on .git/hooks; in a linked worktree .git is a file, so every one of those commands fails with “Not a directory.” Update those examples to resolve the shared directory through git rev-parse --git-common-dir so the newly documented workflow is usable from a worktree.

AGENTS.md reference: AGENTS.md:L17-L17

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/no-changelog A changelog entry is not required for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants