13

I am developing validation and linting utility to be integrated with various commit hooks, including Git one

https://github.com/miohtama/vvv

Currently validators and linters are run against the whole project codebase on every commit. However, it would be much more optimal to run them against changed files only. For this, I would need to know changed files list in my Git precommit hook (in Python)

https://github.com/miohtama/vvv/blob/master/vvv/hooks/git.py

What options I have to extract the changed files list (in Python if that matters)?

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435

2 Answers2

6

The pre-commit hook is a bit of a pain, if you really want to make things work "right", because what's in the work tree is not necessarily the same as what is to be committed:

$ echo morestuff >> file1; echo morestuff >> file2
$ git add file1 # but not file2
$ git commit -m 'modified two files but check in just one'

You can use git diff-index --cached HEAD to get a list of "what's about to be checked-in". See also, e.g., http://newartisans.com/2009/02/building-a-better-pre-commit-hook-for-git/.

torek
  • 448,244
  • 59
  • 642
  • 775
  • For the article link: quite the pain to keep second copy of the repository around just for the checking what files have changed :( – Mikko Ohtamaa Apr 15 '12 at 18:26
  • You don't need a second copy of the repo, but you may (depending on what you're doing) need a second work-tree. There are basically two alternatives: check the index out elsewhere, so that you get a working tree that matches what is to be checked in; or, verify that the current work tree is "clean", so that you can use the current directory (the pre-commit hook is run in the work tree). – torek Apr 15 '12 at 20:30
  • 2
    Works perfectly, this far. Here is the full solution https://github.com/miohtama/vvv/blob/master/vvv/hooks/git.py – Mikko Ohtamaa May 12 '12 at 00:57
  • Just scanning quickly over that python code: you can do `sys.exit("some string")` instead of `print("some string"); sys.exit(1)`. You might also want `git diff -z ...` and then split the output at `\x00` bytes. – torek May 12 '12 at 05:35
  • To make sure your test suite runs on the result of the commit, use `git stash`. See http://codeinthehole.com/writing/tips-for-using-a-git-pre-commit-hook/ – user1071136 Oct 21 '13 at 01:35
  • @user1071136: there's a minor bug in `git stash` that if the index version has a change and the current working directory version changes it back to what's in the previous commit (i.e., `HEAD`), `git stash --keep-index` loses the work-directory version. (Of course that's still in `HEAD`. But it makes using `git stash` in the pre-commit hook slightly broken.) – torek Oct 21 '13 at 03:25
1

This is not a direct answer to this - but I came across this when searching for a similar solution for JavaScript with npm.

With some further searching I believe this is now a solved problem for npm with the lint-staged library. This will lint only the staged files.

The problem I had when searching is that I was always searching for "pre-commit" hook linting rather than "staged file" linting. So I'm putting this answer here for anyone like me who comes here searching for a JavaScript solution.

Hopefully also the npm package can be of some inspiration to the Python world.

icc97
  • 11,395
  • 8
  • 76
  • 90