Konstantin Kuznetsov
Konstantin Kuznetsov

Reputation: 903

Git pre-commit hook behavior with Intellij Idea

I have a monorepo project with pre-commit git hook that bumps version in package.json files. This hook uses the following script:

#!/usr/bin/env bash

set -e

# See if git detects any changes for the given directory
if [[ -z `git diff --cached --shortstat ./packages/$1` ]]; then
    VERSION=`node -p -e "require('./packages/$1/package.json').version"`
    echo "$1 has not changed, old version: $VERSION"
    exit 0
fi

VERSION=$(cd packages/$1 && npm version patch --no-git-tag-version)
# Add package.json to staged
git add packages/$1/package.json > /dev/null
echo "$1 has changed, new version: ${VERSION//v}"

I change one file tsconfig.json in backend package and commit it via Idea UI, with "Run git hooks option checked". I only check this on file in UI dialog, but the hook should also bump package.json. In Idea version control console I see following log appear:

14:28:08.610: [myproject] git -c core.quotepath=false -c log.showSignature=false commit --only -F /private/var/folders/rf/mnfmp6xs2zjb50x0nqfrlftw0000gn/T/git-commit-msg-.txt -- packages/backend/tsconfig.json
[master c5ec828] Hooks test 24
 2 files changed, 2 insertions(+), 2 deletions(-)

Running git log -1 --stat says that package.json got changed by hook and was commited:

git log -1 --stat
commit c5ec8289afa8f15d7134b362992d4a91e31bda16 (HEAD -> master)
Author: doomsower <[email protected]>
Date:   Tue Feb 13 14:28:08 2018 +0300

    Hooks test 24

 packages/backend/package.json  | 2 +-
 packages/backend/tsconfig.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

The packages/backend/package.json version was bumped by hook and is correct. However, when I run git status I see following:

On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   packages/backend/package.json

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   packages/backend/package.json

Then I run git add packages/backend/package.json and after that git status returns:

On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

I don't quite understand what's going on here:

1) According to logs, Idea ran git commit with --only flag and package.json was not specified in command line, yet it was commited. How is it possible?

2) Ok, so 2 files were committed and package.json was committed with bumped version number. How is it possible that after that git working tree is not clean and I have to run git add to make it clean?

Upvotes: 0

Views: 3359

Answers (1)

Leighton
Leighton

Reputation: 1180

So I think this is the timeline of events in your above situation:
1. You change tsconfig.json and add it to the git index
2. You then commit the index which only has tsconfig.json. Before the commit is run your hook modifies and adds package.json to the index.
3. The index is then committed, specifying only to commit tsconfig.json. Normally this would leave package.json as staged but (and, full disclosure, I'm taking an educated guess here) because it was added in the hook git has already dome some commit-processing to the file.
4. This leaves you with your new package.json committed, the old package.json in the index, and the new one on your file system. Hence adding it back to the index cancels out the change, as it now matches the committed history - giving a clean repo.

The fix for this would be to remove the add from your pre-commit, and run the commit in your post-commit hook, like so:
git add package.json
git commit --amend -C HEAD --no-verify
Using --no-verify to prevent an infinite loop of hooks

Upvotes: 1

Related Questions