Parthiva
Parthiva

Reputation: 300

pre-commit hook changed files to be added to commit

I am writing a pre-commit hook for my repositories to format the code according to coding standards.

npm install
./node_modules/.bin/eslint --fix ./index.js

The above line is part of my hook. It is working as I wanted it and changed the index.js file to standard format with clean code. After successful commit, when I did git status I see a unstaged change which is the change made by pre-commit hook in the recent commit.

I am looking for a way where all the changes done by the pre-commit hook to be included in the present commit without having to commit again. So, the flow should be as

  1. git commit
  2. Pre-commit hook runs, changes the files if necessary, adds the changes to the present commit
  3. Now, I can just push

Upvotes: 6

Views: 7045

Answers (3)

Amritesh Sharma
Amritesh Sharma

Reputation: 41

I had the same problem(spring-boot, maven project), formatting was handled by spring-javaformat-maven-plugin(io.spring.javaformat:spring-javaformat-maven-plugin).

The following steps helped me get through.

  1. Create a client-side(at developer end)pre-commit git hook and execute a bash script(say - code-formatter.sh). This script does the formatting and adds changed files to the existing commit, see below.

(a) first, get the list of changed files (b) run the formatting on the source (c) add only changed files to the commit

#!/bin/bash
set -e
cd ..
cd <project-directory>
echo '==pre-commit-code-formatting=='
echo 'file(s) to be committed'
fileString=`git diff --cached --name-only` #getting changed files(name only)
files=${fileString%$'\n'*} #convert to list
for file in "$files"
do
  echo "==>$file" #print file
done
echo 'running formatter(spring-javaformat:apply)'
mvn io.spring.javaformat:spring-javaformat-maven-plugin:apply
echo 'formatting completed!'
echo 'adding changes to existing-commit'
for file in "$files"
do
  git add "$file" #add to commit
  echo "==>added file : $file"
done
echo '==pre-commit-code-formatting-completed=='
  1. Create the hook file(pre-commit), this file has no extension, like docker file, and execute the script file from the previous step.
#!/bin/bash
"$(git rev-parse --git-dir)/hooks/code-formatter.sh"
  1. Place both files in a directory at project root (say - pre-commit)

  2. Use maven plugin(maven-antrun-plugin) to add them to .git folder of your project

      <plugin>
             <artifactId>maven-antrun-plugin</artifactId>
             <executions>
                 <execution>
                     <id>make</id>
                     <phase>generate-sources</phase>
                     <goals>
                         <goal>run</goal>
                     </goals>
                     <configuration>
                         <target name="make">
                             <echo>installing pre-commit hook</echo>
                             <copy todir="${project.basedir}/.git/hooks">
                                 <fileset
                                         dir="${project.basedir}\pre-commit">
                                     <include name="**/*"/>
                                 </fileset>
                             </copy>
                         </target>
                     </configuration>
                 </execution>
             </executions>
         </plugin>
    

All done, run maven clean install and it will install the git hook. On the next commit onwards your sh file will run(even on windows)

ofcourse the formatter plugin must be in your pom.xml

<plugin>
            <groupId>io.spring.javaformat</groupId>
            <artifactId>spring-javaformat-maven-plugin</artifactId>
            <version>0.0.29</version>
            <executions>
                <execution>
                    <phase>validate</phase>
                    <inherited>true</inherited>
                    <goals>
                        <goal>validate</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>

Upvotes: 0

tegandbiscuits
tegandbiscuits

Reputation: 81

The Lint Staged package is an option. The example they give uses Husky to manage git hooks, but I assume it should work with normal git hooks.

It only runs the linter on staged files, restages them if they change, then creates the commit. However (at this time) you lose the ability to stage parts of a file.

Upvotes: 0

Mark Adelsberger
Mark Adelsberger

Reputation: 45819

So the hook needs to stage the changes, just like you stage any change you want in the commit - with git add.

If you know your worktree is in sync with the index when you start this process, then that's as simple as

git add .

That's usually not a good assumption. You could modify your script to either ensure that the work tree is clean (though it would take jumping through some hoops if you want to be able to restore the work tree afterward) or abort if it's not (though that could be limiting if it's done in the pre-commit hook).

Somewhat better is to add just the modified files (though this means you have to be able to tell what files the script actually modified).

This still assumes (as does the general nature of your script) that if you've modified a file, your intent is to stage all modifications to that file. That may be valid for your workflow, and if so then the above is sufficient.

Of course, maybe your workflow doesn't allow for such assumptions, in which case you need to revisit how your script works more fundamentally. A couple options in that case:

1) You could stash the unstaged changes at the start of your script.

git stash --keep-index --include-untracked

then run your clean-up and do a git add . (knowing that all changes in the worktree are the result of running the script), and then

git stash pop

2) You could bypass the worktree entirely, operating on the files as they exist in the index. (Because the index isn't in a form where your tools will work on it directly, you'd basically have to extract each index entry to a file to be cleaned and then updated back into the index.)

Upvotes: 4

Related Questions