Web lists-archives.com

[PATCH 2/2] worktree: add: change to new worktree directory before running hook




Although "git worktree add" learned to run the 'post-checkout' hook in
ade546be47 (worktree: invoke post-checkout hook, 2017-12-07), it
neglects to change to the directory of the newly-created worktree
before running the hook. Instead, the hook is run within the directory
from which the "git worktree add" command itself was invoked, which
effectively neuters the hook since it knows nothing about the new
worktree directory.

Fix this by changing to the new worktree's directory before running
the hook, and adjust the tests to verify that the hook is indeed run
within the correct directory.

While at it, also add a test to verify that the hook is run within the
correct directory even when the new worktree is created from a sibling
worktree (as opposed to the main worktree).

Reported-by: Lars Schneider <larsxschneider@xxxxxxxxx>
Signed-off-by: Eric Sunshine <sunshine@xxxxxxxxxxxxxx>
---
 builtin/worktree.c      | 11 ++++++++---
 t/t2025-worktree-add.sh | 25 ++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7cef5b120b..b55c55a26c 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -345,9 +345,14 @@ static int add_worktree(const char *path, const char *refname,
 	 * Hook failure does not warrant worktree deletion, so run hook after
 	 * is_junk is cleared, but do return appropriate code when hook fails.
 	 */
-	if (!ret && opts->checkout)
-		ret = run_hook_le(NULL, "post-checkout", oid_to_hex(&null_oid),
-				  oid_to_hex(&commit->object.oid), "1", NULL);
+	if (!ret && opts->checkout) {
+		char *p = absolute_pathdup(path);
+		ret = run_hook_cd_le(p, NULL, "post-checkout",
+				     oid_to_hex(&null_oid),
+				     oid_to_hex(&commit->object.oid),
+				     "1", NULL);
+		free(p);
+	}
 
 	argv_array_clear(&child_env);
 	strbuf_release(&sb);
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..cf0aaeaf88 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -454,20 +454,29 @@ post_checkout_hook () {
 	test_when_finished "rm -f .git/hooks/post-checkout" &&
 	mkdir -p .git/hooks &&
 	write_script .git/hooks/post-checkout <<-\EOF
-	echo $* >hook.actual
+	{
+		echo $*
+		git rev-parse --show-toplevel
+	} >../hook.actual
 	EOF
 }
 
 test_expect_success '"add" invokes post-checkout hook (branch)' '
 	post_checkout_hook &&
-	printf "%s %s 1\n" $_z40 $(git rev-parse HEAD) >hook.expect &&
+	{
+		echo $_z40 $(git rev-parse HEAD) 1 &&
+		echo $(pwd)/gumby
+	} >hook.expect &&
 	git worktree add gumby &&
 	test_cmp hook.expect hook.actual
 '
 
 test_expect_success '"add" invokes post-checkout hook (detached)' '
 	post_checkout_hook &&
-	printf "%s %s 1\n" $_z40 $(git rev-parse HEAD) >hook.expect &&
+	{
+		echo $_z40 $(git rev-parse HEAD) 1 &&
+		echo $(pwd)/grumpy
+	} >hook.expect &&
 	git worktree add --detach grumpy &&
 	test_cmp hook.expect hook.actual
 '
@@ -479,4 +488,14 @@ test_expect_success '"add --no-checkout" suppresses post-checkout hook' '
 	test_path_is_missing hook.actual
 '
 
+test_expect_success '"add" within worktree invokes post-checkout hook' '
+	post_checkout_hook &&
+	{
+		echo $_z40 $(git rev-parse HEAD) 1 &&
+		echo $(pwd)/guppy
+	} >hook.expect &&
+	git -C gloopy worktree add --detach ../guppy &&
+	test_cmp hook.expect hook.actual
+'
+
 test_done
-- 
2.16.1.291.g4437f3f132