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

Re: Interaction between pre-commit hook and git commit <pathspec>

From
Chris Torek <chris.torek@gmail.com>
Date
Nov 3, 2026, 20:43 UTC
Message-ID
<CAPx1Gvd3H2-e5RBoH9e1r0cWqe2uo1tm-eUSop0ffNBc2Pj6tg@mail.gmail.com>
In-Reply-To
<CY8PR17MB6236D16AD8CD80720FF1342DAE692@CY8PR17MB6236.namprd17.prod.outlook.com>
On Tue, Nov 3, 2026 at 12:00 PM Kevin Lyles <klyles@epic.com> wrote:
Show 5 quoted lines
> The documentation for the pathspec option of the commit command claims:
> "The contents of these files are also staged for the next commit on top
> of what have been staged before."
> However, that appears to only be true if the pre-commit hook doesn't
> modify the index contents.
There's an implementation detail here that makes this tricky.

Git documentation talks about "the" index / staging-area. Or, more precisely, there is one such entity per work-tree: the work-tree's index.

But when you use "git commit --only" or "git commit --include", well, now there is a big problem to deal with. If the commit is accepted, the ("the") index / staging-area should be updated accordingly. But if it's aborted, the index should roll back to how it was before you ran "git commit [--only | --include] <pathspecs>".

In order to make this work internally, Git actually needs two or even three index-es (indices?) / staging-areas for the work-tree in question: the one for "before the commit", possibly a separate one for "making the commit" (when using --only), and one for "after the commit succeeds, assuming it does succeed".

To get a little bit more concrete (which makes describing the underlying process a lot easier), let's note now that "the index" is really a simple file. The main one is ".git/index". (I'm ignoring extra complications like a split index here as they don't affect the result, so this is purely an internal implementation detail, but if you ever dive into the Git code, it's something else to trip over....)

Git handles the "old version, temporary intermediate version if needed, new version" problem by creating two or three files total. One of these is named ".git/index.lock", which serves as both a locking file to prevent two "git commit" operations from running at the same time and stepping on each other, and also "the future version of .git/index, should the commit succeed".

(The third file, which doesn't apply to your specific case, has a funky temporary name with a unique set of characters sprinkled in.)

If your pre-commit hook attempts modification(s) of the proposed snapshot for the new commit, it may need to update more than one of these files to make all three conditions hold, and in general it just can't. (It's too hard to know what the correct names are, since they're different in a work-tree and the "--only" name is randomized.) So pre-commit hooks are restricted to "ok" or "not ok" actions.

> It's possible that there is a better way to achieve my goal than a
> pre-commit hook.

Instead of running "git commit" directly, why not run a script that does the appropriate "git add"s, then runs "git commit" for you? The pre-commit hook can then inspect to be sure that this has occurred, and if not, remind users to run the script instead.

Chris
Previous: Junio C Hamano
Message 4 of 4 in “Interaction between pre-commit hook and git commit <pathspec>”
  1. Kevin LylesNov 3, 2026
  2. Kristoffer HaugsbakkNov 3, 2026
  3. Junio C HamanoNov 3, 2026
  4. Chris TorekNov 3, 2026

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.