All of lore.kernel.org
 help / color / mirror / Atom feed
From: Emily Shaffer <emilyshaffer@google.com>
To: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
Cc: git@vger.kernel.org, Jeff King <peff@peff.net>,
	Junio C Hamano <gitster@pobox.com>,
	James Ramsay <james@jramsay.com.au>,
	Jonathan Nieder <jrnieder@gmail.com>,
	"brian m. carlson" <sandals@crustytoothpaste.net>,
	Phillip Wood <phillip.wood123@gmail.com>,
	Josh Steadmon <steadmon@google.com>,
	Johannes Schindelin <Johannes.Schindelin@gmx.de>,
	Jonathan Tan <jonathantanmy@google.com>
Subject: Re: [PATCH v8 00/37] config-based hooks
Date: Wed, 17 Mar 2021 12:16:55 -0700	[thread overview]
Message-ID: <YFJVp+5IVJux9Vbe@google.com> (raw)
In-Reply-To: <YFJNd6an0eGRC4/p@google.com>

On Wed, Mar 17, 2021 at 11:41:59AM -0700, Emily Shaffer wrote:
> 
> On Fri, Mar 12, 2021 at 10:49:38AM +0100, �var Arnfj�r� Bjarmason wrote:
> > 
> > 
> > On Thu, Mar 11 2021, Emily Shaffer wrote:
> > 
> > > Since v7:
> > > - Addressed Jonathan Tan's review of part I
> > > - Addressed Junio's review of part I and II
> > > - Combined parts I and II
> > >
> > > I think the updates to patch 1 between the rest of the work I've been
> > > doing probably have covered �var's comments.
> > 
> > A range-diff between iterations of such a large series would be most
> > useful. Do you have a public repo with tags or whatever the different
> > versions, for those who'd like an easier way to follow along the
> > differing versions than scraping the ML archive?
> 
> I am really embarrassed to say that I don't have the
> branches/tags/whatever up. I have not succeeded in building that habit
> yet. I'll generate one from my local patches today and send it here.

 1:  be907f68b9 !  1:  a5e8c233c3 doc: propose hooks managed by the config
    @@ Documentation/technical/config-based-hooks.txt (new)
     +[[motivation]]
     +== Motivation
     +
    -+Replace the .git/hook/hookname path as the only source of hooks to execute;
    ++Replace the `.git/hook/hookname` path as the only source of hooks to execute;
     +allow users to define hooks using config files, in a way which is friendly to
    -+users with multiple repos which have similar needs.
    ++users with multiple repos which have similar needs - hooks can be easily shared
    ++between multiple Git repos.
     +
     +Redefine "hook" as an event rather than a single script, allowing users to
     +perform multiple unrelated actions on a single event.
     +
    -+Take a step closer to safety when copying zipped Git repositories from untrusted
    -+users by making it more apparent to users which scripts will be run during
    -+normal Git operations.
    -+
     +Make it easier for users to discover Git's hook feature and automate their
     +workflows.
     +
    @@ Documentation/technical/config-based-hooks.txt (new)
     +number of cases:
     +
     +- "no": the legacy hook will not be run
    ++- "error": Git will print a warning to stderr before ignoring the legacy hook
     +- "interactive": Git will prompt the user before running the legacy hook
     +- "warn": Git will print a warning to stderr before running the legacy hook
     +- "yes" (default): Git will silently run the legacy hook
    @@ Documentation/technical/config-based-hooks.txt (new)
     +given which Git does not recognize, Git should discard that config entry. For
     +example, if "warn" was specified at system level and "junk" was specified at
     +global level, Git would resolve the value to "warn"; if the only time the config
    -+was set was to "junk", Git would use the default value of "yes".
    ++was set was to "junk", Git would use the default value of "yes" (but print a
    ++warning to the user first to let them know their value is wrong).
     +
     +`struct hookcmd` is expected to grow in size over time as more functionality is
     +added to hooks; so that other parts of the code don't need to understand the
    @@ Documentation/technical/config-based-hooks.txt (new)
     +=== Security and repo config
     +
     +Part of the motivation behind this refactor is to mitigate hooks as an attack
    -+vector;footnote:[https://lore.kernel.org/git/20171002234517.GV19555@aiede.mtv.corp.google.com/]
    -+however, as the design stands, users can still provide hooks in the repo-level
    -+config, which is included when a repo is zipped and sent elsewhere.  The
    ++vector.footnote:[https://lore.kernel.org/git/20171002234517.GV19555@aiede.mtv.corp.google.com/]
    ++However, as the design stands, users can still provide hooks in the repo-level
    ++config, which is included when a repo is zipped and sent elsewhere. The
     +security of the repo-level config is still under discussion; this design
    -+generally assumes the repo-level config is secure, which is not true yet. The
    -+goal is to avoid an overcomplicated design to work around a problem which has
    -+ceased to exist.
    ++generally assumes the repo-level config is secure, which is not true yet. This
    ++assumption was made to avoid overcomplicating the design. So, this series
    ++doesn't particularly improve security or resistance to zip attacks.
     +
     +[[ease-of-use]]
     +=== Ease of use
    @@ Documentation/technical/config-based-hooks.txt (new)
     +A previous summary of alternatives exists in the
     +archives.footnote:[https://lore.kernel.org/git/20191116011125.GG22855@google.com]
     +
    -+[[status-quo]]
    -+=== Status quo
    -+
    -+Today users can implement multihooks themselves by using a "trampoline script"
    -+as their hook, and pointing that script to a directory or list of other scripts
    -+they wish to run.
    -+
    -+[[hook-directories]]
    -+=== Hook directories
    -+
    -+Other contributors have suggested Git learn about the existence of a directory
    -+such as `.git/hooks/<hookname>.d` and execute those hooks in alphabetical order.
    -+
    -+[[comparison]]
    -+=== Comparison table
    ++The table below shows a number of goals and how they might be achieved with
    ++config-based hooks, by implementing directory support (i.e.
    ++'.git/hooks/pre-commit.d'), or as hooks are run today.
     +
     +.Comparison of alternatives
     +|===
    @@ Documentation/technical/config-based-hooks.txt (new)
     +|Natively
     +|With user effort
     +
    ++|Supports parallelization
    ++|Natively
    ++|Natively
    ++|No (user's multihook trampoline script would need to handle parallelism)
    ++
     +|Safer for zipped repos
     +|A little
     +|No
    @@ Documentation/technical/config-based-hooks.txt (new)
     +
     +|Can install one hook to many repos
     +|Yes
    -+|No
    -+|No
    ++|With symlinks or core.hooksPath
    ++|With symlinks or core.hooksPath
     +
     +|Discoverability
    -+|Better (in `git help git`)
    -+|Same as before
    ++|Findable with 'git help git' or tab-completion via 'git hook' subcommand
    ++|Findable via improved documentation
     +|Same as before
     +
     +|Hard to run unexpected hook
     +|If configured
    -+|No
    ++|Could be made to warn or look for a config
     +|No
     +|===
     +
    ++[[status-quo]]
    ++=== Status quo
    ++
    ++Today users can implement multihooks themselves by using a "trampoline script"
    ++as their hook, and pointing that script to a directory or list of other scripts
    ++they wish to run.
    ++
    ++[[hook-directories]]
    ++=== Hook directories
    ++
    ++Other contributors have suggested Git learn about the existence of a directory
    ++such as `.git/hooks/<hookname>.d` and execute those hooks in alphabetical order.
    ++
     +[[future-work]]
     +== Future work
     +
    @@ Documentation/technical/config-based-hooks.txt (new)
     +dependencies. If we decide to solve this problem, we may want to look to modern
     +build systems for inspiration on how to manage dependencies and parallel tasks.
     +
    ++[[nontrivial-hooks]]
    ++=== Multihooks and nontrivial output
    ++
    ++Some hooks - like 'proc-receive' - don't lend themselves well to multihooks at
    ++all. In the case of 'proc-receive', for now, multiple hook definitions are
    ++disallowed. In the future we might be able to conceive a better approach, for
    ++example, running the hooks in series and using the output from one hook as the
    ++input to the next.
    ++
     +[[securing-hookdir-hooks]]
     +=== Securing hookdir hooks
     +
 2:  b1d37c3911 =  2:  a3e858d056 hook: scaffolding for git-hook subcommand
 3:  fea411c598 !  3:  60b28a652b hook: add list command
    @@ Commit message
         run in config order. If more properties need to be set on a given hook
         in the future, commands can also be specified by providing
         "hook.<hookname>.command = <hookcmd-name>", as well as a "[hookcmd
    -    <hookcmd-name>]" subsection; at minimum, this subsection must contain a
    +    <hookcmd-name>]" subsection; this subsection should contain a
         "hookcmd.<hookcmd-name>.command = <path-to-hook>" line.
     
         For example:
    @@ Makefile: LIB_OBJS += hash-lookup.o
      ## builtin/hook.c ##
     @@
      #include "cache.h"
    - 
    +-
      #include "builtin.h"
     +#include "config.h"
     +#include "hook.h"
    @@ builtin/hook.c
      {
     -	struct option builtin_hook_options[] = {
     +	struct list_head *head, *pos;
    -+	struct hook *item;
     +	struct strbuf hookname = STRBUF_INIT;
     +
     +	struct option list_options[] = {
    @@ builtin/hook.c
     +	}
     +
     +	list_for_each(pos, head) {
    -+		item = list_entry(pos, struct hook, list);
    ++		struct hook *item = list_entry(pos, struct hook, list);
     +		if (item)
     +			printf("%s: %s\n",
     +			       config_scope_name(item->origin),
    @@ hook.c (new)
     +		    list_del(pos);
     +		    /* we'll simply move the hook to the end */
     +		    to_add = it;
    ++		    break;
     +		}
     +	}
     +
     +	if (!to_add) {
     +		/* adding a new hook, not moving an old one */
    -+		to_add = xmalloc(sizeof(struct hook));
    ++		to_add = xmalloc(sizeof(*to_add));
     +		strbuf_init(&to_add->command, 0);
     +		strbuf_addstr(&to_add->command, command);
     +	}
    @@ hook.c (new)
     +	/* re-set the scope so we show where an override was specified */
     +	to_add->origin = current_config_scope();
     +
    -+	list_add_tail(&to_add->list, pos);
    ++	list_add_tail(&to_add->list, head);
     +}
     +
     +static void remove_hook(struct list_head *to_remove)
    @@ hook.c (new)
     +		const char *command = value;
     +		struct strbuf hookcmd_name = STRBUF_INIT;
     +
    -+		/* Check if a hookcmd with that name exists. */
    ++		/*
    ++		 * Check if a hookcmd with that name exists. If it doesn't,
    ++		 * 'git_config_get_value()' is documented not to touch &command,
    ++		 * so we don't need to do anything.
    ++		 */
     +		strbuf_addf(&hookcmd_name, "hookcmd.%s.command", command);
     +		git_config_get_value(hookcmd_name.buf, &command);
     +
    @@ hook.c (new)
     +
     +	strbuf_addf(&hook_key, "hook.%s.command", hookname->buf);
     +
    -+	git_config(hook_config_lookup, (void*)&cb_data);
    ++	git_config(hook_config_lookup, &cb_data);
     +
     +	strbuf_release(&hook_key);
     +	return hook_head;
    @@ hook.h (new)
     +#include "list.h"
     +#include "strbuf.h"
     +
    -+struct hook
    -+{
    ++struct hook {
     +	struct list_head list;
     +	/*
     +	 * Config file which holds the hook.*.command definition.
 4:  89f1adf34d !  4:  d8232a8254 hook: include hookdir hook in list
    @@ Commit message
         $GIT_DIR/hooks/$HOOKNAME (or $HOOKDIR/$HOOKNAME). Although hooks taken
         from the config are more featureful than hooks placed in the $HOOKDIR,
         those hooks should not stop working for users who already have them.
    -
    -    Legacy hooks should be run directly, not in shell. We know that they are
    -    a path to an executable, not a oneliner script - and running them
    -    directly takes care of path quoting concerns for us for free.
    +    Let's list them to the user, but instead of displaying a config scope
    +    (e.g. "global: blah") we can prefix them with "hookdir:".
     
         Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
     
      ## builtin/hook.c ##
     @@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
    - 	struct list_head *head, *pos;
    - 	struct hook *item;
    - 	struct strbuf hookname = STRBUF_INIT;
    -+	struct strbuf hookdir_annotation = STRBUF_INIT;
    - 
    - 	struct option list_options[] = {
    - 		OPT_END(),
    -@@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
      
      	list_for_each(pos, head) {
    - 		item = list_entry(pos, struct hook, list);
    + 		struct hook *item = list_entry(pos, struct hook, list);
     -		if (item)
    --			printf("%s: %s\n",
    --			       config_scope_name(item->origin),
    --			       item->command.buf);
    ++		item = list_entry(pos, struct hook, list);
     +		if (item) {
     +			/* Don't translate 'hookdir' - it matches the config */
    -+			printf("%s: %s%s\n",
    + 			printf("%s: %s\n",
    +-			       config_scope_name(item->origin),
     +			       (item->from_hookdir
     +				? "hookdir"
     +				: config_scope_name(item->origin)),
    -+			       item->command.buf,
    -+			       (item->from_hookdir
    -+				? hookdir_annotation.buf
    -+				: ""));
    + 			       item->command.buf);
     +		}
      	}
      
    @@ hook.c
      void free_hook(struct hook *ptr)
      {
     @@ hook.c: static void append_or_move_hook(struct list_head *head, const char *command)
    - 		to_add = xmalloc(sizeof(struct hook));
    + 		to_add = xmalloc(sizeof(*to_add));
      		strbuf_init(&to_add->command, 0);
      		strbuf_addstr(&to_add->command, command);
     +		to_add->from_hookdir = 0;
    @@ hook.c: static void append_or_move_hook(struct list_head *head, const char *comm
      
      	/* re-set the scope so we show where an override was specified */
     @@ hook.c: struct list_head* hook_list(const struct strbuf* hookname)
    - 	struct strbuf hook_key = STRBUF_INIT;
    - 	struct list_head *hook_head = xmalloc(sizeof(struct list_head));
    - 	struct hook_config_cb cb_data = { &hook_key, hook_head };
    -+	const char *legacy_hook_path = NULL;
    - 
    - 	INIT_LIST_HEAD(hook_head);
      
    -@@ hook.c: struct list_head* hook_list(const struct strbuf* hookname)
    + 	git_config(hook_config_lookup, &cb_data);
      
    - 	git_config(hook_config_lookup, (void*)&cb_data);
    - 
    -+	if (have_git_dir())
    -+		legacy_hook_path = find_hook(hookname->buf);
    ++	if (have_git_dir()) {
    ++		const char *legacy_hook_path = find_hook(hookname->buf);
     +
    -+	/* Unconditionally add legacy hook, but annotate it. */
    -+	if (legacy_hook_path) {
    -+		struct hook *legacy_hook;
    ++		/* Unconditionally add legacy hook, but annotate it. */
    ++		if (legacy_hook_path) {
    ++			struct hook *legacy_hook;
     +
    -+		append_or_move_hook(hook_head, absolute_path(legacy_hook_path));
    -+		legacy_hook = list_entry(hook_head->prev, struct hook, list);
    -+		legacy_hook->from_hookdir = 1;
    ++			append_or_move_hook(hook_head,
    ++					    absolute_path(legacy_hook_path));
    ++			legacy_hook = list_entry(hook_head->prev, struct hook,
    ++						 list);
    ++			legacy_hook->from_hookdir = 1;
    ++		}
     +	}
     +
      	strbuf_release(&hook_key);
    @@ hook.c: struct list_head* hook_list(const struct strbuf* hookname)
      }
     
      ## hook.h ##
    -@@ hook.h: struct hook
    +@@ hook.h: struct hook {
      	enum config_scope origin;
      	/* The literal command to run. */
      	struct strbuf command;
    -+	int from_hookdir;
    ++	unsigned from_hookdir : 1;
      };
      
      /*
 5:  723edcd785 !  5:  96c0a4838f hook: respect hook.runHookDir
    @@ Metadata
     Author: Emily Shaffer <emilyshaffer@google.com>
     
      ## Commit message ##
    -    hook: respect hook.runHookDir
    +    hook: teach hook.runHookDir
     
    -    Include hooks specified in the hook directory in the list of hooks to
    -    run. These hooks do need to be treated differently from config-specified
    -    ones - they do not need to run in a shell, and later on may be disabled
    -    or warned about based on a config setting.
    -
    -    Because they are at least as local as the local config, we'll run them
    -    last - to keep the hook execution order from global to local.
    -
    -    Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
    +    For now, just give a hint about how these hooks will be run in 'git hook
    +    list'. Later on, though, we will pay attention to this enum when running
    +    the hooks.
     
      ## Documentation/config/hook.txt ##
     @@ Documentation/config/hook.txt: hookcmd.<name>.command::
    @@ builtin/hook.c: static const char * const builtin_hook_usage[] = {
      static int list(int argc, const char **argv, const char *prefix)
      {
      	struct list_head *head, *pos;
    + 	struct strbuf hookname = STRBUF_INIT;
    ++	struct strbuf hookdir_annotation = STRBUF_INIT;
    + 
    + 	struct option list_options[] = {
    + 		OPT_END(),
     @@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
      		return 0;
      	}
    @@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
     +		case HOOKDIR_NO:
     +			strbuf_addstr(&hookdir_annotation, _(" (will not run)"));
     +			break;
    ++		case HOOKDIR_ERROR:
    ++			strbuf_addstr(&hookdir_annotation, _(" (will error and not run)"));
    ++			break;
     +		case HOOKDIR_INTERACTIVE:
     +			strbuf_addstr(&hookdir_annotation, _(" (will prompt)"));
     +			break;
     +		case HOOKDIR_WARN:
    -+		case HOOKDIR_UNKNOWN:
    -+			strbuf_addstr(&hookdir_annotation, _(" (will warn)"));
    ++			strbuf_addstr(&hookdir_annotation, _(" (will warn but run)"));
     +			break;
     +		case HOOKDIR_YES:
     +		/*
     +		 * The default behavior should agree with
    -+		 * hook.c:configured_hookdir_opt().
    ++		 * hook.c:configured_hookdir_opt(). HOOKDIR_UNKNOWN should just
    ++		 * do the default behavior.
     +		 */
    ++		case HOOKDIR_UNKNOWN:
     +		default:
     +			break;
     +	}
     +
      	list_for_each(pos, head) {
    + 		struct hook *item = list_entry(pos, struct hook, list);
      		item = list_entry(pos, struct hook, list);
      		if (item) {
    + 			/* Don't translate 'hookdir' - it matches the config */
    +-			printf("%s: %s\n",
    ++			printf("%s: %s%s\n",
    + 			       (item->from_hookdir
    + 				? "hookdir"
    + 				: config_scope_name(item->origin)),
    +-			       item->command.buf);
    ++			       item->command.buf,
    ++			       (item->from_hookdir
    ++				? hookdir_annotation.buf
    ++				: ""));
    + 		}
    + 	}
    + 
    + 	clear_hook_list(head);
    ++	strbuf_release(&hookdir_annotation);
    + 	strbuf_release(&hookname);
    + 
    + 	return 0;
     @@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
      
      int cmd_hook(int argc, const char **argv, const char *prefix)
    @@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
     +	if (run_hookdir)
     +		if (!strcmp(run_hookdir, "no"))
     +			should_run_hookdir = HOOKDIR_NO;
    ++		else if (!strcmp(run_hookdir, "error"))
    ++			should_run_hookdir = HOOKDIR_ERROR;
     +		else if (!strcmp(run_hookdir, "yes"))
     +			should_run_hookdir = HOOKDIR_YES;
     +		else if (!strcmp(run_hookdir, "warn"))
    @@ hook.c: static int hook_config_lookup(const char *key, const char *value, void *
     +	if (!strcmp(key, "no"))
     +		return HOOKDIR_NO;
     +
    ++	if (!strcmp(key, "error"))
    ++		return HOOKDIR_ERROR;
    ++
     +	if (!strcmp(key, "yes"))
     +		return HOOKDIR_YES;
     +
    @@ hook.c: static int hook_config_lookup(const char *key, const char *value, void *
      	struct strbuf hook_key = STRBUF_INIT;
     
      ## hook.h ##
    -@@ hook.h: struct hook
    +@@ hook.h: struct hook {
       */
      struct list_head* hook_list(const struct strbuf *hookname);
      
     +enum hookdir_opt
     +{
     +	HOOKDIR_NO,
    ++	HOOKDIR_ERROR,
     +	HOOKDIR_WARN,
     +	HOOKDIR_INTERACTIVE,
     +	HOOKDIR_YES,
    @@ t/t1360-config-based-hooks.sh: test_expect_success 'git hook list shows hooks fr
     +	test_i18ncmp expected actual
     +'
     +
    ++test_expect_success 'hook.runHookDir = error is respected by list' '
    ++	setup_hookdir &&
    ++
    ++	test_config hook.runHookDir "error" &&
    ++
    ++	cat >expected <<-EOF &&
    ++	hookdir: $(pwd)/.git/hooks/pre-commit (will error and not run)
    ++	EOF
    ++
    ++	git hook list pre-commit >actual &&
    ++	# the hookdir annotation is translated
    ++	test_i18ncmp expected actual
    ++'
    ++
     +test_expect_success 'hook.runHookDir = warn is respected by list' '
     +	setup_hookdir &&
     +
     +	test_config hook.runHookDir "warn" &&
     +
     +	cat >expected <<-EOF &&
    -+	hookdir: $(pwd)/.git/hooks/pre-commit (will warn)
    ++	hookdir: $(pwd)/.git/hooks/pre-commit (will warn but run)
     +	EOF
     +
     +	git hook list pre-commit >actual &&
    @@ t/t1360-config-based-hooks.sh: test_expect_success 'git hook list shows hooks fr
     +	# the hookdir annotation is translated
     +	test_i18ncmp expected actual
     +'
    ++
    ++test_expect_success 'hook.runHookDir is tolerant to unknown values' '
    ++	setup_hookdir &&
    ++
    ++	test_config hook.runHookDir "junk" &&
    ++
    ++	cat >expected <<-EOF &&
    ++	hookdir: $(pwd)/.git/hooks/pre-commit
    ++	EOF
    ++
    ++	git hook list pre-commit >actual &&
    ++	# the hookdir annotation is translated
    ++	test_i18ncmp expected actual
    ++'
     +
      test_done
 6:  567f6d9d00 !  6:  9068e11679 hook: implement hookcmd.<name>.skip
    @@ Commit message
         hook: implement hookcmd.<name>.skip
     
         If a user wants a specific repo to skip execution of a hook which is set
    -    at a global or system level, they can now do so by specifying 'skip' in
    -    their repo config:
    +    at a global or system level, they will be able to do so by specifying
    +    'skip' in their repo config:
     
         ~/.gitconfig
           [hook.pre-commit]
    @@ Commit message
     
         Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
     
    + ## Documentation/config/hook.txt ##
    +@@ Documentation/config/hook.txt: hookcmd.<name>.command::
    + 	as a command. This can be an executable on your device or a oneliner for
    + 	your shell. See linkgit:git-hook[1].
    + 
    ++hookcmd.<name>.skip::
    ++	Specify this boolean to remove a command from earlier in the execution
    ++	order. Useful if you want to make a single repo an exception to hook
    ++	configured at the system or global scope. If there is no hookcmd
    ++	specified for the command you want to skip, you can use the value of
    ++	`hook.<command>.command` as <name> as a shortcut. The "skip" setting
    ++	must be specified after the "hook.<command>.command" to have an effect.
    ++
    + hook.runHookDir::
    + 	Controls how hooks contained in your hookdir are executed. Can be any of
    + 	"yes", "warn", "interactive", or "no". Defaults to "yes". See
    +
    + ## Documentation/git-hook.txt ##
    +@@ Documentation/git-hook.txt: $ git hook list "prepare-commit-msg"
    + local: /bin/linter --c
    + ----
    + 
    ++If there is a command you wish to run in most cases but have one or two
    ++exceptional repos where it should be skipped, you can use specify
    ++`hookcmd.<name>.skip`, for example:
    ++
    ++System config
    ++----
    ++  [hook "pre-commit"]
    ++    command = check-for-secrets
    ++
    ++  [hookcmd "check-for-secrets"]
    ++    command = /bin/secret-checker --aggressive
    ++----
    ++
    ++Local config
    ++----
    ++  [hookcmd "check-for-secrets"]
    ++    skip = true
    ++  # This works for inlined hook commands, too:
    ++  [hookcmd "~/typocheck.sh"]
    ++    skip = true
    ++----
    ++
    ++After these configs are added, the hook list becomes:
    ++
    ++----
    ++$ git hook list "post-commit"
    ++global: /bin/linter --c
    ++local: python ~/run-test-suite.py
    ++
    ++$ git hook list "pre-commit"
    ++no commands configured for hook 'pre-commit'
    ++----
    ++
    + COMMANDS
    + --------
    + 
    +
      ## hook.c ##
     @@ hook.c: void free_hook(struct hook *ptr)
      	}
      }
      
     -static void append_or_move_hook(struct list_head *head, const char *command)
    -+static struct hook* find_hook_by_command(struct list_head *head, const char *command)
    ++static struct hook * find_hook_by_command(struct list_head *head, const char *command)
      {
      	struct list_head *pos = NULL, *tmp = NULL;
     -	struct hook *to_add = NULL;
    @@ hook.c: void free_hook(struct hook *ptr)
     -		    /* we'll simply move the hook to the end */
     -		    to_add = it;
     +		    found = it;
    + 		    break;
      		}
      	}
     +	return found;
    @@ hook.c: void free_hook(struct hook *ptr)
      
      	if (!to_add) {
      		/* adding a new hook, not moving an old one */
    -@@ hook.c: static void append_or_move_hook(struct list_head *head, const char *command)
    - 	/* re-set the scope so we show where an override was specified */
    - 	to_add->origin = current_config_scope();
    - 
    --	list_add_tail(&to_add->list, pos);
    -+	list_add_tail(&to_add->list, head);
    - }
    - 
    - static void remove_hook(struct list_head *to_remove)
     @@ hook.c: static int hook_config_lookup(const char *key, const char *value, void *cb_data)
      	if (!strcmp(key, hook_key)) {
      		const char *command = value;
    @@ hook.c: static int hook_config_lookup(const char *key, const char *value, void *
     +		strbuf_addf(&hookcmd_name, "hookcmd.%s.skip", command);
     +		git_config_get_bool(hookcmd_name.buf, &skip);
      
    - 		/* Check if a hookcmd with that name exists. */
    + 		/*
    + 		 * Check if a hookcmd with that name exists. If it doesn't,
    + 		 * 'git_config_get_value()' is documented not to touch &command,
    + 		 * so we don't need to do anything.
    + 		 */
     +		strbuf_reset(&hookcmd_name);
      		strbuf_addf(&hookcmd_name, "hookcmd.%s.command", command);
      		git_config_get_value(hookcmd_name.buf, &command);
    @@ t/t1360-config-based-hooks.sh: test_expect_success 'hook.runHookDir = warn is re
     +	test_i18ncmp expected actual
     +'
     +
    ++test_expect_success 'git hook list ignores skip referring to unused hookcmd' '
    ++	test_config hookcmd.abc.command "/path/abc" --add &&
    ++	test_config hookcmd.abc.skip "true" --add &&
    ++
    ++	cat >expected <<-EOF &&
    ++	no commands configured for hook '\''pre-commit'\''
    ++	EOF
    ++
    ++	git hook list pre-commit >actual &&
    ++	test_i18ncmp expected actual
    ++'
    ++
     +test_expect_success 'git hook list removes skipped inlined hook' '
     +	setup_hooks &&
     +	test_config hookcmd."$ROOT/path/ghi".skip "true" --add &&
 7:  a1c02b6758 !  7:  a2867ab8c0 parse-options: parse into strvec
    @@ Documentation/technical/api-parse-options.txt: There are some macros to easily d
      	Use of `--no-option` will clear the list of preceding values.
      
     +`OPT_STRVEC(short, long, &struct strvec, arg_str, description)`::
    -+	Introduce an option with a string argument.
    -+	The string argument is stored as an element in `strvec`.
    ++	Introduce an option with a string argument, meant to be specified
    ++	multiple times.
    ++	The string argument is stored as an element in `strvec`, and later
    ++	arguments are added to the same `strvec`.
     +	Use of `--no-option` will clear the list of preceding values.
     +
      `OPT_INTEGER(short, long, &int_var, description)`::
 8:  d865772ebc !  8:  8848eeddf2 hook: add 'run' subcommand
    @@ Commit message
         supported.
     
         Legacy hooks (those present in $GITDIR/hooks) are run at the end of the
    -    execution list. For now, there is no way to disable them.
    +    execution list. They can be disabled, or made to print warnings, or to
    +    prompt before running, with the 'hook.runHookDir' config.
     
         Users may wish to provide hook commands like 'git config
         hook.pre-commit.command "~/linter.sh --pre-commit"'. To enable this,
    @@ Documentation/git-hook.txt: in the order they should be run, and print the confi
     +run [(-e|--env)=<var>...] [(-a|--arg)=<arg>...] `<hook-name>`::
     +
     +Runs hooks configured for `<hook-name>`, in the same order displayed by `git
    -+hook list`. Hooks configured this way are run prepended with `sh -c`, so paths
    -+containing special characters or spaces should be wrapped in single quotes:
    -+`command = '/my/path with spaces/script.sh' some args`.
    ++hook list`. Hooks configured this way may be run prepended with `sh -c`, so
    ++paths containing special characters or spaces should be wrapped in single
    ++quotes: `command = '/my/path with spaces/script.sh' some args`.
     +
     +OPTIONS
     +-------
    @@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
     +static int run(int argc, const char **argv, const char *prefix)
     +{
     +	struct strbuf hookname = STRBUF_INIT;
    -+	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
    ++	struct run_hooks_opt opt;
     +	int rc = 0;
     +
     +	struct option run_options[] = {
    @@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
     +		OPT_END(),
     +	};
     +
    -+	/*
    -+	 * While it makes sense to list hooks out-of-repo, it doesn't make sense
    -+	 * to execute them. Hooks usually want to look at repository artifacts.
    -+	 */
    -+	if (!have_git_dir())
    -+		usage_msg_opt(_("You must be in a Git repo to execute hooks."),
    -+			      builtin_hook_usage, run_options);
    ++	run_hooks_opt_init(&opt);
     +
     +	argc = parse_options(argc, argv, prefix, run_options,
     +			     builtin_hook_usage, 0);
    @@ hook.c: enum hookdir_opt configured_hookdir_opt(void)
     +
     +	switch (cfg)
     +	{
    ++		case HOOKDIR_ERROR:
    ++			fprintf(stderr, _("Skipping legacy hook at '%s'\n"),
    ++				path);
    ++			/* FALLTHROUGH */
     +		case HOOKDIR_NO:
     +			return 0;
    -+		case HOOKDIR_UNKNOWN:
    -+			fprintf(stderr,
    -+				_("Unrecognized value for 'hook.runHookDir'. "
    -+				  "Is there a typo? "));
    -+			/* FALLTHROUGH */
     +		case HOOKDIR_WARN:
     +			fprintf(stderr, _("Running legacy hook at '%s'\n"),
     +				path);
    @@ hook.c: enum hookdir_opt configured_hookdir_opt(void)
     +			} while (prompt.len); /* an empty reply means "Yes" */
     +			strbuf_release(&prompt);
     +			return 1;
    ++		/*
    ++		 * HOOKDIR_UNKNOWN should match the default behavior, but let's
    ++		 * give a heads up to the user.
    ++		 */
    ++		case HOOKDIR_UNKNOWN:
    ++			fprintf(stderr,
    ++				_("Unrecognized value for 'hook.runHookDir'. "
    ++				  "Is there a typo? "));
    ++			/* FALLTHROUGH */
     +		case HOOKDIR_YES:
     +		default:
     +			return 1;
    @@ hook.c: struct list_head* hook_list(const struct strbuf* hookname)
     +	strvec_clear(&o->args);
     +}
     +
    ++static void prepare_hook_cp(struct hook *hook, struct run_hooks_opt *options,
    ++			    struct child_process *cp)
    ++{
    ++	if (!hook)
    ++		return;
    ++
    ++	cp->no_stdin = 1;
    ++	cp->env = options->env.v;
    ++	cp->stdout_to_stderr = 1;
    ++	cp->trace2_hook_name = hook->command.buf;
    ++
    ++	/*
    ++	 * Commands from the config could be oneliners, but we know
    ++	 * for certain that hookdir commands are not.
    ++	 */
    ++	cp->use_shell = !hook->from_hookdir;
    ++
    ++	/* add command */
    ++	strvec_push(&cp->args, hook->command.buf);
    ++
    ++	/*
    ++	 * add passed-in argv, without expanding - let the user get back
    ++	 * exactly what they put in
    ++	 */
    ++	strvec_pushv(&cp->args, options->args.v);
    ++}
    ++
     +int run_hooks(const char *hookname, struct run_hooks_opt *options)
     +{
     +	struct strbuf hookname_str = STRBUF_INIT;
    @@ hook.c: struct list_head* hook_list(const struct strbuf* hookname)
     +		struct child_process hook_proc = CHILD_PROCESS_INIT;
     +		struct hook *hook = list_entry(pos, struct hook, list);
     +
    -+		hook_proc.env = options->env.v;
    -+		hook_proc.no_stdin = 1;
    -+		hook_proc.stdout_to_stderr = 1;
    -+		hook_proc.trace2_hook_name = hook->command.buf;
    -+		hook_proc.use_shell = 1;
    -+
    -+		if (hook->from_hookdir) {
    -+		    if (!should_include_hookdir(hook->command.buf, options->run_hookdir))
    ++		if (hook->from_hookdir &&
    ++		    !should_include_hookdir(hook->command.buf, options->run_hookdir))
     +			continue;
    -+		    /*
    -+		     * Commands from the config could be oneliners, but we know
    -+		     * for certain that hookdir commands are not.
    -+		     */
    -+		    hook_proc.use_shell = 0;
    -+		}
    -+
    -+		/* add command */
    -+		strvec_push(&hook_proc.args, hook->command.buf);
     +
    -+		/*
    -+		 * add passed-in argv, without expanding - let the user get back
    -+		 * exactly what they put in
    -+		 */
    -+		strvec_pushv(&hook_proc.args, options->args.v);
    ++		prepare_hook_cp(hook, options, &hook_proc);
     +
     +		rc |= run_command(&hook_proc);
     +	}
    @@ hook.h
      #include "strbuf.h"
     +#include "strvec.h"
      
    - struct hook
    - {
    + struct hook {
    + 	struct list_head list;
     @@ hook.h: enum hookdir_opt
       */
      enum hookdir_opt configured_hookdir_opt(void);
    @@ hook.h: enum hookdir_opt
     +	enum hookdir_opt run_hookdir;
     +};
     +
    -+#define RUN_HOOKS_OPT_INIT  {   		\
    -+	.env = STRVEC_INIT, 				\
    -+	.args = STRVEC_INIT, 			\
    -+	.run_hookdir = configured_hookdir_opt()	\
    -+}
    -+
     +void run_hooks_opt_init(struct run_hooks_opt *o);
     +void run_hooks_opt_clear(struct run_hooks_opt *o);
     +
    @@ t/t1360-config-based-hooks.sh: test_expect_success 'hook.runHookDir = no is resp
     +	test_must_be_empty actual
      '
      
    - test_expect_success 'hook.runHookDir = warn is respected by list' '
    + test_expect_success 'hook.runHookDir = error is respected by list' '
    +@@ t/t1360-config-based-hooks.sh: test_expect_success 'hook.runHookDir = error is respected by list' '
    + 
    + 	git hook list pre-commit >actual &&
    + 	# the hookdir annotation is translated
    ++	test_i18ncmp expected actual &&
    ++
    ++	cat >expected <<-EOF &&
    ++	Skipping legacy hook at '\''$(pwd)/.git/hooks/pre-commit'\''
    ++	EOF
    ++
    ++	git hook run pre-commit 2>actual &&
    + 	test_i18ncmp expected actual
    + '
    + 
     @@ t/t1360-config-based-hooks.sh: test_expect_success 'hook.runHookDir = warn is respected by list' '
      
      	git hook list pre-commit >actual &&
    @@ t/t1360-config-based-hooks.sh: test_expect_success 'hook.runHookDir = interactiv
     +	nongit test_must_fail git hook run pre-commit
      '
      
    - test_done
    + test_expect_success 'hook.runHookDir is tolerant to unknown values' '
 9:  53a655ed2c !  9:  452f7eea89 hook: replace find_hook() with hook_exists()
    @@ Metadata
     Author: Emily Shaffer <emilyshaffer@google.com>
     
      ## Commit message ##
    -    hook: replace find_hook() with hook_exists()
    +    hook: introduce hook_exists()
     
         Add a helper to easily determine whether any hooks exist for a given
         hook event.
    @@ Commit message
         hook; that check should include the config-based hooks as well. Optimize
         by checking the config directly. Since commands which execute hooks
         might want to take args to replace 'hook.runHookDir', let
    -    'hook_exists()' mirror the behavior of 'hook.runHookDir'.
    +    'hook_exists()' take a hookdir_opt to override that config.
     
    -    Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
    +    In some cases, external callers today use find_hook() to discover the
    +    location of a hook and then run it manually with run-command.h (that is,
    +    not with run_hook_le()). Later, those cases will call hook.h:run_hook()
    +    directly instead.
     
    - ## builtin/bugreport.c ##
    -@@
    - #include "strbuf.h"
    - #include "help.h"
    - #include "compat/compiler.h"
    --#include "run-command.h"
    -+#include "hook.h"
    - 
    - 
    - static void get_system_info(struct strbuf *sys_info)
    -@@ builtin/bugreport.c: static void get_populated_hooks(struct strbuf *hook_info, int nongit)
    - 	}
    - 
    - 	for (i = 0; i < ARRAY_SIZE(hook); i++)
    --		if (find_hook(hook[i]))
    -+		if (hook_exists(hook[i], configured_hookdir_opt()))
    - 			strbuf_addf(hook_info, "%s\n", hook[i]);
    - }
    - 
    +    Once the entire codebase is using hook_exists() instead of find_hook(),
    +    find_hook() can be safely rolled into hook_exists() and removed from
    +    run-command.h.
    +
    +    Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
     
      ## hook.c ##
     @@ hook.c: void run_hooks_opt_init(struct run_hooks_opt *o)
    @@ hook.c: void run_hooks_opt_init(struct run_hooks_opt *o)
     +{
     +	const char *value = NULL; /* throwaway */
     +	struct strbuf hook_key = STRBUF_INIT;
    ++	int could_run_hookdir;
    ++
    ++	if (should_run_hookdir == HOOKDIR_USE_CONFIG)
    ++		should_run_hookdir = configured_hookdir_opt();
     +
    -+	int could_run_hookdir = (should_run_hookdir == HOOKDIR_INTERACTIVE ||
    ++	could_run_hookdir = (should_run_hookdir == HOOKDIR_INTERACTIVE ||
     +				should_run_hookdir == HOOKDIR_WARN ||
     +				should_run_hookdir == HOOKDIR_YES)
     +				&& !!find_hook(hookname);
    @@ hook.c: void run_hooks_opt_init(struct run_hooks_opt *o)
      	strvec_clear(&o->env);
     
      ## hook.h ##
    +@@ hook.h: struct list_head* hook_list(const struct strbuf *hookname);
    + 
    + enum hookdir_opt
    + {
    ++	HOOKDIR_USE_CONFIG,
    + 	HOOKDIR_NO,
    + 	HOOKDIR_ERROR,
    + 	HOOKDIR_WARN,
     @@ hook.h: struct run_hooks_opt
      void run_hooks_opt_init(struct run_hooks_opt *o);
      void run_hooks_opt_clear(struct run_hooks_opt *o);
10:  13abc6ce24 ! 10:  e76507b290 hook: support passing stdin to hooks
    @@ Documentation/git-hook.txt: in the order they should be run, and print the confi
     +run [(-e|--env)=<var>...] [(-a|--arg)=<arg>...] [--to-stdin=<path>] `<hook-name>`::
      
      Runs hooks configured for `<hook-name>`, in the same order displayed by `git
    - hook list`. Hooks configured this way are run prepended with `sh -c`, so paths
    + hook list`. Hooks configured this way may be run prepended with `sh -c`, so
     @@ Documentation/git-hook.txt: Specify arguments to pass to every hook that is run.
      +
      Specify environment variables to set for every hook that is run.
    @@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
      
     
      ## hook.c ##
    -@@ hook.c: int run_hooks(const char *hookname, struct run_hooks_opt *options)
    - 		struct child_process hook_proc = CHILD_PROCESS_INIT;
    - 		struct hook *hook = list_entry(pos, struct hook, list);
    +@@ hook.c: void run_hooks_opt_init(struct run_hooks_opt *o)
    + {
    + 	strvec_init(&o->env);
    + 	strvec_init(&o->args);
    ++	o->path_to_stdin = NULL;
    + 	o->run_hookdir = configured_hookdir_opt();
    + }
    + 
    +@@ hook.c: static void prepare_hook_cp(struct hook *hook, struct run_hooks_opt *options,
    + 	if (!hook)
    + 		return;
      
    -+		/* reopen the file for stdin; run_command closes it. */
    -+		if (options->path_to_stdin)
    -+			hook_proc.in = xopen(options->path_to_stdin, O_RDONLY);
    -+		else
    -+			hook_proc.no_stdin = 1;
    +-	cp->no_stdin = 1;
    ++	/* reopen the file for stdin; run_command closes it. */
    ++	if (options->path_to_stdin)
    ++		cp->in = xopen(options->path_to_stdin, O_RDONLY);
    ++	else
    ++		cp->no_stdin = 1;
     +
    - 		hook_proc.env = options->env.v;
    --		hook_proc.no_stdin = 1;
    - 		hook_proc.stdout_to_stderr = 1;
    - 		hook_proc.trace2_hook_name = hook->command.buf;
    - 		hook_proc.use_shell = 1;
    + 	cp->env = options->env.v;
    + 	cp->stdout_to_stderr = 1;
    + 	cp->trace2_hook_name = hook->command.buf;
     
      ## hook.h ##
     @@ hook.h: struct run_hooks_opt
    @@ hook.h: struct run_hooks_opt
     +	const char *path_to_stdin;
      };
      
    - #define RUN_HOOKS_OPT_INIT  {   		\
    --	.env = STRVEC_INIT, 				\
    -+	.env = STRVEC_INIT, 			\
    - 	.args = STRVEC_INIT, 			\
    -+	.path_to_stdin = NULL,			\
    - 	.run_hookdir = configured_hookdir_opt()	\
    - }
    - 
    + void run_hooks_opt_init(struct run_hooks_opt *o);
     @@ hook.h: int hook_exists(const char *hookname, enum hookdir_opt should_run_hookdir);
      
      /*
    @@ hook.h: int hook_exists(const char *hookname, enum hookdir_opt should_run_hookdi
      
     
      ## t/t1360-config-based-hooks.sh ##
    -@@ t/t1360-config-based-hooks.sh: test_expect_success 'out-of-repo runs excluded' '
    - 	nongit test_must_fail git hook run pre-commit
    +@@ t/t1360-config-based-hooks.sh: test_expect_success 'hook.runHookDir is tolerant to unknown values' '
    + 	test_i18ncmp expected actual
      '
      
     +test_expect_success 'stdin to multiple hooks' '
11:  0465a9ec94 ! 11:  5f41555e49 run-command: allow stdin for run_processes_parallel
    @@ run-command.c: static int pp_start_one(struct parallel_processes *pp)
      	if (i == pp->max_processes)
      		BUG("bookkeeping is hard");
      
    -+	/* disallow by default, but allow users to set up stdin if they wish */
    ++	/*
    ++	 * By default, do not inherit stdin from the parent process - otherwise,
    ++	 * all children would share stdin! Users may overwrite this to provide
    ++	 * something to the child's stdin by having their 'get_next_task'
    ++	 * callback assign 0 to .no_stdin and an appropriate integer to .in.
    ++	 */
     +	pp->children[i].process.no_stdin = 1;
     +
      	code = pp->get_next_task(&pp->children[i].process,
12:  83eb7805a4 ! 12:  a3bf826304 hook: allow parallel hook execution
    @@ Documentation/git-hook.txt: in the order they should be run, and print the confi
     +run [(-e|--env)=<var>...] [(-a|--arg)=<arg>...] [--to-stdin=<path>] [(-j|--jobs)<n>] `<hook-name>`::
      
      Runs hooks configured for `<hook-name>`, in the same order displayed by `git
    - hook list`. Hooks configured this way are run prepended with `sh -c`, so paths
    + hook list`. Hooks configured this way may be run prepended with `sh -c`, so
     @@ Documentation/git-hook.txt: Specify environment variables to set for every hook that is run.
      Specify a file which will be streamed into stdin for every hook that is run.
      Each hook will receive the entire file from beginning to EOF.
    @@ builtin/hook.c
      	NULL
      };
      
    -@@ builtin/hook.c: static int list(int argc, const char **argv, const char *prefix)
    - static int run(int argc, const char **argv, const char *prefix)
    - {
    - 	struct strbuf hookname = STRBUF_INIT;
    --	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
    -+	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_ASYNC;
    - 	int rc = 0;
    - 
    - 	struct option run_options[] = {
     @@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
      			   N_("argument to pass to hook")),
      		OPT_STRING(0, "to-stdin", &opt.path_to_stdin, N_("path"),
    @@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
      		OPT_END(),
      	};
      
    +-	run_hooks_opt_init(&opt);
    ++	run_hooks_opt_init_async(&opt);
    + 
    + 	argc = parse_options(argc, argv, prefix, run_options,
    + 			     builtin_hook_usage, 0);
     
      ## hook.c ##
     @@ hook.c: enum hookdir_opt configured_hookdir_opt(void)
    @@ hook.c: enum hookdir_opt configured_hookdir_opt(void)
      static int should_include_hookdir(const char *path, enum hookdir_opt cfg)
      {
      	struct strbuf prompt = STRBUF_INIT;
    -@@ hook.c: void run_hooks_opt_init(struct run_hooks_opt *o)
    +@@ hook.c: struct list_head* hook_list(const struct strbuf* hookname)
    + 	return hook_head;
    + }
    + 
    +-void run_hooks_opt_init(struct run_hooks_opt *o)
    ++void run_hooks_opt_init_sync(struct run_hooks_opt *o)
    + {
      	strvec_init(&o->env);
      	strvec_init(&o->args);
    + 	o->path_to_stdin = NULL;
      	o->run_hookdir = configured_hookdir_opt();
    ++	o->jobs = 1;
    ++}
    ++
    ++void run_hooks_opt_init_async(struct run_hooks_opt *o)
    ++{
    ++	run_hooks_opt_init_sync(o);
     +	o->jobs = configured_hook_jobs();
      }
      
    @@ hook.c: void run_hooks_opt_clear(struct run_hooks_opt *o)
      	strvec_clear(&o->args);
      }
      
    -+
    +-static void prepare_hook_cp(struct hook *hook, struct run_hooks_opt *options,
    +-			    struct child_process *cp)
     +static int pick_next_hook(struct child_process *cp,
     +			  struct strbuf *out,
     +			  void *pp_cb,
     +			  void **pp_task_cb)
    -+{
    + {
     +	struct hook_cb_data *hook_cb = pp_cb;
    ++	struct hook *hook = hook_cb->run_me;
     +
    -+	struct hook *hook = list_entry(hook_cb->run_me, struct hook, list);
    -+
    -+	if (hook_cb->head == hook_cb->run_me)
    + 	if (!hook)
    +-		return;
     +		return 0;
    -+
    -+	cp->env = hook_cb->options->env.v;
    -+	cp->stdout_to_stderr = 1;
    -+	cp->trace2_hook_name = hook->command.buf;
    -+
    -+	/* reopen the file for stdin; run_command closes it. */
    + 
    + 	/* reopen the file for stdin; run_command closes it. */
    +-	if (options->path_to_stdin)
    +-		cp->in = xopen(options->path_to_stdin, O_RDONLY);
    +-	else
     +	if (hook_cb->options->path_to_stdin) {
     +		cp->no_stdin = 0;
     +		cp->in = xopen(hook_cb->options->path_to_stdin, O_RDONLY);
     +	} else {
    -+		cp->no_stdin = 1;
    + 		cp->no_stdin = 1;
     +	}
    -+
    -+	/*
    -+	 * Commands from the config could be oneliners, but we know
    -+	 * for certain that hookdir commands are not.
    -+	 */
    -+	if (hook->from_hookdir)
    -+		cp->use_shell = 0;
    -+	else
    -+		cp->use_shell = 1;
    -+
    -+	/* add command */
    -+	strvec_push(&cp->args, hook->command.buf);
    -+
    -+	/*
    -+	 * add passed-in argv, without expanding - let the user get back
    -+	 * exactly what they put in
    -+	 */
    + 
    +-	cp->env = options->env.v;
    ++	cp->env = hook_cb->options->env.v;
    + 	cp->stdout_to_stderr = 1;
    + 	cp->trace2_hook_name = hook->command.buf;
    + 
    +@@ hook.c: static void prepare_hook_cp(struct hook *hook, struct run_hooks_opt *options,
    + 	 * add passed-in argv, without expanding - let the user get back
    + 	 * exactly what they put in
    + 	 */
    +-	strvec_pushv(&cp->args, options->args.v);
     +	strvec_pushv(&cp->args, hook_cb->options->args.v);
     +
     +	/* Provide context for errors if necessary */
     +	*pp_task_cb = hook;
     +
     +	/* Get the next entry ready */
    -+	hook_cb->run_me = hook_cb->run_me->next;
    ++	if (hook_cb->run_me->list.next == hook_cb->head)
    ++		hook_cb->run_me = NULL;
    ++	else
    ++		hook_cb->run_me = list_entry(hook_cb->run_me->list.next,
    ++					     struct hook, list);
     +
     +	return 1;
     +}
    @@ hook.c: void run_hooks_opt_clear(struct run_hooks_opt *o)
     +	strbuf_addf(out, _("Couldn't start '%s', configured in '%s'\n"),
     +		    attempted->command.buf,
     +		    attempted->from_hookdir ? "hookdir"
    -+		    	: config_scope_name(attempted->origin));
    ++			: config_scope_name(attempted->origin));
     +
     +	/* NEEDSWORK: if halt_on_error is desired, do it here. */
     +	return 0;
    @@ hook.c: void run_hooks_opt_clear(struct run_hooks_opt *o)
     +
     +	/* NEEDSWORK: if halt_on_error is desired, do it here. */
     +	return 0;
    -+}
    -+
    + }
    + 
      int run_hooks(const char *hookname, struct run_hooks_opt *options)
      {
      	struct strbuf hookname_str = STRBUF_INIT;
    @@ hook.c: int run_hooks(const char *hookname, struct run_hooks_opt *options)
     -		struct child_process hook_proc = CHILD_PROCESS_INIT;
      		struct hook *hook = list_entry(pos, struct hook, list);
      
    --		/* reopen the file for stdin; run_command closes it. */
    --		if (options->path_to_stdin)
    --			hook_proc.in = xopen(options->path_to_stdin, O_RDONLY);
    --		else
    --			hook_proc.no_stdin = 1;
    --
    --		hook_proc.env = options->env.v;
    --		hook_proc.stdout_to_stderr = 1;
    --		hook_proc.trace2_hook_name = hook->command.buf;
    --		hook_proc.use_shell = 1;
    --
    --		if (hook->from_hookdir) {
    --		    if (!should_include_hookdir(hook->command.buf, options->run_hookdir))
    + 		if (hook->from_hookdir &&
    + 		    !should_include_hookdir(hook->command.buf, options->run_hookdir))
     -			continue;
    --		    /*
    --		     * Commands from the config could be oneliners, but we know
    --		     * for certain that hookdir commands are not.
    --		     */
    --		    hook_proc.use_shell = 0;
    --		}
    --
    --		/* add command */
    --		strvec_push(&hook_proc.args, hook->command.buf);
    -+		if (hook->from_hookdir &&
    -+		    !should_include_hookdir(hook->command.buf, options->run_hookdir))
     +			    list_del(pos);
     +	}
    ++
    ++	if (list_empty(to_run))
    ++		return 0;
      
    --		/*
    --		 * add passed-in argv, without expanding - let the user get back
    --		 * exactly what they put in
    --		 */
    --		strvec_pushv(&hook_proc.args, options->args.v);
    +-		prepare_hook_cp(hook, options, &hook_proc);
     +	cb_data.head = to_run;
    -+	cb_data.run_me = to_run->next;
    ++	cb_data.run_me = list_entry(to_run->next, struct hook, list);
      
     -		rc |= run_command(&hook_proc);
     -	}
    @@ hook.h: enum hookdir_opt
      	/* Environment vars to be set for each hook */
     @@ hook.h: struct run_hooks_opt
      
    + 	/*
    + 	 * How should the hookdir be handled?
    +-	 * Leave the RUN_HOOKS_OPT_INIT default in most cases; this only needs
    ++	 * Leave the run_hooks_opt_init_*() default in most cases; this only needs
    + 	 * to be overridden if the user can override it at the command line.
    + 	 */
    + 	enum hookdir_opt run_hookdir;
    + 
      	/* Path to file which should be piped to stdin for each hook */
      	const char *path_to_stdin;
     +
     +	/* Number of threads to parallelize across */
     +	int jobs;
    - };
    - 
    --#define RUN_HOOKS_OPT_INIT  {   		\
    ++};
    ++
     +/*
     + * Callback provided to feed_pipe_fn and consume_sideband_fn.
     + */
     +struct hook_cb_data {
     +	int rc;
     +	struct list_head *head;
    -+	struct list_head *run_me;
    ++	struct hook *run_me;
     +	struct run_hooks_opt *options;
    -+};
    -+
    -+#define RUN_HOOKS_OPT_INIT_SYNC  {   		\
    - 	.env = STRVEC_INIT, 			\
    - 	.args = STRVEC_INIT, 			\
    - 	.path_to_stdin = NULL,			\
    -+	.jobs = 1,				\
    - 	.run_hookdir = configured_hookdir_opt()	\
    - }
    + };
      
    -+#define RUN_HOOKS_OPT_INIT_ASYNC {		\
    -+	.env = STRVEC_INIT, 			\
    -+	.args = STRVEC_INIT, 			\
    -+	.path_to_stdin = NULL,			\
    -+	.jobs = configured_hook_jobs(),		\
    -+	.run_hookdir = configured_hookdir_opt()	\
    -+}
    -+
    -+
    - void run_hooks_opt_init(struct run_hooks_opt *o);
    +-void run_hooks_opt_init(struct run_hooks_opt *o);
    ++void run_hooks_opt_init_sync(struct run_hooks_opt *o);
    ++void run_hooks_opt_init_async(struct run_hooks_opt *o);
      void run_hooks_opt_clear(struct run_hooks_opt *o);
      
    + /*
13:  f84c879d5a <  -:  ---------- hook: allow specifying working directory for hooks
 -:  ---------- > 13:  0c4add98a4 hook: allow specifying working directory for hooks
14:  ac9cec6587 = 14:  1847c4c675 run-command: add stdin callback for parallelization
15:  71fca28ccf ! 15:  ab781c94d7 hook: provide stdin by string_list or callback
    @@ hook.c: static void append_or_move_hook(struct list_head *head, const char *comm
      	}
      
      	/* re-set the scope so we show where an override was specified */
    +@@ hook.c: void run_hooks_opt_init_sync(struct run_hooks_opt *o)
    + 	o->run_hookdir = configured_hookdir_opt();
    + 	o->jobs = 1;
    + 	o->dir = NULL;
    ++	o->feed_pipe = NULL;
    ++	o->feed_pipe_ctx = NULL;
    + }
    + 
    + void run_hooks_opt_init_async(struct run_hooks_opt *o)
     @@ hook.c: void run_hooks_opt_clear(struct run_hooks_opt *o)
    - {
    - 	strvec_clear(&o->env);
      	strvec_clear(&o->args);
    -+	string_list_clear(&o->str_stdin, 0);
      }
      
    - 
    -+static int pipe_from_string_list(struct strbuf *pipe, void *pp_cb, void *pp_task_cb)
    ++int pipe_from_string_list(struct strbuf *pipe, void *pp_cb, void *pp_task_cb)
     +{
     +	int *item_idx;
     +	struct hook *ctx = pp_task_cb;
    -+	struct string_list *to_pipe = &((struct hook_cb_data*)pp_cb)->options->str_stdin;
    ++	struct string_list *to_pipe = ((struct hook_cb_data*)pp_cb)->options->feed_pipe_ctx;
     +
     +	/* Bootstrap the state manager if necessary. */
     +	if (!ctx->feed_pipe_cb_data) {
    @@ hook.c: int run_hooks(const char *hookname, struct run_hooks_opt *options)
      	if (!options)
      		BUG("a struct run_hooks_opt must be provided to run_hooks");
      
    -+	if ((options->path_to_stdin && options->str_stdin.nr) ||
    -+	    (options->path_to_stdin && options->feed_pipe) ||
    -+	    (options->str_stdin.nr && options->feed_pipe))
    ++	if (options->path_to_stdin && options->feed_pipe)
     +		BUG("choose only one method to populate stdin");
    -+
    -+	if (options->str_stdin.nr)
    -+		options->feed_pipe = &pipe_from_string_list;
     +
      	strbuf_addstr(&hookname_str, hookname);
      
    @@ hook.h
      #include "strvec.h"
     +#include "run-command.h"
      
    - struct hook
    - {
    -@@ hook.h: struct hook
    + struct hook {
    + 	struct list_head list;
    +@@ hook.h: struct hook {
      	/* The literal command to run. */
      	struct strbuf command;
    - 	int from_hookdir;
    + 	unsigned from_hookdir : 1;
     +
     +	/*
     +	 * Use this to keep state for your feed_pipe_fn if you are using
    @@ hook.h: struct run_hooks_opt
      
      	/* Path to file which should be piped to stdin for each hook */
      	const char *path_to_stdin;
    -+	/* Pipe each string to stdin, separated by newlines */
    -+	struct string_list str_stdin;
     +	/*
     +	 * Callback and state pointer to ask for more content to pipe to stdin.
     +	 * Will be called repeatedly, for each hook. See
     +	 * hook.c:pipe_from_stdin() for an example. Keep per-hook state in
     +	 * hook.feed_pipe_cb_data (per process). Keep initialization context in
     +	 * feed_pipe_ctx (shared by all processes).
    ++	 *
    ++	 * See 'pipe_from_string_list()' for info about how to specify a
    ++	 * string_list as the stdin input instead of writing your own handler.
     +	 */
     +	feed_pipe_fn feed_pipe;
     +	void *feed_pipe_ctx;
    @@ hook.h: struct run_hooks_opt
     +
      };
      
    ++/*
    ++ * To specify a 'struct string_list', set 'run_hooks_opt.feed_pipe_ctx' to the
    ++ * string_list and set 'run_hooks_opt.feed_pipe' to 'pipe_from_string_list()'.
    ++ * This will pipe each string in the list to stdin, separated by newlines.  (Do
    ++ * not inject your own newlines.)
    ++ */
    ++int pipe_from_string_list(struct strbuf *pipe, void *pp_cb, void *pp_task_cb);
    ++
      /*
    -@@ hook.h: struct hook_cb_data {
    - 	.path_to_stdin = NULL,			\
    - 	.jobs = 1,				\
    - 	.dir = NULL,				\
    -+	.str_stdin = STRING_LIST_INIT_DUP,	\
    -+	.feed_pipe = NULL,			\
    -+	.feed_pipe_ctx = NULL,			\
    - 	.run_hookdir = configured_hookdir_opt()	\
    - }
    - 
    -@@ hook.h: struct hook_cb_data {
    - 	.path_to_stdin = NULL,			\
    - 	.jobs = configured_hook_jobs(),		\
    - 	.dir = NULL,				\
    -+	.str_stdin = STRING_LIST_INIT_DUP,	\
    -+	.feed_pipe = NULL,			\
    -+	.feed_pipe_ctx = NULL,			\
    - 	.run_hookdir = configured_hookdir_opt()	\
    - }
    - 
    +  * Callback provided to feed_pipe_fn and consume_sideband_fn.
    +  */
16:  98253fa8fd = 16:  c51bf46e8d run-command: allow capturing of collated output
17:  9505812b74 ! 17:  b90a4ee79b hooks: allow callers to capture output
    @@ Commit message
         Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
     
      ## hook.c ##
    +@@ hook.c: void run_hooks_opt_init_sync(struct run_hooks_opt *o)
    + 	o->dir = NULL;
    + 	o->feed_pipe = NULL;
    + 	o->feed_pipe_ctx = NULL;
    ++	o->consume_sideband = NULL;
    + }
    + 
    + void run_hooks_opt_init_async(struct run_hooks_opt *o)
     @@ hook.c: int run_hooks(const char *hookname, struct run_hooks_opt *options)
      				   pick_next_hook,
      				   notify_start_failure,
    @@ hook.h: struct run_hooks_opt
      	/* Number of threads to parallelize across */
      	int jobs;
      
    -@@ hook.h: struct hook_cb_data {
    - 	.str_stdin = STRING_LIST_INIT_DUP,	\
    - 	.feed_pipe = NULL,			\
    - 	.feed_pipe_ctx = NULL,			\
    -+	.consume_sideband = NULL,		\
    - 	.run_hookdir = configured_hookdir_opt()	\
    - }
    - 
    -@@ hook.h: struct hook_cb_data {
    - 	.str_stdin = STRING_LIST_INIT_DUP,	\
    - 	.feed_pipe = NULL,			\
    - 	.feed_pipe_ctx = NULL,			\
    -+	.consume_sideband = NULL,		\
    - 	.run_hookdir = configured_hookdir_opt()	\
    - }
    - 

  reply	other threads:[~2021-03-17 19:17 UTC|newest]

Thread overview: 479+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-11  2:10 [PATCH v8 00/37] config-based hooks Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 01/37] doc: propose hooks managed by the config Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 02/37] hook: scaffolding for git-hook subcommand Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 03/37] hook: add list command Emily Shaffer
2021-03-12  8:20   ` Ævar Arnfjörð Bjarmason
2021-03-24 17:31     ` Emily Shaffer
2021-03-25 12:36       ` Ævar Arnfjörð Bjarmason
2021-03-11  2:10 ` [PATCH v8 04/37] hook: include hookdir hook in list Emily Shaffer
2021-03-12  8:30   ` Ævar Arnfjörð Bjarmason
2021-03-24 17:56     ` Emily Shaffer
2021-03-24 19:11       ` Junio C Hamano
2021-03-24 19:23         ` Eric Sunshine
2021-03-24 20:07           ` Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 05/37] hook: teach hook.runHookDir Emily Shaffer
2021-03-12  8:33   ` Ævar Arnfjörð Bjarmason
2021-03-24 18:46     ` Emily Shaffer
2021-03-24 22:38       ` Ævar Arnfjörð Bjarmason
2021-03-11  2:10 ` [PATCH v8 06/37] hook: implement hookcmd.<name>.skip Emily Shaffer
2021-03-12  8:49   ` Ævar Arnfjörð Bjarmason
2021-03-11  2:10 ` [PATCH v8 07/37] parse-options: parse into strvec Emily Shaffer
2021-03-12  8:50   ` Ævar Arnfjörð Bjarmason
2021-03-24 20:34     ` Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 08/37] hook: add 'run' subcommand Emily Shaffer
2021-03-12  8:54   ` Ævar Arnfjörð Bjarmason
2021-03-24 21:29     ` Emily Shaffer
2021-03-12 10:22   ` Junio C Hamano
2021-03-11  2:10 ` [PATCH v8 09/37] hook: introduce hook_exists() Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 10/37] hook: support passing stdin to hooks Emily Shaffer
2021-03-12  9:00   ` Ævar Arnfjörð Bjarmason
2021-03-12 10:22   ` Junio C Hamano
2021-03-11  2:10 ` [PATCH v8 11/37] run-command: allow stdin for run_processes_parallel Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 12/37] hook: allow parallel hook execution Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 13/37] hook: allow specifying working directory for hooks Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 14/37] run-command: add stdin callback for parallelization Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 15/37] hook: provide stdin by string_list or callback Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 16/37] run-command: allow capturing of collated output Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 17/37] hooks: allow callers to capture output Emily Shaffer
2021-03-12  9:08   ` Ævar Arnfjörð Bjarmason
2021-03-24 21:54     ` Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 18/37] commit: use config-based hooks Emily Shaffer
2021-03-12 10:22   ` Junio C Hamano
2021-03-11  2:10 ` [PATCH v8 19/37] am: convert applypatch hooks to use config Emily Shaffer
2021-03-12 10:23   ` Junio C Hamano
2021-03-29 23:39     ` Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 20/37] merge: use config-based hooks for post-merge hook Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 21/37] gc: use hook library for pre-auto-gc hook Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 22/37] rebase: teach pre-rebase to use hook.h Emily Shaffer
2021-03-12 10:24   ` Junio C Hamano
2021-03-11  2:10 ` [PATCH v8 23/37] read-cache: convert post-index-change hook to use config Emily Shaffer
2021-03-12 10:22   ` Junio C Hamano
2021-03-29 23:56     ` Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 24/37] receive-pack: convert push-to-checkout hook to hook.h Emily Shaffer
2021-03-12 10:24   ` Junio C Hamano
2021-03-29 23:59     ` Emily Shaffer
2021-03-30  0:10       ` Junio C Hamano
2021-03-11  2:10 ` [PATCH v8 25/37] git-p4: use 'git hook' to run hooks Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 26/37] hooks: convert 'post-checkout' hook to hook library Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 27/37] hook: convert 'post-rewrite' hook to config Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 28/37] transport: convert pre-push hook to use config Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 29/37] reference-transaction: look for hooks in config Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 30/37] receive-pack: convert 'update' hook to hook.h Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 31/37] proc-receive: acquire hook list from hook.h Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 32/37] post-update: use hook.h library Emily Shaffer
2021-03-12  9:14   ` Ævar Arnfjörð Bjarmason
2021-03-30  0:01     ` Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 33/37] receive-pack: convert receive hooks to hook.h Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 34/37] bugreport: use hook_exists instead of find_hook Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 35/37] git-send-email: use 'git hook run' for 'sendemail-validate' Emily Shaffer
2021-03-12  9:21   ` Ævar Arnfjörð Bjarmason
2021-03-30  0:03     ` Emily Shaffer
2021-03-31 21:47     ` Emily Shaffer
2021-03-31 22:06       ` Junio C Hamano
2021-04-01 18:08         ` Emily Shaffer
2021-04-01 18:55           ` Junio C Hamano
2021-04-02 11:34       ` [PATCH 0/2] git-send-email: refactor duplicate $? checks into a function Ævar Arnfjörð Bjarmason
2021-04-02 11:34         ` [PATCH 1/2] git-send-email: replace "map" in void context with "for" Ævar Arnfjörð Bjarmason
2021-04-02 21:31           ` Junio C Hamano
2021-04-02 21:37             ` Emily Shaffer
2021-04-02 11:34         ` [PATCH 2/2] git-send-email: refactor duplicate $? checks into a function Ævar Arnfjörð Bjarmason
2021-04-02 21:36           ` Junio C Hamano
2021-04-04  9:19         ` [PATCH v2 0/4] refactor duplicate $? checks into a function + improve errors Ævar Arnfjörð Bjarmason
2021-04-04  9:19           ` [PATCH v2 1/4] git-send-email: replace "map" in void context with "for" Ævar Arnfjörð Bjarmason
2021-04-04  9:19           ` [PATCH v2 2/4] git-send-email: refactor duplicate $? checks into a function Ævar Arnfjörð Bjarmason
2021-04-05 19:11             ` Junio C Hamano
2021-04-05 23:47             ` Junio C Hamano
2021-04-08 22:43               ` Junio C Hamano
2021-04-08 22:46                 ` Junio C Hamano
2021-04-08 23:54                   ` Ævar Arnfjörð Bjarmason
2021-04-09  0:08                     ` Junio C Hamano
2021-05-03 20:30                       ` Emily Shaffer
2021-04-04  9:19           ` [PATCH v2 3/4] git-send-email: test full --validate output Ævar Arnfjörð Bjarmason
2021-04-04  9:19           ` [PATCH v2 4/4] git-send-email: improve --validate error output Ævar Arnfjörð Bjarmason
2021-04-05 19:14             ` Junio C Hamano
2021-04-06 14:00           ` [PATCH v3 0/3] refactor duplicate $? checks into a function + improve errors Ævar Arnfjörð Bjarmason
2021-04-06 14:00             ` [PATCH v3 1/3] git-send-email: test full --validate output Ævar Arnfjörð Bjarmason
2021-04-06 14:00             ` [PATCH v3 2/3] git-send-email: refactor duplicate $? checks into a function Ævar Arnfjörð Bjarmason
2021-04-06 14:00             ` [PATCH v3 3/3] git-send-email: improve --validate error output Ævar Arnfjörð Bjarmason
2021-04-06 20:33             ` [PATCH v3 0/3] refactor duplicate $? checks into a function + improve errors Junio C Hamano
2021-03-12 23:29   ` [PATCH v8 35/37] git-send-email: use 'git hook run' for 'sendemail-validate' Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 36/37] run-command: stop thinking about hooks Emily Shaffer
2021-03-12  9:23   ` Ævar Arnfjörð Bjarmason
2021-03-30  0:07     ` Emily Shaffer
2021-03-11  2:10 ` [PATCH v8 37/37] docs: unify githooks and git-hook manpages Emily Shaffer
2021-03-12  9:29   ` Ævar Arnfjörð Bjarmason
2021-03-30  0:10     ` Emily Shaffer
2021-04-07  2:36   ` Junio C Hamano
2021-04-08 20:20     ` Jeff Hostetler
2021-04-08 21:17       ` Junio C Hamano
2021-04-08 23:46     ` Emily Shaffer
2021-04-09  0:03       ` Junio C Hamano
2021-03-11 22:26 ` [PATCH v8 00/37] config-based hooks Junio C Hamano
2021-03-12 23:27   ` Emily Shaffer
2021-03-12  9:49 ` Ævar Arnfjörð Bjarmason
2021-03-17 18:41   ` Emily Shaffer
2021-03-17 19:16     ` Emily Shaffer [this message]
2021-03-12 11:13 ` Ævar Arnfjörð Bjarmason
2021-03-25 12:41   ` Ævar Arnfjörð Bjarmason
2021-05-27  0:08 ` [PATCH v9 00/37] propose " Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 01/37] doc: propose hooks managed by the config Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 02/37] hook: introduce git-hook subcommand Emily Shaffer
2021-05-27  2:18     ` Junio C Hamano
2021-05-27  0:08   ` [PATCH v9 03/37] hook: include hookdir hook in list Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 04/37] hook: teach hook.runHookDir Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 05/37] hook: implement hookcmd.<name>.skip Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 06/37] parse-options: parse into strvec Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 07/37] hook: add 'run' subcommand Emily Shaffer
2021-06-03  9:07     ` Ævar Arnfjörð Bjarmason
2021-06-03 22:29       ` Junio C Hamano
2021-05-27  0:08   ` [PATCH v9 08/37] hook: introduce hook_exists() Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 09/37] hook: support passing stdin to hooks Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 10/37] run-command: allow stdin for run_processes_parallel Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 11/37] hook: allow parallel hook execution Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 12/37] hook: allow specifying working directory for hooks Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 13/37] run-command: add stdin callback for parallelization Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 14/37] hook: provide stdin by string_list or callback Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 15/37] run-command: allow capturing of collated output Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 16/37] hooks: allow callers to capture output Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 17/37] commit: use config-based hooks Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 18/37] am: convert applypatch hooks to use config Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 19/37] merge: use config-based hooks for post-merge hook Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 20/37] gc: use hook library for pre-auto-gc hook Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 21/37] rebase: teach pre-rebase to use hook.h Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 22/37] read-cache: convert post-index-change hook to use config Emily Shaffer
2021-05-27 23:04     ` Ævar Arnfjörð Bjarmason
2021-05-28  1:09       ` Taylor Blau
2021-05-31 19:21       ` Felipe Contreras
2021-05-27  0:08   ` [PATCH v9 23/37] receive-pack: convert push-to-checkout hook to hook.h Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 24/37] git-p4: use 'git hook' to run hooks Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 25/37] hooks: convert 'post-checkout' hook to hook library Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 26/37] hook: convert 'post-rewrite' hook to config Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 27/37] transport: convert pre-push hook to use config Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 28/37] reference-transaction: look for hooks in config Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 29/37] receive-pack: convert 'update' hook to hook.h Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 30/37] proc-receive: acquire hook list from hook.h Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 31/37] post-update: use hook.h library Emily Shaffer
2021-06-14  9:09     ` Ævar Arnfjörð Bjarmason
2021-05-27  0:08   ` [PATCH v9 32/37] receive-pack: convert receive hooks to hook.h Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 33/37] bugreport: use hook_exists instead of find_hook Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 34/37] git-send-email: use 'git hook run' for 'sendemail-validate' Emily Shaffer
2021-05-27 11:56     ` Ævar Arnfjörð Bjarmason
2021-05-27  0:08   ` [PATCH v9 35/37] run-command: stop thinking about hooks Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 36/37] doc: clarify fsmonitor-watchman specification Emily Shaffer
2021-05-27  0:08   ` [PATCH v9 37/37] docs: link githooks and git-hook manpages Emily Shaffer
2021-06-03  9:18     ` Ævar Arnfjörð Bjarmason
2021-05-27 11:49   ` [PATCH v9 00/37] propose config-based hooks Ævar Arnfjörð Bjarmason
2021-05-27 13:36   ` Ævar Arnfjörð Bjarmason
2021-05-27 17:46     ` Felipe Contreras
2021-05-28 12:11     ` [PATCH 00/31] minimal restart of "config-based-hooks" Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 01/31] hooks tests: don't leave "actual" nonexisting on failure Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 02/31] gc tests: add a test for the "pre-auto-gc" hook Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 03/31] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 04/31] run-command.h: move find_hook() to hook.h Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 05/31] hook.c: add a hook_exists() wrapper and use it in bugreport.c Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 06/31] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 07/31] rebase: teach pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 08/31] am: convert applypatch hooks to use config Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 09/31] hooks: convert 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 10/31] merge: use config-based hooks for post-merge hook Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 11/31] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 12/31] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 13/31] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 14/31] commit: use hook.h to execute hooks Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 15/31] read-cache: convert post-index-change hook to use config Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 16/31] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
2021-06-02  0:51         ` Felipe Contreras
2021-05-28 12:11       ` [PATCH 17/31] run-command: allow stdin for run_processes_parallel Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 18/31] hook: support passing stdin to hooks Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 19/31] am: convert 'post-rewrite' hook to hook.h Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 20/31] run-command: add stdin callback for parallelization Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 21/31] hook: provide stdin by string_list or callback Ævar Arnfjörð Bjarmason
2021-06-02  1:00         ` Felipe Contreras
2021-05-28 12:11       ` [PATCH 22/31] hook: convert 'post-rewrite' hook in sequencer.c to hook.h Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 23/31] transport: convert pre-push hook to use config Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 24/31] reference-transaction: use hook.h to run hooks Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 25/31] run-command: allow capturing of collated output Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 26/31] hooks: allow callers to capture output Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 27/31] receive-pack: convert 'update' hook to hook.h Ævar Arnfjörð Bjarmason
2021-06-02  1:04         ` Felipe Contreras
2021-05-28 12:11       ` [PATCH 28/31] post-update: use hook.h library Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 29/31] receive-pack: convert receive hooks to hook.h Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 30/31] hooks: fix a TOCTOU in "did we run a hook?" heuristic Ævar Arnfjörð Bjarmason
2021-05-28 12:48         ` Bagas Sanjaya
2021-05-28 14:11           ` Ævar Arnfjörð Bjarmason
2021-05-28 12:11       ` [PATCH 31/31] hook-list.h: add a generated list of hooks, like config-list.h Ævar Arnfjörð Bjarmason
2021-06-01  1:00         ` Ævar Arnfjörð Bjarmason
2021-06-01 18:14       ` [PATCH 00/31] minimal restart of "config-based-hooks" Emily Shaffer
2021-06-01 20:50         ` Derrick Stolee
2021-06-02  5:42           ` Felipe Contreras
2021-06-02  7:46             ` Ævar Arnfjörð Bjarmason
2021-06-02  9:34           ` Ævar Arnfjörð Bjarmason
2021-06-02  5:30         ` Felipe Contreras
2021-06-02  7:56         ` Ævar Arnfjörð Bjarmason
2021-06-02  9:39           ` Ævar Arnfjörð Bjarmason
2021-06-25 18:14           ` Felipe Contreras
2021-06-14 10:32       ` [PATCH v2 00/30] Minimal " Ævar Arnfjörð Bjarmason
2021-06-14 10:32         ` [PATCH v2 01/30] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-06-14 21:33           ` Emily Shaffer
2021-06-15  9:36             ` Ævar Arnfjörð Bjarmason
2021-06-18 22:13               ` Emily Shaffer
2021-06-20 19:30                 ` Ævar Arnfjörð Bjarmason
2021-06-21  3:44                   ` Junio C Hamano
2021-06-22  0:00                   ` Emily Shaffer
2021-06-29  1:12                     ` Junio C Hamano
2021-06-25 19:02                 ` Felipe Contreras
2021-06-25 19:08             ` Felipe Contreras
2021-06-14 10:32         ` [PATCH v2 02/30] run-command.h: move find_hook() to hook.h Ævar Arnfjörð Bjarmason
2021-06-14 10:32         ` [PATCH v2 03/30] hook.c: add a hook_exists() wrapper and use it in bugreport.c Ævar Arnfjörð Bjarmason
2021-06-14 10:32         ` [PATCH v2 04/30] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
2021-06-14 23:57           ` Emily Shaffer
2021-06-14 10:32         ` [PATCH v2 05/30] rebase: teach pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
2021-06-14 10:32         ` [PATCH v2 06/30] am: convert applypatch hooks to use config Ævar Arnfjörð Bjarmason
2021-06-14 10:32         ` [PATCH v2 07/30] hooks: convert 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
2021-06-14 10:32         ` [PATCH v2 08/30] merge: use config-based hooks for post-merge hook Ævar Arnfjörð Bjarmason
2021-06-14 10:32         ` [PATCH v2 09/30] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
2021-06-14 10:32         ` [PATCH v2 10/30] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 11/30] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 12/30] commit: use hook.h to execute hooks Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 13/30] read-cache: convert post-index-change hook to use config Ævar Arnfjörð Bjarmason
2021-06-25 18:32           ` Felipe Contreras
2021-06-14 10:33         ` [PATCH v2 14/30] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 15/30] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
2021-06-25 18:34           ` Felipe Contreras
2021-06-14 10:33         ` [PATCH v2 16/30] run-command: allow stdin for run_processes_parallel Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 17/30] hook: support passing stdin to hooks Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 18/30] am: convert 'post-rewrite' hook to hook.h Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 19/30] run-command: add stdin callback for parallelization Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 20/30] hook: provide stdin by string_list or callback Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 21/30] hook: convert 'post-rewrite' hook in sequencer.c to hook.h Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 22/30] transport: convert pre-push hook to use config Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 23/30] reference-transaction: use hook.h to run hooks Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 24/30] run-command: allow capturing of collated output Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 25/30] hooks: allow callers to capture output Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 26/30] receive-pack: convert 'update' hook to hook.h Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 27/30] post-update: use hook.h library Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 28/30] receive-pack: convert receive hooks to hook.h Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 29/30] hooks: fix a TOCTOU in "did we run a hook?" heuristic Ævar Arnfjörð Bjarmason
2021-06-14 10:33         ` [PATCH v2 30/30] hook-list.h: add a generated list of hooks, like config-list.h Ævar Arnfjörð Bjarmason
2021-06-15 10:02           ` Ævar Arnfjörð Bjarmason
2021-06-14 20:22         ` [PATCH v2 00/30] Minimal restart of "config-based-hooks" Emily Shaffer
2021-06-16  0:45           ` Junio C Hamano
2021-06-17 10:22         ` [PATCH 00/27] Base for "config-based-hooks" Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 01/27] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 02/27] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
2021-07-22 21:58             ` Emily Shaffer
2021-06-17 10:22           ` [PATCH 03/27] rebase: teach pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 04/27] am: convert applypatch hooks to use config Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 05/27] hooks: convert 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 06/27] merge: use config-based hooks for post-merge hook Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 07/27] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
2021-07-02 23:47             ` Emily Shaffer
2021-06-17 10:22           ` [PATCH 08/27] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 09/27] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 10/27] commit: use hook.h to execute hooks Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 11/27] read-cache: convert post-index-change hook to use config Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 12/27] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 13/27] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 14/27] run-command: allow stdin for run_processes_parallel Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 15/27] hook: support passing stdin to hooks Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 16/27] am: convert 'post-rewrite' hook to hook.h Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 17/27] run-command: add stdin callback for parallelization Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 18/27] hook: provide stdin by string_list or callback Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 19/27] hook: convert 'post-rewrite' hook in sequencer.c to hook.h Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 20/27] transport: convert pre-push hook to use config Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 21/27] reference-transaction: use hook.h to run hooks Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 22/27] run-command: allow capturing of collated output Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 23/27] hooks: allow callers to capture output Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 24/27] receive-pack: convert 'update' hook to hook.h Ævar Arnfjörð Bjarmason
2021-06-17 10:22           ` [PATCH 25/27] post-update: use hook.h library Ævar Arnfjörð Bjarmason
2021-06-17 10:23           ` [PATCH 26/27] receive-pack: convert receive hooks to hook.h Ævar Arnfjörð Bjarmason
2021-06-17 10:23           ` [PATCH 27/27] hooks: fix a TOCTOU in "did we run a hook?" heuristic Ævar Arnfjörð Bjarmason
2021-06-18 22:09             ` Emily Shaffer
2021-07-15 23:25           ` [PATCH 0/9] config-based hooks restarted Emily Shaffer
2021-07-15 23:25             ` [PATCH 1/9] hook: run a list of hooks instead Emily Shaffer
2021-07-15 23:25             ` [PATCH 2/9] hook: allow parallel hook execution Emily Shaffer
2021-07-16  8:36               ` Ævar Arnfjörð Bjarmason
2021-07-22 21:12                 ` Emily Shaffer
2021-07-23  9:30                   ` Ævar Arnfjörð Bjarmason
2021-07-15 23:25             ` [PATCH 3/9] hook: introduce "git hook list" Emily Shaffer
2021-07-16  8:52               ` Ævar Arnfjörð Bjarmason
2021-07-22 22:18                 ` Emily Shaffer
2021-07-23  9:29                   ` Ævar Arnfjörð Bjarmason
2021-07-15 23:25             ` [PATCH 4/9] hook: treat hookdir hook specially Emily Shaffer
2021-07-16  8:58               ` Ævar Arnfjörð Bjarmason
2021-07-22 22:24                 ` Emily Shaffer
2021-07-23  9:26                   ` Ævar Arnfjörð Bjarmason
2021-07-23 17:33                   ` Felipe Contreras
2021-07-23 18:22                     ` Eric Sunshine
2021-07-23 20:02                       ` Felipe Contreras
2021-07-15 23:25             ` [PATCH 5/9] hook: allow running non-native hooks Emily Shaffer
2021-07-15 23:26             ` [PATCH 6/9] hook: include hooks from the config Emily Shaffer
2021-07-16  9:01               ` Ævar Arnfjörð Bjarmason
2021-07-22 22:51                 ` Emily Shaffer
2021-07-23  9:22                   ` Ævar Arnfjörð Bjarmason
2021-07-15 23:26             ` [PATCH 7/9] hook: allow out-of-repo 'git hook' invocations Emily Shaffer
2021-07-16  8:33               ` Ævar Arnfjörð Bjarmason
2021-07-22 23:07                 ` Emily Shaffer
2021-07-23  9:18                   ` Ævar Arnfjörð Bjarmason
2021-07-15 23:26             ` [PATCH 8/9] hook: teach 'hookcmd' config to alias hook scripts Emily Shaffer
2021-07-16  9:13               ` Ævar Arnfjörð Bjarmason
2021-07-22 23:31                 ` Emily Shaffer
2021-07-23  7:41                   ` Ævar Arnfjörð Bjarmason
2021-08-04 20:38                     ` Emily Shaffer
2021-08-05  0:17                       ` Ævar Arnfjörð Bjarmason
2021-08-05 21:45                         ` Emily Shaffer
2021-08-05 22:26                           ` Ævar Arnfjörð Bjarmason
2021-08-06 20:18                             ` Emily Shaffer
2021-08-04 21:49                     ` Jonathan Tan
2021-07-15 23:26             ` [PATCH 9/9] hook: implement hookcmd.<name>.skip Emily Shaffer
2021-07-28 20:39           ` [PATCH 00/27] Base for "config-based-hooks" Emily Shaffer
2021-08-03 19:38           ` [PATCH v4 00/36] Run hooks via "git run hook" & hook library Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 01/36] Makefile: mark "check" target as .PHONY Ævar Arnfjörð Bjarmason
2021-08-20  0:04               ` Emily Shaffer
2021-08-03 19:38             ` [PATCH v4 02/36] Makefile: stop hardcoding {command,config}-list.h Ævar Arnfjörð Bjarmason
2021-08-20  0:03               ` Emily Shaffer
2021-08-24 14:22                 ` Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 03/36] Makefile: remove an out-of-date comment Ævar Arnfjörð Bjarmason
2021-08-20  0:05               ` Emily Shaffer
2021-08-03 19:38             ` [PATCH v4 04/36] hook.[ch]: move find_hook() to this new library Ævar Arnfjörð Bjarmason
2021-08-20  0:08               ` Emily Shaffer
2021-08-03 19:38             ` [PATCH v4 05/36] hook.c: add a hook_exists() wrapper and use it in bugreport.c Ævar Arnfjörð Bjarmason
2021-08-20  0:09               ` Emily Shaffer
2021-08-03 19:38             ` [PATCH v4 06/36] hook.c users: use "hook_exists()" insted of "find_hook()" Ævar Arnfjörð Bjarmason
2021-08-20  0:10               ` Emily Shaffer
2021-08-03 19:38             ` [PATCH v4 07/36] hook-list.h: add a generated list of hooks, like config-list.h Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 08/36] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-08-04 10:15               ` Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 09/36] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 10/36] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 11/36] am: convert applypatch " Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 12/36] hooks: convert 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 13/36] merge: convert post-merge to use hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 14/36] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 15/36] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 16/36] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 17/36] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 18/36] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 19/36] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 20/36] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 21/36] run-command: allow stdin for run_processes_parallel Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 22/36] hook: support passing stdin to hooks Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 23/36] am: convert 'post-rewrite' hook to hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 24/36] run-command: add stdin callback for parallelization Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 25/36] hook: provide stdin by string_list or callback Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 26/36] hook: convert 'post-rewrite' hook in sequencer.c to hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 27/36] transport: convert pre-push hook " Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 28/36] hook tests: test for exact "pre-push" hook input Ævar Arnfjörð Bjarmason
2021-08-20  0:16               ` Emily Shaffer
2021-08-03 19:38             ` [PATCH v4 29/36] hook tests: use a modern style for "pre-push" tests Ævar Arnfjörð Bjarmason
2021-08-20  0:18               ` Emily Shaffer
2021-08-03 19:38             ` [PATCH v4 30/36] reference-transaction: use hook.h to run hooks Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 31/36] run-command: allow capturing of collated output Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 32/36] hooks: allow callers to capture output Ævar Arnfjörð Bjarmason
2021-08-03 19:38             ` [PATCH v4 33/36] receive-pack: convert 'update' hook to hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:39             ` [PATCH v4 34/36] post-update: use hook.h library Ævar Arnfjörð Bjarmason
2021-08-03 19:39             ` [PATCH v4 35/36] receive-pack: convert receive hooks to hook.h Ævar Arnfjörð Bjarmason
2021-08-03 19:39             ` [PATCH v4 36/36] hooks: fix a TOCTOU in "did we run a hook?" heuristic Ævar Arnfjörð Bjarmason
2021-08-12  0:42             ` [PATCH v2 0/6] config-based hooks restarted Emily Shaffer
2021-08-12  0:42               ` [PATCH v2 1/6] hook: run a list of hooks instead Emily Shaffer
2021-08-12 17:25                 ` Junio C Hamano
2021-08-16 23:38                   ` Emily Shaffer
2021-08-12  0:42               ` [PATCH v2 2/6] hook: allow parallel hook execution Emily Shaffer
2021-08-12 17:51                 ` Junio C Hamano
2021-08-16 23:59                   ` Emily Shaffer
2021-08-12  0:42               ` [PATCH v2 3/6] hook: introduce "git hook list" Emily Shaffer
2021-08-12 18:59                 ` Junio C Hamano
2021-08-17  0:36                   ` Emily Shaffer
2021-08-12  0:42               ` [PATCH v2 4/6] hook: allow running non-native hooks Emily Shaffer
2021-08-12 19:08                 ` Junio C Hamano
2021-08-18 20:51                   ` Emily Shaffer
2021-08-18 21:14                     ` Emily Shaffer
2021-08-18 21:24                       ` Junio C Hamano
2021-08-12  0:42               ` [PATCH v2 5/6] hook: include hooks from the config Emily Shaffer
2021-08-12 20:48                 ` Junio C Hamano
2021-08-19  0:09                   ` Emily Shaffer
2021-08-12  0:42               ` [PATCH v2 6/6] hook: allow out-of-repo 'git hook' invocations Emily Shaffer
2021-08-12  4:47               ` [PATCH v2 0/6] config-based hooks restarted Junio C Hamano
2021-08-12  5:02                 ` Junio C Hamano
2021-08-16 22:31                   ` Emily Shaffer
2021-08-19  3:34               ` [PATCH v3 " Emily Shaffer
2021-08-19  3:34                 ` [PATCH v3 1/6] hook: run a list of hooks instead Emily Shaffer
2021-08-24 14:56                   ` Ævar Arnfjörð Bjarmason
2021-08-26 21:16                     ` Emily Shaffer
2021-08-27 11:15                       ` Ævar Arnfjörð Bjarmason
2021-08-19  3:34                 ` [PATCH v3 2/6] hook: allow parallel hook execution Emily Shaffer
2021-08-24 15:01                   ` Ævar Arnfjörð Bjarmason
2021-08-24 16:13                     ` Eric Sunshine
2021-08-26 22:36                     ` Emily Shaffer
2021-08-19  3:34                 ` [PATCH v3 3/6] hook: introduce "git hook list" Emily Shaffer
2021-08-24 15:08                   ` Ævar Arnfjörð Bjarmason
2021-08-26 21:43                     ` Emily Shaffer
2021-08-24 15:53                   ` Ævar Arnfjörð Bjarmason
2021-08-26 22:38                     ` Emily Shaffer
2021-08-19  3:34                 ` [PATCH v3 4/6] hook: allow running non-native hooks Emily Shaffer
2021-08-24 15:55                   ` Ævar Arnfjörð Bjarmason
2021-08-26 22:50                     ` Emily Shaffer
2021-08-27  0:22                       ` Junio C Hamano
2021-08-19  3:34                 ` [PATCH v3 5/6] hook: include hooks from the config Emily Shaffer
2021-08-19 22:39                   ` Junio C Hamano
2021-08-19 23:43                     ` Emily Shaffer
2021-08-19 23:48                       ` Junio C Hamano
2021-08-24 19:30                   ` Ævar Arnfjörð Bjarmason
2021-08-31 19:05                     ` Emily Shaffer
2021-08-19  3:34                 ` [PATCH v3 6/6] hook: allow out-of-repo 'git hook' invocations Emily Shaffer
2021-08-24 20:12                   ` Ævar Arnfjörð Bjarmason
2021-08-24 20:38                     ` Randall S. Becker
2021-08-24 22:45                       ` Ævar Arnfjörð Bjarmason
2021-08-31 21:09                     ` Emily Shaffer
2021-08-24 20:29                 ` [PATCH v3 0/6] config-based hooks restarted Ævar Arnfjörð Bjarmason
2021-09-02 22:01                   ` Emily Shaffer
2021-09-09 12:41                 ` [PATCH v4 0/5] " Ævar Arnfjörð Bjarmason
2021-09-09 12:41                   ` [PATCH v4 1/5] hook: run a list of hooks instead Ævar Arnfjörð Bjarmason
2021-09-09 12:59                     ` [PATCH v4] fixup! " Ævar Arnfjörð Bjarmason
2021-09-09 12:42                   ` [PATCH v4 2/5] hook: allow parallel hook execution Ævar Arnfjörð Bjarmason
2021-09-09 12:42                   ` [PATCH v4 3/5] hook: introduce "git hook list" Ævar Arnfjörð Bjarmason
2021-09-09 12:42                   ` [PATCH v4 4/5] hook: include hooks from the config Ævar Arnfjörð Bjarmason
2021-09-09 12:42                   ` [PATCH v4 5/5] hook: allow out-of-repo 'git hook' invocations Ævar Arnfjörð Bjarmason
2021-08-19  0:17             ` [PATCH v4 00/36] Run hooks via "git run hook" & hook library Emily Shaffer
2021-08-19 23:40             ` Emily Shaffer
2021-09-02  7:21               ` Ævar Arnfjörð Bjarmason
2021-09-02 13:11             ` [PATCH v5 " Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 01/36] Makefile: mark "check" target as .PHONY Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 02/36] Makefile: stop hardcoding {command,config}-list.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 03/36] Makefile: remove an out-of-date comment Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 04/36] hook.[ch]: move find_hook() from run-command.c to hook.c Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 05/36] hook.c: add a hook_exists() wrapper and use it in bugreport.c Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 06/36] hook.c users: use "hook_exists()" instead of "find_hook()" Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 07/36] hook-list.h: add a generated list of hooks, like config-list.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 08/36] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 09/36] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 10/36] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 11/36] am: convert applypatch " Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 12/36] hooks: convert 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 13/36] merge: convert post-merge to use hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 14/36] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 15/36] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 16/36] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 17/36] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 18/36] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 19/36] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 20/36] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 21/36] run-command: allow stdin for run_processes_parallel Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 22/36] hook: support passing stdin to hooks Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 23/36] am: convert 'post-rewrite' hook to hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 24/36] run-command: add stdin callback for parallelization Ævar Arnfjörð Bjarmason
2021-10-06 11:03                 ` ab/config-based-hooks-N status (was Re: [PATCH v5 24/36] run-command: add stdin callback for parallelization) Ævar Arnfjörð Bjarmason
2021-10-12 12:59                   ` Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 25/36] hook: provide stdin by string_list or callback Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 26/36] hook: convert 'post-rewrite' hook in sequencer.c to hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 27/36] transport: convert pre-push hook " Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 28/36] hook tests: test for exact "pre-push" hook input Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 29/36] hook tests: use a modern style for "pre-push" tests Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 30/36] reference-transaction: use hook.h to run hooks Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 31/36] run-command: allow capturing of collated output Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 32/36] hooks: allow callers to capture output Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 33/36] receive-pack: convert 'update' hook to hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 34/36] post-update: use hook.h library Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 35/36] receive-pack: convert receive hooks to hook.h Ævar Arnfjörð Bjarmason
2021-09-02 13:11               ` [PATCH v5 36/36] hooks: fix a TOCTOU in "did we run a hook?" heuristic Ævar Arnfjörð Bjarmason
2021-06-25 18:22         ` [PATCH v2 00/30] Minimal restart of "config-based-hooks" Felipe Contreras

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YFJVp+5IVJux9Vbe@google.com \
    --to=emilyshaffer@google.com \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=james@jramsay.com.au \
    --cc=jonathantanmy@google.com \
    --cc=jrnieder@gmail.com \
    --cc=peff@peff.net \
    --cc=phillip.wood123@gmail.com \
    --cc=sandals@crustytoothpaste.net \
    --cc=steadmon@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.