What to stage after a pre

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 (ie 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?


    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.


    You can put the changes that you have not staged for commit in a stash in your pre-commit script, and then pop them off when you are done. The --keep-index option only stashes changes that you haven't added to the index (haven't run git add on), and the --quiet options suppress the notices that you're creating and destroying the stash.

    The way you described isn't quite the canonical "git way to do it," most pre-commit scripts that I've seen only check for incorrect style and then error out of the commit if they find anything. That way you don't have your pre-commit script inadvertently rewrite some file that was supposed to have tabs in it for some reason (eg testing data)---you could simply rerun the commit with --no-verify once you were confident that the errors were supposed to be there.

    I have a simple pre-commit script here. It pretty much just runs git's basic test of diff-index --check, but it uses the git stash to only work on the changes that it should.

    #!/bin/sh
    if git rev-parse --verify HEAD >/dev/null 2>&1
    then
        against=HEAD
    else
        # Initial commit: diff against an empty tree object
        against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
    fi
    
    git stash save --keep-index --quiet
    git diff-index --check --cached $against --
    RETVAL=$?
    git stash pop --quiet
    exit $RETVAL
    

    Update:

    You will get merge conflicts if you try to use this strategy with a script that modifies the contents you want to commit. We should take the stash pop out of the pre-commit script, and perform an explicit merge in the post-commit script.

    #!/bin/sh
    
    git stash save --keep-index --quiet
    # Add your script to prettify the code here ...
    git add .
    

    Now the post-commit script looks like this

    #!/bin/sh
    
    git merge stash@{0} -s recursive -Xtheirs
    git stash drop --quiet stash@{0}
    

    The recursive merge with the theirs parameter should keep the changes the script made when possible.


    I'm not 100% sure I understand the goal, but perhaps you could try the following approach. Have your hook generate a patch instead of writing the changes to disk. (You could do this, eg, in Python using the difflib module, or write a temp file and shell out to diff .) Then use git apply (with --cached and other flags as appropriate) to apply your patch to the index as well as to the working tree (either manually or automatically by the hook).

    链接地址: http://www.djcxy.com/p/56756.html

    上一篇: 如何将额外的项目添加到现有的Android操作系统源?

    下一篇: 预备后要做什么?