git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] commit: skip discarding the index if there is no pre-commit hook

From
Jeff King <peff@peff.net>
Date
Aug 10, 2017, 19:16 UTC
Message-ID
<20170810191613.kpmhzg4seyxy3cpq@sigill.intra.peff.net>
In-Reply-To
<20170810185416.8224-1-kewillf@microsoft.com>
On Thu, Aug 10, 2017 at 02:54:16PM -0400, Kevin Willford wrote:
Show 5 quoted lines
> If there is not a pre-commit hook, there is no reason to discard
> the index and reread it.
> 
> This change checks to presence of a pre-commit hook and then only
> discards the index if there was one.
Sounds like a smart optimization.
Show 9 quoted lines
> diff --git a/builtin/commit.c b/builtin/commit.c
> index e7a2cb6285..443949d87b 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -671,12 +671,22 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  	const char *hook_arg2 = NULL;
>  	int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
>  	int old_display_comment_prefix;
> +	const char *precommit_hook = NULL;

The return value from find_hook() points to storage that may later be overwritten or even freed. I know your patch doesn't actually look at the contents of precommit_hook, but it seems like it's setting up a potential bomb for somebody later.

Can we make this:
  int have_precommit_hook = 0;
  ...
  have_precommit_hook = !!find_hook("pre-commit");
? Though see below.
Show 13 quoted lines
> -	if (!no_verify && run_commit_hook(use_editor, index_file, "pre-commit", NULL))
> -		return 0;
> +
> +	if (!no_verify) {
> +		/*
> +		 * Check to see if there is a pre-commit hook
> +		 * If there not one we can skip discarding the index later on
> +		 */
> +		precommit_hook = find_hook("pre-commit");
> +		if (precommit_hook &&
> +		    run_commit_hook(use_editor, index_file, "pre-commit", NULL))
> +			return 0;
> +	}

We'll find the hook again in run_commit_hook(), but it's not so expensive that it's worth trying to pass down the hook path we found (and if we switch to an integer flag we don't have the path anyway ;) ).

But note that we don't even care about precommit_hook here. We could just call run_commit_hook() regardless. We only care later whether we ran it or not. So we could drop this hunk and the precommit_hook variable entirely, and...

Show 18 quoted lines
> @@ -940,12 +950,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  		return 0;
>  	}
>  
> -	/*
> -	 * Re-read the index as pre-commit hook could have updated it,
> -	 * and write it out as a tree.  We must do this before we invoke
> -	 * the editor and after we invoke run_status above.
> -	 */
> -	discard_cache();
> +	if (!no_verify && precommit_hook) {
> +		/*
> +		 * Re-read the index as pre-commit hook could have updated it,
> +		 * and write it out as a tree.  We must do this before we invoke
> +		 * the editor and after we invoke run_status above.
> +		 */
> +		discard_cache();
> +	}
Just make this:
  if (!no_verify && find_hook("pre-commit"))
     ... discard cache ...

That is racy if somebody removes the hook while we're running (so is your patch, but in the opposite direction). What we really want to know is "did we run the hook" and annoyingly run_hook_ve() doesn't tell us that. So I think the most robust solution would be refactoring that to pass out the information, and then use the flag here. But I'm not sure it's actually worth worrying about such a race in practice.

-Peff
Previous: Kevin WillfordNext: Junio C Hamano
Message 2 of 8 in “commit: skip discarding the index if there is no pre-commit hook”
  1. commit: skip discarding the index if there is no pre-commit hookKevin Willford, Aug 10, 2017
  2. Jeff KingAug 10, 2017
  3. Junio C HamanoAug 10, 2017
  4. commit: skip discarding the index if there is no pre-commit hookKevin Willford, Aug 14, 2017
  5. Jeff KingAug 14, 2017
  6. Kevin WillfordAug 15, 2017
  7. Jeff KingAug 15, 2017
  8. Junio C HamanoAug 15, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.