Can a Git hook automatically add files to the commit?
Solution 1
Since git add was also not working for me in a pre commit, I followed mark's idea of using a .commit file and splitting the process into pre- and post-commit.
Here is some code that should be easy to understand
In the pre-commit:
- Touch a file .commit or something. (be sure to add this to .gitignore)
#!/bin/sh
echo
touch .commit
exit
In the post-commit:
if .commit exists you know a commit has just taken place but a post-commit hasn't run yet. So, you can do your code generation here. Additionally, test for .commit and if it exists:
- add the files
- commit --amend -C HEAD --no-verify (avoid looping)
- delete .commit file
#!/bin/sh
echo
if [ -e .commit ]
then
rm .commit
git add yourfile
git commit --amend -C HEAD --no-verify
fi
exit
Hope this makes it easier for people with few bash knowledge to follow mark's idea.
Solution 2
It's possible to do what you want using pre-commit hooks. We do something similar for a heroku deployment (compiling coffeescript to javascript). The reason your script isn't working is because you used the exec
command improperly.
From the man page:
The exec builtin is used to replace the currently running shells process image with a new command. On successful completion, exec never returns. exec can not be used inside a pipeline.
Only your first exec command is running. After that your script is basically terminated.
Give something like this a try (as a pre-commit hook):
#!/bin/sh
files=`git diff --cached --name-status`
re="<files of importance>"
if [[ $files =~ $re ]]
then
echo "Creating files"
bundle exec create_my_files
git add my_files
fi
Solution 3
#!/bin/sh
#
# .git/hooks/pre-commit
#
git add file.xyz
This worked just fine for me. It will be part of the current commit.
git version 1.7.12.4 (Apple Git-37)
Solution 4
You could use a combination of a pre and post commit script.
In the pre-commit:
- Touch a file .commit or something. (be sure to add this to .gitignore)
In the post-commit:
if .commit exists you know a commit has just taken place but a post-commit hasn't run yet. So, you can do your code generation here. Additionally, test for .commit and if it exists:
- add the files
- commit --amend -C HEAD --no-verify (avoid looping)
- delete .commit file
This is roughly the process I use to store a .metadata file in the repository generated from metastore.
If anyone knows a better way I'm all ears but it seems to work for now.
Solution 5
You can use update-index
:
git update-index --add my_files
Related videos on Youtube
Ian Terrell
Updated on November 24, 2021Comments
-
Ian Terrell over 2 years
I'd like to add an automatically generated file to the same commit using a pre- or post-commit hook in Git, dependent on the files that were modified in that commit. How would I go about this?
I've tried this as a pre-commit hook, but no luck:
#!/bin/sh files=`git diff --cached --name-status` re="<files of importance>" if [[ $files =~ $re ]] then echo "Creating files" exec bundle exec create_my_files exec git add my_files exec git commit --amend -C HEAD fi
This successfully adds them to the repository, but does not add them to the commit. I've also tried using the last two exec lines in a post-commit hook along with the pre-commit inspection, but no good either.
-
Martin Jambon about 6 yearsYou need to remove the
exec
s from this code (seeman sh
). It's impossible for any shell command to be executed after anexec
, sinceexec
clobbers the current process, i.e. the shell that is used to interpret commands.
-
-
rfunduk almost 14 yearsTrue, but doesn't answer the question. He might have a very good reason for putting the generated file under source control, that's not for us to decide :)
-
Ian Terrell almost 14 yearsThey can't be generated anywhere: they're being deployed from source control to a read-only filesystem.
-
Ian Terrell almost 14 yearsI updated the question with the information. There are no errors. The files are created. Git status shows they've been added but not committed.
-
rfunduk almost 14 yearsThere you have it! :) You might try to put the generation step into your deploy script, but that might also be impractical.
-
Ian Terrell almost 14 yearsThe deployment is automated with a git push (it's a Rails app on Heroku), so it's not terribly practical to put it there. Pre-commit is really the place for it, as I can test to see if any dependent files have changed and only rebuild the generated files if they have.
-
Craig Trader almost 14 years@Ian, it really sounds like this is something for your build scripts, before you commit, instead of trying to use Git to automate the generation. If anything should be put into the pre-commit step, it should be a check to ensure that the files are up-to-date before committing (and fail the commit if they are out of sync).
-
rfunduk almost 14 yearsIt's possible that another option to
update-index
will be what you need, too: ftp.sunet.se/pub/Linux/kernel.org/software/scm/git/docs/… -
rfunduk almost 14 yearsLooks like you're right about pre-commit... unfortunately for Ian's developers, there are likely no 'build scripts' involved in his project -- unless you count tests :)
-
Ian Terrell almost 14 yearsI will definitely look at that as an option. Thanks!
-
kojiro over 12 yearsI don't know about @IanTerrell, but I'm still stuck on this. I tried both
git add
andgit update-index --add
. In both cases the files get added to the repository (so they'd be in the next commit), but not to the current commit. -
Rubycut almost 12 yearsThis is not working in recent git (I use 1.7.9), git add in pre-commit adds the files for future commit, not the one you just engaged.
-
ben almost 12 yearsWorks for me in git 1.7.10. The files are not added to the commit message, but they are commited. It seems that the 'git status' in the commit message is generated before pre-commit. This seems like a bug to me, but I suspect it was done on purpose for some reason. What you can do is add a line to the end of pre-commit that looks something like 'git status; echo -n Hit enter to continue...; read'. There is likely a better way to solve this, but that was a quick fix for me.
-
inf3rno about 11 yearsI forgot mention, I have git version 1.7.7. This feature is available only version 1.7.10+ according to previous comments.
-
jbasko about 10 yearsI have git 1.8.3.4 and whatever is added in pre-commit hook doesn't appear to be staged until the next commit.
-
Albert Netymk over 8 yearsShouldn't
-a
be-e
to test if.commit
exist? -
erichlf over 8 yearsrfunduk's response worked perfectly for me on git 2.6.2, i.e. git update-index --add my_files
-
Flimm over 8 years
git add
in apre-commit
hook doesn't work as intended for me in Git 2.6.4 -
Yi Jiang almost 8 yearsActually, I can confirm this works in git 2.7.4 I'm using right now. It doesn't appear that way when editing the commit message, but when you actually commit you will see the files you added during the pre-commit hook appear in the commit.
-
IanS over 7 yearsThis worked for me, too, except I needed to change the working directory of my script using
cd $(git rev-parse --show-toplevel)
-
Eliran Malka about 7 years@AlbertNetymk - there is practically no difference; the
-a
primary was introduced as a KornShell proposal and made its way to POSIX, it's only supported today for backwards-compatibility. later-e
was added to avoid confusing the-a
primary with the-a
binary operator. -
Albert Netymk about 7 years@EliranMalka Could you provide a ref? I have trouble locating
-a
. linux.die.net/man/1/test The only use I found is for logicaland
. -
Eliran Malka about 7 years@AlbertNetymk, sure, here is the POSIX
test
command man page on unix.com. search the page for the term "An early proposal used the KornShell -a primary" -
Albert Netymk about 7 years@EliranMalka I see. Thank you very much.
-a
should probably never be used other than as a boolean operator just to avoid the confusion. -
superarts.org over 6 yearsNot work in
2.11.0
either. Changes are added but not committed. -
Iulian Onofrei over 6 yearsThis also doesn't work if you have another file in the index which you don't want to add to the commit.
-
laurent over 6 yearsWorked for me too. If doing just
git commit
, the added files won't appear in the automatically generated commit message, but they will be added anyway. -
jcollum about 4 yearsgit-scm.com/docs/githooks post-commit runs after the commit is complete -- you can't amend it at that point afaics
-
jcollum about 4 yearsI don't get the purpose of .commit here -- from messing with this it seems like post-commit will only run after a commit is complete making the .commit file irrelevant. Maybe you meant the .commit file to indicate a special state like "cleanup needed"?
-
rfunduk about 4 years
git commit --amend
changes the previous commit (which as you said has just happened) -
Gabriella Gonzalez about 4 years@jcollum: Apparently, the
.commit
file prevents an infinite loop. Specifically,--no-verify
doesn't prevent thepost-commit
hook from running, so the post-commit runs twice: once when the.commit
file is present, which then runsgit commit --amend …
which triggers the post-commit hook again, but this time with the.commit
file being gone, which ends the loop. -
Gabriella Gonzalez about 4 yearsI believe this needs a final
exit
command at the end of thepre-commit
script -
mhucka about 4 yearsThis scheme works for me, with the critical modification that I had to move the
git add
to thepre-commit
hook instead of thepost-commit
hook. I'm using git version 2.25.1 on macOS. -
mhashim6 over 3 yearsshould be
--amend
not--ammend
.