Skip to content

Commit 107f41a

Browse files
authored
Update behavior for postCommand.strategy=post-index-change (#748)
This feature was introduced in #736 but had a few pain points that were discovered when testing the full replacement of the existing post-index-change and post-command hooks in our internal environment: 1. When using `core.hooksPath` to point to a directory within the worktree, the sentinel files were being written into the worktree. Write to `$GITDIR/info/` instead. 2. The existing internal post-index-change hook only signaled that work needed to be done if actually the _worktree_ changed. Make the sentinel file logic more restrictive to only write in these cases. Tests are added to confirm both of these behavior changes. To reflect the changed behavior, the name `post-index-change` was renamed to `worktree-change`.
2 parents ba7e40a + aa035a2 commit 107f41a

File tree

3 files changed

+62
-21
lines changed

3 files changed

+62
-21
lines changed

Documentation/config/postcommand.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ postCommand.strategy::
77
`always`;;
88
run the `post-command` hook on every process (default).
99

10-
`post-index-change`;;
10+
`worktree-change`;;
1111
run the `post-command` hook only if the current process wrote to
12-
the index.
12+
the index and updated the worktree.
1313
----

hook.c

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,11 @@ static char *get_post_index_change_sentinel_name(struct repository *r)
190190
if (slash)
191191
*slash = 0;
192192

193-
repo_git_path_replace(r, &path, "hooks/index-change-%s.snt", sid);
193+
/*
194+
* Do not write to hooks directory, as it could be redirected
195+
* somewhere like the source tree.
196+
*/
197+
repo_git_path_replace(r, &path, "info/index-change-%s.snt", sid);
194198

195199
return strbuf_detach(&path, NULL);
196200
}
@@ -229,6 +233,37 @@ static int post_index_change_sentinel_exists(struct repository *r)
229233
return res;
230234
}
231235

236+
/**
237+
* See if we can replace the requested hook with an internal behavior.
238+
* Returns 0 if the real hook should run. Returns nonzero if we instead
239+
* executed custom internal behavior and the real hook should not run.
240+
*/
241+
static int handle_hook_replacement(struct repository *r,
242+
const char *hook_name,
243+
struct strvec *args)
244+
{
245+
const char *strval;
246+
if (repo_config_get_string_tmp(r, "postcommand.strategy", &strval) ||
247+
strcasecmp(strval, "worktree-change"))
248+
return 0;
249+
250+
if (!strcmp(hook_name, "post-index-change")) {
251+
/* Create a sentinel file only if the worktree changed. */
252+
if (!strcmp(args->v[0], "1"))
253+
write_post_index_change_sentinel(r);
254+
255+
/* We don't skip post-index-change hooks that exist. */
256+
return 0;
257+
}
258+
if (!strcmp(hook_name, "post-command") &&
259+
!post_index_change_sentinel_exists(r)) {
260+
/* We skip the post-command hook in this case. */
261+
return 1;
262+
}
263+
264+
return 0;
265+
}
266+
232267
int run_hooks_opt(struct repository *r, const char *hook_name,
233268
struct run_hooks_opt *options)
234269
{
@@ -255,17 +290,9 @@ int run_hooks_opt(struct repository *r, const char *hook_name,
255290
};
256291

257292
/* Interject hook behavior depending on strategy. */
258-
if (r && r->gitdir) {
259-
const char *strval;
260-
if (!repo_config_get_string_tmp(r, "postcommand.strategy", &strval) &&
261-
!strcasecmp(strval, "post-index-change")) {
262-
if (!strcmp(hook_name, "post-index-change"))
263-
return write_post_index_change_sentinel(r);
264-
if (!strcmp(hook_name, "post-command") &&
265-
!post_index_change_sentinel_exists(r))
266-
return 0;
267-
}
268-
}
293+
if (r && r->gitdir &&
294+
handle_hook_replacement(r, hook_name, &options->args))
295+
return 0;
269296

270297
hook_path = find_hook(r, hook_name);
271298

t/t0401-post-command-hook.sh

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,20 @@ test_expect_success 'with failing pre-command hook' '
3232
'
3333

3434
test_expect_success 'with post-index-change config' '
35-
mkdir -p .git/hooks &&
36-
write_script .git/hooks/post-command <<-EOF &&
35+
mkdir -p internal-hooks &&
36+
write_script internal-hooks/post-command <<-EOF &&
3737
echo ran >post-command.out
3838
EOF
39-
write_script .git/hooks/post-index-change <<-EOF &&
39+
write_script internal-hooks/post-index-change <<-EOF &&
4040
echo ran >post-index-change.out
4141
EOF
4242
43+
# prevent writing of sentinel files to this directory.
44+
test_when_finished chmod 775 internal-hooks &&
45+
chmod a-w internal-hooks &&
46+
47+
git config core.hooksPath internal-hooks &&
48+
4349
# First, show expected behavior.
4450
echo ran >expect &&
4551
rm -f post-command.out post-index-change.out &&
@@ -57,18 +63,26 @@ test_expect_success 'with post-index-change config' '
5763
test_cmp expect post-command.out &&
5864
5965
# Now, show configured behavior
60-
git config postCommand.strategy post-index-change &&
61-
rm -f post-command.out post-index-change.out &&
66+
git config postCommand.strategy worktree-change &&
6267
6368
# rev-parse leaves index intact and thus skips post-command.
69+
rm -f post-command.out post-index-change.out &&
6470
git rev-parse HEAD &&
6571
test_path_is_missing post-index-change.out &&
6672
test_path_is_missing post-command.out &&
6773
6874
echo stuff >>file &&
69-
# add updates the index and runs post-command.
75+
# add keeps the worktree the same, so does not run post-command.
76+
rm -f post-command.out post-index-change.out &&
7077
git add file &&
71-
test_path_is_missing post-index-change.out &&
78+
test_cmp expect post-index-change.out &&
79+
test_path_is_missing post-command.out &&
80+
81+
echo stuff >>file &&
82+
# reset --hard updates the worktree.
83+
rm -f post-command.out post-index-change.out &&
84+
git reset --hard &&
85+
test_cmp expect post-index-change.out &&
7286
test_cmp expect post-command.out
7387
'
7488

0 commit comments

Comments
 (0)