将更改内容隔离成独立的提交的 Git 提交策略

3

我希望要求将SVG文件单独提交以保持其他内容的差异输出更加清晰。例如,我不想允许像这样的提交:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   src/css/main.css
        modified:   src/images/example.svg
        modified:   src/index.html

这个问题能用 pre-commit 钩子完成吗?该如何编写它?

编辑:我认为 git ls-files -dmo 在这里会很有用,但我不知道如何编写脚本来解析它的输出。


请不要在标题后添加“_solved_”。相反,考虑将一个答案标记为已接受。这将告诉其他人问题现在已经解决。谢谢。 - Bugs
更新:我的问题是一个XY问题的实例,因为我的最终目标是“保持其他所有内容的差异输出更清晰”。我最终被说服,将对.svg文件的更改分离成它们自己的提交会违反原子提交的原则。相反,我现在使用了一个包含行*.svg -diff.gitattributes文件。这告诉Git将.svg文件视为二进制文件,因此它将输出“二进制文件不同”作为差异消息。 - Jordan Bradford
1个回答

2

这个可以通过 pre-commit 钩子完成。

如何编写呢?

取决于您想使用哪种语言进行编写。

由于可以直接运行 Git 工具,因此 Shell 脚本往往是最简单的。在这里,您可以运行 git diff-index --name-status 来比较索引(拟议提交)和当前提交(即 HEAD),然后读取正在添加、修改或删除的文件,以查看是否有名字以 .svg 结尾的文件,以及是否有其他结尾的文件。这让您可以调整规则,允许删除 .svg 文件而进行其他更改。或者,如果文件状态(添加/删除/修改)不相关,则会更简单:

# straight from the sample pre-commit hook
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

# create a temp file to hold diff output
tmpfile=$(mktemp)
trap "rm -f $tmpfile; exit" 0 1 2 3 15
git diff-index --cached --name-only --diff-filter=ADM $against > $tmpfile

# read the status and names from the temp file.
# we use a temp file simply because "| while read ..." runs
# a sub-shell which means that variable changes don't make
# it back to the parent shell.  there are other workarounds
# but this one is simple.
num_svg=0
num_nonsvg=0
while read name; do
    case "$name" in
    *.svg) num_svg=$((num_svg + 1));;
    *) num_nonsvg=$((num_nonsvg + 1));;
    esac
done < $tmpfile

# now disallow commit if there are mixed svg and non-svg files
if [ $num_svg -gt 0 -a $num_nonsvg -gt 0 ]; then
    echo "this commit affects both .svg files and non-svg files" 1>&2
    exit 1
fi
# run any other checks here too
exit 0

(注:这完全未经测试)

(注:这完全未经测试)


上述脚本将阻止提交,如果其中包含 svg 文件。但我们是否可以仅允许没有 svg 文件的提交,并且在钩子脚本中添加 svg 文件到新的提交中?注意:这可能不是 OP 所要求的内容。但我正在寻找类似的解决方案。 - karthick
@karthick:理论上讲,可以让钩子(hook)自己进行单独的提交,但这是一个不好的想法。不要这样做:相反,编写一个脚本来进行提交。该脚本可以禁用任何钩子(使用--no-verify),或设置控制钩子的环境变量(使用您喜欢的任何代码)。 - torek
“git ls-files -dmo --exclude-standard” 会产生与您的 “git diff-index” 命令相同的结果吗? - Jordan Bradford
不,git ls-files 读取索引("将被提交的内容"),并可选择将其与当前的工作目录进行比较(这就是 -d-m 的作用),但根本不会将其与 HEAD 提交进行比较。使用 git diff-index --cached 比较 HEAD("现在已提交的内容")与索引。 - torek
感谢您提醒这段代码完全未经测试,因为当我尝试时它并没有起作用。我在最后一个测试中添加了一个else语句,以打印计数器变量以查看发生了什么: echo "DEBUG: num_svg: $num_svg num_nonsvg: $num_nonsvg" 1>&2输出始终为DEBUG: num_svg: 0 num_nonsvg: 0 - Jordan Bradford
哦,嗯,显然是个错误,循环需要重定向其标准输入。我会修复的。 - torek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接