From ba089950b480a55f80dfdec1203d4835eae94957 Mon Sep 17 00:00:00 2001 From: cinereal Date: Thu, 14 May 2026 16:26:05 +0200 Subject: [PATCH] feat: fall back to main worktree config in linked worktrees MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using `git worktree add`, the linked worktree inherits `core.hooksPath` (pointing at the common git dir's hooks) but not the untracked `.pre-commit-config.yaml` symlink — that symlink is only created on shell entry via `installationScript`. Until then every `git commit` in the linked worktree fails with "No .pre-commit-config.yaml file was found". After `pre-commit install` writes the hook scripts, patch each one to splice a prelude after the shebang and rewrite the `--config=` literal in the `ARGS=` line to read from a variable resolved by that prelude. At hook runtime the prelude resolves the config path: 1. The current toplevel's `cfg.configPath` if present. 2. Otherwise, only in a linked worktree (detected by comparing `git rev-parse --git-dir` against `--git-common-dir`), the main worktree's config. 3. Otherwise `exit 0`. Behavior in the main worktree is unchanged: a missing config there still produces pre-commit's normal error. A marker comment makes the patch idempotent across repeated shell entries. Fixes https://github.com/cachix/git-hooks.nix/issues/710 Assisted-by: Claude:claude-sonnet-4-6 --- modules/pre-commit.nix | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/modules/pre-commit.nix b/modules/pre-commit.nix index 75f71c11..763cd2d5 100644 --- a/modules/pre-commit.nix +++ b/modules/pre-commit.nix @@ -543,6 +543,37 @@ in # Convert the absolute path to a path relative to the toplevel working directory. common_dir=''${common_dir#''$GIT_WC/} + # Patch installed hook scripts to fall back to the main worktree's config in linked worktrees. + _prelude=$(mktemp) + cat > "$_prelude" <<'PRELUDE' + # git-hooks.nix: worktree-config-fallback + _git=${lib.getExe cfg.gitPackage} + _cfg_rel=${cfg.configPath} + _top=$("$_git" rev-parse --show-toplevel) + _config="$_top/$_cfg_rel" + if [ ! -e "$_config" ]; then + _dir=$("$_git" rev-parse --git-dir) + _common=$("$_git" rev-parse --path-format=absolute --git-common-dir) + if [ "$_dir" != "$_common" ]; then + _alt="$(dirname "$_common")/$_cfg_rel" + if [ -e "$_alt" ]; then + _config="$_alt" + else + exit 0 + fi + fi + fi +PRELUDE + for hook in ${concatStringsSep " " (remove "manual" supportedHooksLib.supportedHooks)}; do + hook_file="''${GIT_WC}/''${common_dir}/hooks/''${hook}" + [ -f "''${hook_file}" ] || continue + if ! grep -qF '# git-hooks.nix: worktree-config-fallback' "''${hook_file}"; then + sed -i "1r ''${_prelude}" "''${hook_file}" + sed -i 's|--config=${cfg.configPath}|--config="$_config"|' "''${hook_file}" + fi + done + rm -f "$_prelude" + ${lib.getExe cfg.gitPackage} config --local core.hooksPath "''$common_dir/hooks" fi fi