Skip to content

fix(install): honor repo-scoped core.hooksPath in worktrees#1673

Draft
schickling wants to merge 1 commit intoj178:masterfrom
schickling:schickling/worktree-safe-install-transactional
Draft

fix(install): honor repo-scoped core.hooksPath in worktrees#1673
schickling wants to merge 1 commit intoj178:masterfrom
schickling:schickling/worktree-safe-install-transactional

Conversation

@schickling
Copy link

Summary

  • keep the existing safety check for externally-scoped core.hooksPath (global/system), but allow install when core.hooksPath is set in repo scopes (--local or --worktree)
  • resolve install target with git rev-parse --path-format=absolute --git-path hooks when repo-scoped hooksPath is configured, so prek install writes to the effective hooks directory in linked worktrees
  • add install tests for local hooksPath and worktree-scoped hooksPath scenarios, including preserving a shared local hooksPath while installing into worktree hooks path

Why

Integrations using linked worktrees currently need custom wrapper logic around prek install due core.hooksPath handling. This change makes prek install work directly with repo-scoped hooksPath settings, reducing downstream complexity.

Refs: #1672

Verification

  • cargo test -p prek --test install install_with_core_hooks_path_set
  • cargo test -p prek --test install install_in_worktree_uses_worktree_hooks_path
  • HOME=/tmp/prek-test-home XDG_CONFIG_HOME=/tmp/prek-test-xdg cargo test -p prek --test install

Created by OpenCode on behalf of @schickling.

@codecov
Copy link

codecov bot commented Feb 19, 2026

Codecov Report

❌ Patch coverage is 97.67442% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 90.38%. Comparing base (8420c6e) to head (56e2c85).

Files with missing lines Patch % Lines
crates/prek/src/git.rs 97.29% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1673      +/-   ##
==========================================
- Coverage   91.64%   90.38%   -1.26%     
==========================================
  Files          96       96              
  Lines       18662    18704      +42     
==========================================
- Hits        17102    16905     -197     
- Misses       1560     1799     +239     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR makes prek install work correctly with Git worktrees and repo-scoped core.hooksPath configurations. Previously, prek would refuse to install when any core.hooksPath was detected. Now it distinguishes between externally-scoped (global/system) and repo-scoped (local/worktree) configurations, allowing the latter while still blocking the former for safety.

Changes:

  • Allow installation when core.hooksPath is set at local or worktree scope, while maintaining safety check for global/system scope
  • Use git rev-parse --git-path hooks to resolve the effective hooks directory when repo-scoped hooksPath is configured
  • Add comprehensive test coverage for local and worktree-scoped hooksPath scenarios

Reviewed changes

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

File Description
crates/prek/tests/install.rs Adds two new tests: one for local hooksPath and one for worktree-scoped hooksPath with shared config preservation
crates/prek/src/git.rs Adds get_git_hooks_dir() to resolve effective hooks directory and has_repo_hooks_path_set() to check for repo-scoped config
crates/prek/src/cli/install.rs Updates install logic to check for repo-scoped hooksPath and use get_git_hooks_dir() when appropriate
Comments suppressed due to low confidence (1)

crates/prek/src/cli/install.rs:49

  • The error message is misleading now that local and worktree-scoped core.hooksPath are allowed. The message suggests unsetting local hooksPath with git config --unset-all --local core.hooksPath, but local hooksPath is now intentionally supported by this PR. Consider updating the error message to clarify that only global/system scoped hooksPath is problematic, or provide more accurate guidance.
        anyhow::bail!(
            "Cowardly refusing to install hooks with `core.hooksPath` set.\nhint: Run these commands to remove core.hooksPath:\nhint:   {}\nhint:   {}",
            "git config --unset-all --local core.hooksPath".cyan(),
            "git config --unset-all --global core.hooksPath".cyan()
        );

Ok(())
}

#[test]
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

Missing test coverage for the safety check that prevents installation when global or system-scoped core.hooksPath is set. The existing tests only cover allowed scenarios (local and worktree scopes). Consider adding a test that sets global hooksPath and verifies that prek install still refuses to proceed with the "Cowardly refusing" error message. This ensures the safety mechanism isn't accidentally broken.

Suggested change
#[test]
#[test]
fn install_with_global_core_hooks_path_fails() -> anyhow::Result<()> {
let context = TestContext::new();
context.init_project();
git_cmd(context.work_dir())
.arg("config")
.arg("--global")
.arg("core.hooksPath")
.arg(".global-hooks")
.assert()
.success();
cmd_snapshot!(context.filters(), context.install(), @r#"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
Cowardly refusing to install hooks because `core.hooksPath` is set globally or system-wide.
"#);
Ok(())
}
#[test]

Copilot uses AI. Check for mistakes.
@prek-ci-bot
Copy link

prek-ci-bot bot commented Feb 19, 2026

📦 Cargo Bloat Comparison

Binary size change: +0.00% (23.8 MiB → 23.8 MiB)

Expand for cargo-bloat output

Head Branch Results

 File  .text    Size             Crate Name
 0.3%   0.8% 83.5KiB             prek? <prek::cli::Command as clap_builder::derive::Subcommand>::augment_subcommands
 0.3%   0.7% 71.3KiB              prek prek::languages::<impl prek::config::Language>::run::{{closure}}::{{closure}}
 0.3%   0.6% 65.6KiB              prek prek::languages::<impl prek::config::Language>::run::{{closure}}::{{closure}}
 0.2%   0.5% 51.2KiB annotate_snippets annotate_snippets::renderer::render::render
 0.2%   0.5% 50.5KiB              prek prek::languages::<impl prek::config::Language>::install::{{closure}}
 0.2%   0.4% 41.1KiB              prek prek::cli::run::run::run::{{closure}}
 0.2%   0.4% 39.3KiB              prek prek::run::{{closure}}
 0.1%   0.3% 31.6KiB             prek? <prek::cli::RunArgs as clap_builder::derive::Args>::augment_args
 0.1%   0.3% 28.5KiB      serde_saphyr saphyr_parser_bw::scanner::Scanner<T>::fetch_more_tokens
 0.1%   0.2% 24.2KiB             prek? <prek::config::_::<impl serde_core::de::Deserialize for prek::config::Config>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map
 0.1%   0.2% 22.8KiB      serde_saphyr saphyr_parser_bw::scanner::Scanner<T>::fetch_more_tokens
 0.1%   0.2% 22.6KiB              prek prek::hooks::meta_hooks::MetaHooks::run::{{closure}}
 0.1%   0.2% 21.1KiB      clap_builder clap_builder::parser::parser::Parser::get_matches_with
 0.1%   0.2% 20.8KiB              prek prek::hooks::meta_hooks::MetaHooks::run::{{closure}}
 0.1%   0.2% 20.0KiB   cargo_metadata? <cargo_metadata::_::<impl serde_core::de::Deserialize for cargo_metadata::Package>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map
 0.1%   0.2% 19.8KiB              prek prek::archive::unzip::{{closure}}
 0.1%   0.2% 19.3KiB               std core::ptr::drop_in_place<prek::languages::<impl prek::config::Language>::install::{{closure}}>
 0.1%   0.2% 19.2KiB              prek <prek::languages::ruby::ruby::Ruby as prek::languages::LanguageImpl>::install::{{closure}}
 0.1%   0.2% 18.6KiB     serde_saphyr? <serde_saphyr::de::YamlDeserializer as serde_core::de::Deserializer>::deserialize_map
 0.1%   0.2% 18.6KiB              ring ring_core_0_17_14__x25519_ge_frombytes_vartime
38.3%  91.7%  9.1MiB                   And 21033 smaller methods. Use -n N to show more.
41.8% 100.0% 10.0MiB                   .text section size, the file size is 23.8MiB

Base Branch Results

 File  .text    Size             Crate Name
 0.3%   0.7% 71.4KiB              prek prek::languages::<impl prek::config::Language>::run::{{closure}}::{{closure}}
 0.3%   0.7% 70.6KiB             prek? <prek::cli::Command as clap_builder::derive::Subcommand>::augment_subcommands
 0.3%   0.6% 65.6KiB              prek prek::languages::<impl prek::config::Language>::run::{{closure}}::{{closure}}
 0.2%   0.5% 51.2KiB annotate_snippets annotate_snippets::renderer::render::render
 0.2%   0.5% 50.5KiB              prek prek::languages::<impl prek::config::Language>::install::{{closure}}
 0.2%   0.4% 41.1KiB              prek prek::cli::run::run::run::{{closure}}
 0.2%   0.4% 38.8KiB              prek prek::run::{{closure}}
 0.1%   0.3% 32.0KiB             prek? <prek::cli::RunArgs as clap_builder::derive::Args>::augment_args
 0.1%   0.3% 28.5KiB      serde_saphyr saphyr_parser_bw::scanner::Scanner<T>::fetch_more_tokens
 0.1%   0.2% 24.7KiB             prek? <prek::config::_::<impl serde_core::de::Deserialize for prek::config::Config>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map
 0.1%   0.2% 22.8KiB      serde_saphyr saphyr_parser_bw::scanner::Scanner<T>::fetch_more_tokens
 0.1%   0.2% 22.7KiB              prek prek::hooks::meta_hooks::MetaHooks::run::{{closure}}
 0.1%   0.2% 21.1KiB      clap_builder clap_builder::parser::parser::Parser::get_matches_with
 0.1%   0.2% 20.5KiB              prek prek::hooks::meta_hooks::MetaHooks::run::{{closure}}
 0.1%   0.2% 20.0KiB   cargo_metadata? <cargo_metadata::_::<impl serde_core::de::Deserialize for cargo_metadata::Package>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map
 0.1%   0.2% 19.6KiB              prek prek::archive::unzip::{{closure}}
 0.1%   0.2% 19.3KiB               std core::ptr::drop_in_place<prek::languages::<impl prek::config::Language>::install::{{closure}}>
 0.1%   0.2% 19.2KiB              prek <prek::languages::ruby::ruby::Ruby as prek::languages::LanguageImpl>::install::{{closure}}
 0.1%   0.2% 18.8KiB        serde_json serde_json::de::from_str
 0.1%   0.2% 18.7KiB     serde_saphyr? <serde_saphyr::de::YamlDeserializer as serde_core::de::Deserializer>::deserialize_map
38.3%  91.8%  9.1MiB                   And 21022 smaller methods. Use -n N to show more.
41.7% 100.0%  9.9MiB                   .text section size, the file size is 23.8MiB

@j178 j178 marked this pull request as draft March 4, 2026 16:38
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.

2 participants