diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 50365f2914e04f..12c756a37b4cc5 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -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 diff --git a/builtin/checkout.c b/builtin/checkout.c index 12837277615d39..56afc3c1a8853d 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -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; } diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh index a39b3b5c78bc90..60ce81f6dbe6ac 100755 --- a/t/t5403-post-checkout-hook.sh +++ b/t/t5403-post-checkout-hook.sh @@ -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