Browse Source

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)
maint
Junio C Hamano 7 years ago
parent
commit
e87f9fc9d4
  1. 3
      Documentation/githooks.txt
  2. 22
      builtin/worktree.c
  3. 29
      t/t2025-worktree-add.sh

3
Documentation/githooks.txt

@ -170,7 +170,8 @@ This hook cannot affect the outcome of 'git checkout'. @@ -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

22
builtin/worktree.c

@ -230,20 +230,21 @@ static int add_worktree(const char *path, const char *refname, @@ -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, @@ -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 @@ done: @@ -339,6 +340,15 @@ done:
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);

29
t/t2025-worktree-add.sh

@ -444,4 +444,33 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' ' @@ -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

Loading…
Cancel
Save