Skip to content

Commit e87f9fc

Browse files
committed
Merge branch 'es/worktree-checkout-hook'
"git worktree add" learned to run the post-checkout hook, just like "git checkout" does, after the initial checkout. * es/worktree-checkout-hook: worktree: invoke post-checkout hook (unless --no-checkout)
2 parents 0da2ba4 + ade546b commit e87f9fc

File tree

3 files changed

+47
-7
lines changed

3 files changed

+47
-7
lines changed

Documentation/githooks.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ This hook cannot affect the outcome of 'git checkout'.
170170

171171
It is also run after 'git clone', unless the --no-checkout (-n) option is
172172
used. The first parameter given to the hook is the null-ref, the second the
173-
ref of the new HEAD and the flag is always 1.
173+
ref of the new HEAD and the flag is always 1. Likewise for 'git worktree add'
174+
unless --no-checkout is used.
174175

175176
This hook can be used to perform repository validity checks, auto-display
176177
differences from the previous HEAD if different, or set working dir metadata

builtin/worktree.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,20 +230,21 @@ static int add_worktree(const char *path, const char *refname,
230230
int counter = 0, len, ret;
231231
struct strbuf symref = STRBUF_INIT;
232232
struct commit *commit = NULL;
233+
int is_branch = 0;
233234

234235
if (file_exists(path) && !is_empty_dir(path))
235236
die(_("'%s' already exists"), path);
236237

237238
/* is 'refname' a branch or commit? */
238239
if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
239-
ref_exists(symref.buf)) { /* it's a branch */
240+
ref_exists(symref.buf)) {
241+
is_branch = 1;
240242
if (!opts->force)
241243
die_if_checked_out(symref.buf, 0);
242-
} else { /* must be a commit */
243-
commit = lookup_commit_reference_by_name(refname);
244-
if (!commit)
245-
die(_("invalid reference: %s"), refname);
246244
}
245+
commit = lookup_commit_reference_by_name(refname);
246+
if (!commit)
247+
die(_("invalid reference: %s"), refname);
247248

248249
name = worktree_basename(path, &len);
249250
git_path_buf(&sb_repo, "worktrees/%.*s", (int)(path + len - name), name);
@@ -308,7 +309,7 @@ static int add_worktree(const char *path, const char *refname,
308309
argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
309310
cp.git_cmd = 1;
310311

311-
if (commit)
312+
if (!is_branch)
312313
argv_array_pushl(&cp.args, "update-ref", "HEAD",
313314
oid_to_hex(&commit->object.oid), NULL);
314315
else
@@ -339,6 +340,15 @@ static int add_worktree(const char *path, const char *refname,
339340
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
340341
unlink_or_warn(sb.buf);
341342
}
343+
344+
/*
345+
* Hook failure does not warrant worktree deletion, so run hook after
346+
* is_junk is cleared, but do return appropriate code when hook fails.
347+
*/
348+
if (!ret && opts->checkout)
349+
ret = run_hook_le(NULL, "post-checkout", oid_to_hex(&null_oid),
350+
oid_to_hex(&commit->object.oid), "1", NULL);
351+
342352
argv_array_clear(&child_env);
343353
strbuf_release(&sb);
344354
strbuf_release(&symref);

t/t2025-worktree-add.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,4 +444,33 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '
444444
)
445445
'
446446

447+
post_checkout_hook () {
448+
test_when_finished "rm -f .git/hooks/post-checkout" &&
449+
mkdir -p .git/hooks &&
450+
write_script .git/hooks/post-checkout <<-\EOF
451+
echo $* >hook.actual
452+
EOF
453+
}
454+
455+
test_expect_success '"add" invokes post-checkout hook (branch)' '
456+
post_checkout_hook &&
457+
printf "%s %s 1\n" $_z40 $(git rev-parse HEAD) >hook.expect &&
458+
git worktree add gumby &&
459+
test_cmp hook.expect hook.actual
460+
'
461+
462+
test_expect_success '"add" invokes post-checkout hook (detached)' '
463+
post_checkout_hook &&
464+
printf "%s %s 1\n" $_z40 $(git rev-parse HEAD) >hook.expect &&
465+
git worktree add --detach grumpy &&
466+
test_cmp hook.expect hook.actual
467+
'
468+
469+
test_expect_success '"add --no-checkout" suppresses post-checkout hook' '
470+
post_checkout_hook &&
471+
rm -f hook.actual &&
472+
git worktree add --no-checkout gloopy &&
473+
test_path_is_missing hook.actual
474+
'
475+
447476
test_done

0 commit comments

Comments
 (0)