【发布时间】:2016-06-01 15:40:46
【问题描述】:
我正在编写一个预提交钩子来运行我的 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 in proper_pop 是唯一的罪魁祸首(删除它会消除错误)。没有安装其他钩子,git 版本是:1.8.1.2,但我也在版本2.5.0 上运行了这个,同样的问题发生了。有没有人任何知道发生了什么?
我尝试将 stdout 和 stderr 传送到 /dev/null 以查看该命令是否有效,并且仍然打印错误...
这完全是一个我可以解决的问题,它确实不会导致任何问题,但我不希望技术水平较低的同事看到这个错误并让它摆脱它们(我不确定每次我们合并带有尾随空格的内容时是否会打印它),所以我很想知道发生了什么以及如何解决这个问题(或告诉git reset忽略尾随空格错误)。
编辑:
这是演示此问题的完整工作存储库:https://github.com/hjc1710/so-git-hook-question,只需按照README.md 中的步骤操作,无论您是否在合并中,您都会收到错误消息。
可以在here 找到我的 git 配置(适用于 1.8.x 上的工作站和 2.5.x 上的笔记本电脑)。敏感信息已被删除,但没有一个是相关的。
【问题讨论】:
-
运行 reset --hard 并存储似乎是预提交中的灾难。在 git 尝试做同样的事情时,你失去了 staging 并更改了 HEAD。此外,如果您在合并过程中执行 git reset 操作,您实际上已经中止了合并。也许不使用预提交,而是使用暂存分支。然后使用 CI 系统的工作流程为您测试 staging 并合并到 master。
-
我正在尝试查看 stdin 在何处通过管道传输到 diff,因为这就是投诉的来源(
<stdin>:28),但语法似乎不存在。您是否确认 pre-commit 挂钩会在全新安装 git 的干净机器上导致相同的问题?运行你的脚本对我来说没有产生任何错误,但这些错误确实让人想起git rebase --whitespace=warn之类的警告。我也有兴趣查看您的 repo、全局和系统 .gitconfigs(git config -l、git config --global -l、git config --system -l)。 -
@Bujiraso 我已经用我的 git 配置(我的笔记本电脑上的 2.5.x 和我的工作站上的 1.8.x)编辑了我的原始问题,以及一个使用剥离钩子和单个文本文件。无论您是否处于合并中,都会发生错误,并且钩子只是用索引存储,并且在没有索引的情况下正确地取消存储。我没有任何全新安装的简单机器,但是如果您想使用它们,repo 中的这些说明应该会在 100% 的情况下触发错误。我不知道这是通过管道传输到 git diff 的。谢谢!
-
@Sukima - 在预提交挂钩中存储更改并不是世界上最疯狂的事情。我见过的大量示例脚本都是这样做的,这样你只需要检查和测试即将提交的内容,而不是刚刚更改的内容。您还必须
reset --hard正确撤消 stash 所做的操作,否则git stash pop会给您合并冲突。我明白你在说什么关于合并,我可能会通过查看挂钩运行时MERGE_MSG是否存在来禁用合并。但是,这也发生在不合并时,所以......我很困惑! -
@hjc1710 - 是的 - 现在我看到了你的错误。将进一步调查。