hook: introduce hook_config_cache_entry for per-hook data

Replace the bare `char *command` util pointer stored in each string_list item with a heap-allocated `struct hook_config_cache_entry` that carries that command string. This is just a refactoring with no behavior changes, to give the cache entry room to grow, so it can carry the additional hook metadata we'll be adding in the following commits. Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Adrian Ratiu committed Mar 25, 2026 at 21:55 UTC d8513bc5d84f21ea6d327a9cf9a369077eb19c67
1 file changed +22 -6
hook.c
+22 -6
@@ -108,6 +108,15 @@ static void list_hooks_add_default(struct repository *r, const char *hookname,
108 string_list_append(hook_list, hook_path)->util = h;
109 }
110
111 +/*
112 + * Cache entry stored as the .util pointer of string_list items inside the
113 + * hook config cache. For now carries only the command for the hook. Next
114 + * commits will add more data.
115 + */
116 +struct hook_config_cache_entry {
117 + char *command;
118 +};
119 +
120 /*
121 * Callback struct to collect all hook.* keys in a single config pass.
122 * commands: friendly-name to command map.
@@ -202,7 +211,12 @@ void hook_cache_clear(struct strmap *cache)
211
212 strmap_for_each_entry(cache, &iter, e) {
213 struct string_list *hooks = e->value;
205 - string_list_clear(hooks, 1); /* free util (command) pointers */
214 + for (size_t i = 0; i < hooks->nr; i++) {
215 + struct hook_config_cache_entry *entry = hooks->items[i].util;
216 + free(entry->command);
217 + free(entry);
218 + }
219 + string_list_clear(hooks, 0);
220 free(hooks);
221 }
222 strmap_clear(cache, 0);
@@ -232,6 +246,7 @@ static void build_hook_config_map(struct repository *r, struct strmap *cache)
246
247 for (size_t i = 0; i < hook_names->nr; i++) {
248 const char *hname = hook_names->items[i].string;
249 + struct hook_config_cache_entry *entry;
250 char *command;
251
252 /* filter out disabled hooks */
@@ -245,9 +260,10 @@ static void build_hook_config_map(struct repository *r, struct strmap *cache)
260 "'hook.%s.event' must be removed;"
261 " aborting."), hname, hname);
262
248 - /* util stores the command; owned by the cache. */
249 - string_list_append(hooks, hname)->util =
250 - xstrdup(command);
263 + /* util stores a cache entry; owned by the cache. */
264 + CALLOC_ARRAY(entry, 1);
265 + entry->command = xstrdup(command);
266 + string_list_append(hooks, hname)->util = entry;
267 }
268
269 strmap_put(cache, e->key, hooks);
@@ -309,7 +325,7 @@ static void list_hooks_add_configured(struct repository *r,
325 /* Iterate through configured hooks and initialize internal states */
326 for (size_t i = 0; configured_hooks && i < configured_hooks->nr; i++) {
327 const char *friendly_name = configured_hooks->items[i].string;
312 - const char *command = configured_hooks->items[i].util;
328 + struct hook_config_cache_entry *entry = configured_hooks->items[i].util;
329 struct hook *hook;
330
331 CALLOC_ARRAY(hook, 1);
@@ -327,7 +343,7 @@ static void list_hooks_add_configured(struct repository *r,
343
344 hook->kind = HOOK_CONFIGURED;
345 hook->u.configured.friendly_name = xstrdup(friendly_name);
330 - hook->u.configured.command = xstrdup(command);
346 + hook->u.configured.command = xstrdup(entry->command);
347
348 string_list_append(list, friendly_name)->util = hook;
349 }