检查暂存文件是否再次被修改的预提交挂钩

pre-commit hook that checks if staged files were modified again

我正在尝试编写一个 git 预提交挂钩,用于检查使用 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

问题是,此挂钩还会拾取已修改但未暂存的文件。我该如何调整我的鱼钩?

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

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

Basically I am interested in these files ...

只需 运行 git status --short(或 --porcelain)和 grep for ^[AM]M:这些是您的文件。 运行 通过某些东西切掉状态部分(cutsed 等)的输出;这些是名字。

sed命令可以进行匹配和切割,并且比awk更轻量,所以可能是最好的工具:

git status --porcelain | sed -n 's/^[AM]M //p'

存在一个缺陷:对于 git status 检测到重命名或复制操作的文件(最左侧列中的 RC),您可能会遗漏一些索引 - vs-work-tree 变化。在工作树中还有 Deleted-in-commit 但 Modified(未删除)。我不确定你是否关心这些案例。如果是这样,请通读 the git status documentation 中的详细信息并相应地修改 sed 正则表达式。

(有一个单独的缺陷:如果您正在进行合并,git status 会告诉您有关合并的信息。但是,在完成合并之前您不能提交,所以我只提到这一点,以防有人想在预提交挂钩以外的其他地方使用同样的想法。)