我正在尝试编写一个git pre-commit挂钩,用于检查在提交之前是否再次修改了使用git add
暂存的文件。
基本上我对这些文件感兴趣
git status --short
MM test1
AM test2
现在预提交钩子看起来像这样:
#!/bin/bash
# git pre-commit hook that checks for staged files that were modified.
# exit on error
set -e
# DOES NOT WORK
cached=$(git diff --name-only --diff-filter=M)
# everything is fine
if ! [[ -n $cached ]]; then
exit 0
fi
# GNU and BSD versions of xargs behave differently.
if xargs --version >/dev/null 2>&1; then
flag="-l" # GNU
else
flag="-L1" # BSD
fi
printf "The following files have been modified after they have been staged:\n\n"
printf "$cached"
printf "\n\nYou can stage these changes with:\n"
printf " git diff --name-only --cached | xargs ${flag} git add\n"
printf "Aborting commit. Stage the modified files and commit again or skip"
printf " checking with --no-verify (not recommended).\n"
exit 1
问题是,这个钩子还会拾取已修改但未暂存的文件。我怎么能调整我的钩子?
答案 0 :(得分:3)
要使用git diff
执行此操作,您需要两次传递,一次查找在索引中添加或修改的文件(git diff --cached --name-status
或类似文件),另一次查找自索引版本以来修改过的文件({{ 1}}或类似的。)
但您不必使用git diff --name-status
执行此操作。答案在你的短语中:
基本上我对这些文件很感兴趣......
只需为git diff
运行git status --short
(或--porcelain
)和grep:这些是您的文件。通过某种方式运行此输出以切断状态部分(^[AM]M
,cut
等);这些都是名字。
sed
命令可以进行匹配和剪切,重量轻于sed
,因此可能是最好的工具:
awk
有一个缺陷:对于git status --porcelain | sed -n 's/^[AM]M //p'
检测到重命名或复制操作(最左列中的git status
和R
)的文件,您可能会错过一些索引与vs工作树的变化。在工作树中还有C
eleted-in-commit但D
odified(未删除)。我不确定你是否关心这些案件。如果是这样,请仔细阅读the git status
documentation中的详细信息并相应地修改sed正则表达式。
(还有一个独立的缺陷:如果您在合并过程中,M
会告诉您合并的结果。但是,您无法提交直到#39}已经完成了合并,所以我只提到这个,以防有人想在预提交钩子以外的东西中使用同样的想法。)