Reputation: 300
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
Upvotes: 6
Views: 7045
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.
(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=='
#!/bin/bash "$(git rev-parse --git-dir)/hooks/code-formatter.sh"
Place both files in a directory at project root (say - pre-commit)
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
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
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