Skip to content

Commit 9c6b4d2

Browse files
derrickstoleedscho
authored andcommitted
hooks: skip post-command hook more often (#813)
The postCommand.strategy=worktree-change config option allows for skipping the post-command hook when the Git command doesn't change the worktree. However, sometimes this config isn't loaded before the post-command hook is invoked, causing the hook to run in cases where we'd prefer it to not run. Examples include: `git version` or `git <typo>`. The tricky bit is that there are several places where we get here and standard config mechanisms can't load due to not having a `gitdir` in the repository struct. We fix this by: 1. Using the "load early config" mechanism also used by `core.hooksPath`. 2. Skipping the lookup for the sentinel file when there isn't a `gitdir` since we couldn't have written one without it. The change is given in two commits: the first expands the tests with the existing behavior and the second changes the behavior, showing the impact on those tests. * [X] This change only applies to microsoft/git specifics (post-command hook) See #736 and #748 for prior art in this space.
2 parents 7c92b3b + bba9292 commit 9c6b4d2

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

hook.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,15 @@ static int write_post_index_change_sentinel(struct repository *r)
219219
*/
220220
static int post_index_change_sentinel_exists(struct repository *r)
221221
{
222-
char *path = get_post_index_change_sentinel_name(r);
222+
char *path;
223223
int res = 1;
224224

225+
/* It can't exist if we don't have a gitdir. */
226+
if (!r->gitdir)
227+
return 0;
228+
229+
path = get_post_index_change_sentinel_name(r);
230+
225231
if (unlink(path)) {
226232
if (is_missing_file_error(errno))
227233
res = 0;
@@ -233,6 +239,21 @@ static int post_index_change_sentinel_exists(struct repository *r)
233239
return res;
234240
}
235241

242+
static int check_worktree_change(const char *key, const char *value,
243+
UNUSED const struct config_context *ctx,
244+
void *data)
245+
{
246+
int *enabled = data;
247+
248+
if (!strcmp(key, "postcommand.strategy") &&
249+
!strcasecmp(value, "worktree-change")) {
250+
*enabled = 1;
251+
return 1;
252+
}
253+
254+
return 0;
255+
}
256+
236257
/**
237258
* See if we can replace the requested hook with an internal behavior.
238259
* Returns 0 if the real hook should run. Returns nonzero if we instead
@@ -242,9 +263,11 @@ static int handle_hook_replacement(struct repository *r,
242263
const char *hook_name,
243264
struct strvec *args)
244265
{
245-
const char *strval;
246-
if (repo_config_get_string_tmp(r, "postcommand.strategy", &strval) ||
247-
strcasecmp(strval, "worktree-change"))
266+
int enabled = 0;
267+
268+
read_early_config(r, check_worktree_change, &enabled);
269+
270+
if (!enabled)
248271
return 0;
249272

250273
if (!strcmp(hook_name, "post-index-change")) {
@@ -290,8 +313,7 @@ int run_hooks_opt(struct repository *r, const char *hook_name,
290313
};
291314

292315
/* Interject hook behavior depending on strategy. */
293-
if (r && r->gitdir &&
294-
handle_hook_replacement(r, hook_name, &options->args))
316+
if (r && handle_hook_replacement(r, hook_name, &options->args))
295317
return 0;
296318

297319
hook_path = find_hook(r, hook_name);

t/t0401-post-command-hook.sh

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,35 @@ test_expect_success 'with post-index-change config' '
7878
test_cmp expect post-index-change.out &&
7979
test_path_is_missing post-command.out &&
8080
81+
# add keeps the worktree the same, so does not run post-command.
82+
# and this should work through an alias.
83+
git config alias.addalias add &&
84+
rm -f post-command.out post-index-change.out &&
85+
echo more stuff >>file &&
86+
git addalias file &&
87+
test_cmp expect post-index-change.out &&
88+
test_path_is_missing post-command.out &&
89+
8190
echo stuff >>file &&
8291
# reset --hard updates the worktree.
92+
# even through an alias
93+
git config alias.resetalias "reset --hard" &&
8394
rm -f post-command.out post-index-change.out &&
84-
git reset --hard &&
95+
git resetalias &&
8596
test_cmp expect post-index-change.out &&
86-
test_cmp expect post-command.out
97+
test_cmp expect post-command.out &&
98+
99+
rm -f post-command.out &&
100+
test_must_fail git && # get help text
101+
test_path_is_missing post-command.out &&
102+
103+
rm -f post-command.out &&
104+
git version &&
105+
test_path_is_missing post-command.out &&
106+
107+
rm -f post-command.out &&
108+
test_must_fail git typo &&
109+
test_path_is_missing post-command.out
87110
'
88111

89112
test_done

0 commit comments

Comments
 (0)