Skip to content

Commit 4cc3812

Browse files
committed
fix(init): resolve hooks path relative to repo root
Ensure that `core.hooksPath` is resolved relative to the repository root of the current worktree, or the git dir if it is bare. This should be the same logic as git uses for resolution.
1 parent 16cab73 commit 4cc3812

File tree

2 files changed

+111
-3
lines changed

2 files changed

+111
-3
lines changed

git-branchless-lib/src/core/config.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,22 @@ pub fn get_main_worktree_hooks_dir(
5454
let hooks_path = if result.exit_code.is_success() {
5555
let path = String::from_utf8(result.stdout)
5656
.context("Decoding git config output for hooks path")?;
57-
PathBuf::from(path.strip_suffix('\n').unwrap_or(&path))
57+
58+
let path = PathBuf::from(path.strip_suffix('\n').unwrap_or(&path));
59+
60+
// Relative hook paths are resolved relative to where hooks are run[1],
61+
// which is the root of the current working tree in a non-bare
62+
// repository, or $GIT_DIR (the .git directory) for a bare
63+
// repository[2].
64+
// [1]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-corehooksPath
65+
// [2]: https://git-scm.com/docs/githooks#_description
66+
repo.get_working_copy_path()
67+
.as_deref()
68+
.unwrap_or_else(
69+
// Bare repo
70+
|| repo.get_path(),
71+
)
72+
.join(path)
5873
} else {
5974
get_default_hooks_dir(repo)?
6075
};

git-branchless/tests/test_init.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,99 @@ fn test_init_prompt_for_main_branch() -> eyre::Result<()> {
279279
Ok(())
280280
}
281281

282+
#[cfg(unix)]
283+
#[test]
284+
fn test_init_in_subdir() -> eyre::Result<()> {
285+
let git = make_git()?;
286+
287+
if !git.supports_reference_transactions()? {
288+
return Ok(());
289+
}
290+
291+
git.init_repo_with_options(&GitInitOptions {
292+
run_branchless_init: false,
293+
..Default::default()
294+
})?;
295+
296+
let subdir = git.repo_path.join("subdir");
297+
std::fs::create_dir(&subdir)?;
298+
299+
{
300+
let (stdout, stderr) = git.branchless_with_options(
301+
"init",
302+
&[],
303+
&GitRunOptions {
304+
working_dir: Some(subdir),
305+
..Default::default()
306+
},
307+
)?;
308+
insta::assert_snapshot!(stderr, @"");
309+
insta::assert_snapshot!(stdout, @r###"
310+
Created config file at <repo-path>/.git/branchless/config
311+
Auto-detected your main branch as: master
312+
If this is incorrect, run: git branchless init --main-branch <branch>
313+
Installing hooks: post-applypatch, post-checkout, post-commit, post-merge, post-rewrite, pre-auto-gc, reference-transaction
314+
Successfully installed git-branchless.
315+
To uninstall, run: git branchless init --uninstall
316+
"###);
317+
}
318+
319+
let hook_path = git.repo_path.join(".git").join("hooks").join("post-commit");
320+
assert!(hook_path.exists());
321+
322+
Ok(())
323+
}
324+
325+
#[cfg(unix)]
326+
#[test]
327+
fn test_init_in_subdir_with_hooks_path() -> eyre::Result<()> {
328+
let git = make_git()?;
329+
330+
if !git.supports_reference_transactions()? {
331+
return Ok(());
332+
}
333+
334+
git.init_repo_with_options(&GitInitOptions {
335+
run_branchless_init: false,
336+
..Default::default()
337+
})?;
338+
339+
let hooks_path = git.repo_path.join("my-hooks");
340+
std::fs::create_dir(&hooks_path)?;
341+
git.run(&["config", "core.hooksPath", "my-hooks"])?;
342+
343+
let subdir = git.repo_path.join("subdir");
344+
std::fs::create_dir(&subdir)?;
345+
346+
{
347+
let (stdout, stderr) = git.branchless_with_options(
348+
"init",
349+
&[],
350+
&GitRunOptions {
351+
working_dir: Some(subdir),
352+
..Default::default()
353+
},
354+
)?;
355+
insta::assert_snapshot!(stderr, @"");
356+
insta::assert_snapshot!(stdout, @r###"
357+
Created config file at <repo-path>/.git/branchless/config
358+
Auto-detected your main branch as: master
359+
If this is incorrect, run: git branchless init --main-branch <branch>
360+
Installing hooks: post-applypatch, post-checkout, post-commit, post-merge, post-rewrite, pre-auto-gc, reference-transaction
361+
Warning: the configuration value core.hooksPath was set to: <repo-path>/my-hooks,
362+
which is not the expected default value of: <repo-path>/.git/hooks
363+
The Git hooks above may have been installed to an unexpected global location.
364+
Successfully installed git-branchless.
365+
To uninstall, run: git branchless init --uninstall
366+
"###);
367+
}
368+
369+
let hook_path = hooks_path.join("post-commit");
370+
assert!(hook_path.exists());
371+
372+
Ok(())
373+
}
374+
282375
#[cfg(unix)]
283376
#[test]
284377
fn test_main_branch_not_found_error_message() -> eyre::Result<()> {
@@ -547,7 +640,7 @@ fn test_init_core_hooks_path_warning() -> eyre::Result<()> {
547640
Auto-detected your main branch as: master
548641
If this is incorrect, run: git branchless init --main-branch <branch>
549642
Installing hooks: post-applypatch, post-checkout, post-commit, post-merge, post-rewrite, pre-auto-gc, reference-transaction
550-
Warning: the configuration value core.hooksPath was set to: my-hooks,
643+
Warning: the configuration value core.hooksPath was set to: <repo-path>/my-hooks,
551644
which is not the expected default value of: <repo-path>/.git/hooks
552645
The Git hooks above may have been installed to an unexpected global location.
553646
Successfully installed git-branchless.
@@ -600,7 +693,7 @@ hooksPath = my-hooks
600693
Auto-detected your main branch as: master
601694
If this is incorrect, run: git branchless init --main-branch <branch>
602695
Installing hooks: post-applypatch, post-checkout, post-commit, post-merge, post-rewrite, pre-auto-gc, reference-transaction
603-
Warning: the configuration value core.hooksPath was set to: my-hooks,
696+
Warning: the configuration value core.hooksPath was set to: <repo-path>/my-hooks,
604697
which is not the expected default value of: <repo-path>/.git/hooks
605698
The Git hooks above may have been installed to an unexpected global location.
606699
Successfully installed git-branchless.

0 commit comments

Comments
 (0)