@@ -193,7 +193,8 @@ worktree. The hook is given three parameters: the ref of the previous HEAD,
the ref of the new HEAD (which may or may not have changed), and a flag
indicating whether the checkout was a branch checkout (changing branches,
flag=1) or a file checkout (retrieving a file from the index, flag=0).
-This hook cannot affect the outcome of `git switch` or `git checkout`.
+If this hook exits with an exit code other than 0, it causes the calling
+`git switch` or `git checkout` command to fail with the same exit code.
It is also run after linkgit:git-clone[1], unless the `--no-checkout` (`-n`) option is
used. The first parameter given to the hook is the null-ref, the second the
@@ -400,7 +400,7 @@ static int checkout_paths(const struct checkout_opts *opts,
static char *ps_matched;
struct object_id rev;
struct commit *head;
- int errs = 0;
+ int errs = 0, ret;
struct lock_file lock_file = LOCK_INIT;
int checkout_index;
@@ -548,8 +548,8 @@ static int checkout_paths(const struct checkout_opts *opts,
read_ref_full("HEAD", 0, &rev, NULL);
head = lookup_commit_reference_gently(the_repository, &rev, 1);
- errs |= post_checkout_hook(head, head, 0);
- return errs;
+ ret = post_checkout_hook(head, head, 0);
+ return !errs ? ret : (errs < 0 ? 1 : errs);
}
static void show_local_changes(struct object *head,
@@ -1062,6 +1062,8 @@ static int switch_branches(const struct checkout_opts *opts,
ret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1);
free(path_to_free);
+ if (ret > 0)
+ return ret;
return ret || writeout_error;
}
@@ -73,4 +73,13 @@ test_expect_success 'post-checkout hook is triggered by clone' '
test -f clone3/.git/post-checkout.args
'
+test_expect_success 'exit code of post-checkout hook is passed through' '
+ mkdir -p exit-code &&
+ echo "exit 123" | write_script exit-code/post-checkout &&
+ test_expect_code 123 \
+ git -c core.hooksPath="$PWD/exit-code" switch -c trigger-exit-code &&
+ test_expect_code 123 \
+ git -c core.hooksPath="$PWD/exit-code" restore .
+'
+
test_done