预提交钩子,用于检查是否再次修改了分阶段文件

时间:2015-08-28 08:51:58

标签: git bash githooks pre-commit-hook

我正在尝试编写一个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

问题是,这个钩子还会拾取已修改但未暂存的文件。我怎么能调整我的钩子?

1 个答案:

答案 0 :(得分:3)

要使用git diff执行此操作,您需要两次传递,一次查找在索引中添加或修改的文件(git diff --cached --name-status或类似文件),另一次查找自索引版本以来修改过的文件({{ 1}}或类似的。)

但您不必使用git diff --name-status执行此操作。答案在你的短语中:

  

基本上我对这些文件很感兴趣......

只需为git diff运行git status --short(或--porcelain)和grep:这些是您的文件。通过某种方式运行此输出以切断状态部分(^[AM]Mcut等);这些都是名字。

sed命令可以进行匹配和剪切,重量轻于sed,因此可能是最好的工具:

awk

有一个缺陷:对于git status --porcelain | sed -n 's/^[AM]M //p' 检测到重命名或复制操作(最左列中的git statusR)的文件,您可能会错过一些索引与vs工作树的变化。在工作树中还有C eleted-in-commit但D odified(未删除)。我不确定你是否关心这些案件。如果是这样,请仔细阅读the git status documentation中的详细信息并相应地修改sed正则表达式。

(还有一个独立的缺陷:如果您在合并过程中,M会告诉您合并的结果。但是,您无法提交直到#39}已经完成了合并,所以我只提到这个,以防有人想在预提交钩子以外的东西中使用同样的想法。)