Search code examples
githookpre-commit

What to stage after a pre-commit hook was run?


For a pre-commit hook that modifies the staged files, I need to figure out what has to be staged after the hook was run.

The pre-commit hook applies some pretty-printing on the files that should be committed. The hook does the following tasks:

  • replace tabs by spaces
  • remove trailing whitespace at the end of lines
  • remove double empty lines *)
  • if missing, add an empty line at the end of the file *)

Actions marked with *) are those that are causing the problem described below.

After these have been done, the hook adds the modified file(s) to the index using git add $filename. That way, the whole file gets staged and I'm no longer able to commit only small portions (i.e. hunks) of the modified file.

Of course, I could git add --no-verify and bypass the hook, but that option isn't available when using the git gui. Also, I want the took to apply pretty-printing on the staged lines of the file, so bypassing the hook is not my aim.

Is there a way to find out what has to be added to the index after the pretty-printing was applied, so that I could stage the right content after the hook was run instead of staging the whole file?


Edit 1:
While the answer provided by David Brigada looks promising, it doesn't work: git stash --keep-index leaves the staged changes intact (that's the good part), but (at least on msysgit) it puts all changes into the stash (not only the unstaged ones). This results in merge conflicts when popping the stash back into WC because the staged lines might get modified.


Edit 2:
Also the updated answer of David leads to no success since git refuses to merge the stash into a dirty WC.


Edit 3:
The answer from larsks points me to the usage of .gitattributes. On the first glimpse, this seems right but I find it quite confusing that the checked in version was run through a filter and the WC is different from the checked in version. At least, that was my experience and is backed up by the following remark in the Git Book:

If you commit those changes and check out the file again, you see the keyword properly substituted

I have to remove the file and then check it out again to see the changes that were applied by the filter? No way! Any more hints?


Solution

  • I'm not sure that a pre-commit hook is the right place to perform this sort of work. Git has a filtering mechanism that allows you to apply commit/checkout filters to documents via .gitattributes; the Pro Git Book includes examples that use this filtering mechanism to apply the indent program to C source files automatically.