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)
This commit is contained in:
Junio C Hamano 2017-12-27 11:16:21 -08:00
commit e87f9fc9d4
3 changed files with 47 additions and 7 deletions

View file

@ -170,7 +170,8 @@ This hook cannot affect the outcome of 'git checkout'.
It is also run after 'git clone', unless the --no-checkout (-n) option is
used. The first parameter given to the hook is the null-ref, the second the
ref of the new HEAD and the flag is always 1.
ref of the new HEAD and the flag is always 1. Likewise for 'git worktree add'
unless --no-checkout is used.
This hook can be used to perform repository validity checks, auto-display
differences from the previous HEAD if different, or set working dir metadata

View file

@ -230,20 +230,21 @@ static int add_worktree(const char *path, const char *refname,
int counter = 0, len, ret;
struct strbuf symref = STRBUF_INIT;
struct commit *commit = NULL;
int is_branch = 0;
if (file_exists(path) && !is_empty_dir(path))
die(_("'%s' already exists"), path);
/* is 'refname' a branch or commit? */
if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
ref_exists(symref.buf)) { /* it's a branch */
ref_exists(symref.buf)) {
is_branch = 1;
if (!opts->force)
die_if_checked_out(symref.buf, 0);
} else { /* must be a commit */
commit = lookup_commit_reference_by_name(refname);
if (!commit)
die(_("invalid reference: %s"), refname);
}
commit = lookup_commit_reference_by_name(refname);
if (!commit)
die(_("invalid reference: %s"), refname);
name = worktree_basename(path, &len);
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,
argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
cp.git_cmd = 1;
if (commit)
if (!is_branch)
argv_array_pushl(&cp.args, "update-ref", "HEAD",
oid_to_hex(&commit->object.oid), NULL);
else
@ -339,6 +340,15 @@ static int add_worktree(const char *path, const char *refname,
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
unlink_or_warn(sb.buf);
}
/*
* 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);
argv_array_clear(&child_env);
strbuf_release(&sb);
strbuf_release(&symref);

View file

@ -444,4 +444,33 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '
)
'
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
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 &&
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 &&
git worktree add --detach grumpy &&
test_cmp hook.expect hook.actual
'
test_expect_success '"add --no-checkout" suppresses post-checkout hook' '
post_checkout_hook &&
rm -f hook.actual &&
git worktree add --no-checkout gloopy &&
test_path_is_missing hook.actual
'
test_done