git reset --hard -q产生有关空格的错误

时间:2016-02-19 22:04:43

标签: git sh githooks

我正在编写一个预提交钩子来运行我的Python测试,一切都运行得非常好......直到我遇到合并冲突。在此合并冲突中,引入了一些具有尾随空格的文档文件,每次我尝试提交时,都会收到以下消息:

<stdin>:28: trailing whitespace.
Ticket Link: 
<stdin>:54: trailing whitespace.
Then visit `http://app.dev` 
<stdin>:13528: trailing whitespace.
                            //most be provided for ALL resource updates, and 
<stdin>:13531: trailing whitespace.
    "deleted": false,  //indicates if this action resulted in a resource delete; 

warning: squelched 415 whitespace errors
warning: 420 lines add whitespace errors.
fatal: could not open '.git/MERGE_HEAD' for reading: No such file or directory

然后当我打开我的编辑器来编写提交消息时,它完全是空的。

我的预提交脚本是:

#!/bin/sh

RED='\033[0;31m'
NC='\033[0m'

proper_pop() {
    git reset --hard -q 
    git stash apply -q --index && git stash drop -q
}

exit_and_pop() {
    proper_pop

    if [ "$1" -ne 0 ]; then
        echo "${RED}Your code failed the pre-commit hook! Please examine the output and fix your issues!${NC}"
    fi

    exit $1
}

run_and_bail() {
    bash -c "$1";
    ret=$?;

    if [ "${ret}" -ne 0 ]; then
        exit_and_pop "${ret}"
    fi
}

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

old_stash=$(git rev-parse -q --verify refs/stash)
git stash -q --keep-index
new_stash=$(git rev-parse -q --verify refs/stash)

if [ "$old_stash" = "$new_stash" ]; then
    echo "pre-commit script: No changes to test. Not running."
    sleep 1  # HACK: Editor may erase message if done too quickly, make the programmer read
    exit 0
fi

# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --bool hooks.allownonascii)

# Redirect output to stderr.
exec 1>&2

# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
    # Note that the use of brackets around a tr range is ok here, (it's
    # even required, for portability to Solaris 10's /usr/bin/tr), since
    # the square bracket bytes happen to fall in the designated range.
    test $(git diff --cached --name-only --diff-filter=A -z $against |
      LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
    cat <<\EOF
Error: Attempt to add a non-ASCII file name.
This can cause problems if you want to work with people on other platforms.
To be portable it is advisable to rename the file.
If you know what you are doing you can disable this check using:
  git config hooks.allownonascii true
EOF
    exit_and_pop 1
fi

if ! [ -z "$(which git-pylint-commit-hook)" ]; then
    run_and_bail "git-pylint-commit-hook"
fi

if ! [ -z "$(which pep8)" ]; then
    run_and_bail "python hooks/pep8-hook-check.py"
fi

proper_pop

通过我的调试,我生成了最小的脚本以重现此错误:

#!/bin/sh

RED='\033[0;31m'
NC='\033[0m'

proper_pop() {
    git reset --hard -q 
    git stash apply -q --index && git stash drop -q
}

exit_and_pop() {
    proper_pop

    if [ "$1" -ne 0 ]; then
        echo "${RED}Your code failed the pre-commit hook! Please examine the output and fix your issues!${NC}"
    fi

    exit $1
}

run_and_bail() {
    bash -c "$1";
    ret=$?;

    if [ "${ret}" -ne 0 ]; then
        exit_and_pop "${ret}"
    fi
}

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

old_stash=$(git rev-parse -q --verify refs/stash)
git stash -q --keep-index
new_stash=$(git rev-parse -q --verify refs/stash)

if [ "$old_stash" = "$new_stash" ]; then
    echo "pre-commit script: No changes to test. Not running."
    sleep 1  # HACK: Editor may erase message if done too quickly, make the programmer read
    exit 0
fi

proper_pop

通过这一点,我了解到git reset --hard -q中的proper_pop行是唯一的罪魁祸首(删除它会删除错误)。没有安装其他钩子,git版本是:1.8.1.2,但我也在版本2.5.0上运行它,并且会出现同样的问题。有没有人任何想法发生了什么?

我尝试将stdout和stderr管道传输到/dev/null以获取该命令,只是为了查看它是否有效,并且错误仍然打印出来......

这完全是一个我可以解决的问题,它确实不会导致任何问题,但我不希望技术水平较低的同事看到这个错误并让它丢掉(我是不确定每次我们合并到尾随空格的内容时是否会打印出来,所以我很想知道发生了什么以及如何解决这个问题(或告诉git reset忽略尾随空白错误)。 / p>

修改

以下是演示此问题的完整工作回购:https://github.com/hjc1710/so-git-hook-question,只需按照README.md中的步骤操作即可获得错误,无论您是否合并

我的git配置(对于我的工作站,在1.8.x上,我的笔记本电脑,在2.5.x上)可以找到here。敏感信息已经被删除,但它们都不应该是相关的。

2 个答案:

答案 0 :(得分:3)

正如this answer中的第二个脚注所指出的,git stash apply只是呼叫git diff ... | git apply --index。警告来自这些命令。

当您有尾随空格,隐藏包含尾随空格的文件,然后应用存储时,会发生这种情况。 更准确地说,只要您尝试将git apply跟踪换行符添加到代码体

,就会发生这种情况

如果您创建一个带尾随空格的git补丁并尝试通过cat a.patch | git diff --index应用它,则会产生相同的错误。

至于解决这个问题,可能会在本地,全局或系统core.whitespace=nowarn中设置gitconfig会使其静音,但这似乎不适用于我,但是YMMV。 (这些设置似乎没有被阅读。) 运行git config core.whitespace -blank-at-eol,正如评论中所指出的那样。

除了上述内容之外,我看到的唯一解决方案是在git-stash bash脚本中找到有问题的行,并自己将--whitespace=nowarn参数添加到git apply。我应该提到的是一个相当非标准的非便携式解决方案。你必须让每个人都这样做,最有可能每次git更新。但是,如果他们打扰你没有尽头 - 这就是你能做的。

好的一面,正如你所提到的那样,它可以解决,但是如果我没有乱七八糟的东西,它本身就可以在git上打开一个bug。 strong> 甚至忽略系统 gitconfig。我希望至少应该尊重这一点。

答案 1 :(得分:2)

感谢你让它如此容易重现!

问题似乎是钩子内的git命令正在将空白错误写入当前tty而不是stdoutstderr。然后,钩子跑步者正在拾取错误,然后错误地声称它是stdout

此修复程序来自the answer以前的一个问题。

#!/bin/sh
git stash > /dev/null
unbuffer sh -c 'git stash apply -q --index  && git stash drop -q ' >/dev/null 2>&1

编辑:如果您想在OSX上使用unbuffer程序,可以使用here说明获取它。

brew tap homebrew/dupes/expect
brew install homebrew/dupes/expect