Search code examples
windowsgitdiffpre-commit

Why does Git prints an incorrect diff at the bottom of a commit message?


I use a pre-commit hook to run Prettier formatter against my HTML documents:

#!/bin/sh

# Retrieving a list of the staged files
stagedFiles=$(git diff --staged --name-only)

# Format staged files automatically
echo "Formatting with Prettier..."
npx prettier --write $stagedFiles
git add $stagedFiles

The formatting successfully applies right after I enter git commit command and right before my configured editor opens the commit message. According to commit.verbose setting, Git appends there a diff showing what is to be committed, but this diff does not take into account changes made by Prettier — it demonstrates the unformatted version of my code. If I then abort the commit (leaving the message empty), I can see that no unstaged changes are in the repository; it means that all formatting modifications had been properly staged during execution of the pre-commit hook. Moreover, if I write some text to the message and complete the commit without aborting, the resulting snapshot does contain all formatting that was missing in the diff.

I finally concluded that the diff lies. But does a solution exist?

Git for Windows version: 2.33.0

OS: Windows 10 21h1 x64


Solution

  • The short answer is : the pre-commit hook is not intended to modify files to be committed.

    You can relate to the following rationale : the content you commit will be the exact content you could review and test before running git commit.

    (the technical reason is : git creates the tree -- the content for the commit -- that will be used before calling the pre-commit hook)

    A pre-commit hook should be written as a read-only action, which may prevent the commit from happening, e.g : if a file is not formatted correctly, reject the commit with a message "please run format.sh before committing".

    Of course, you could work your way around that, but, FWIW, I advise you to follow this rule.