GIT预提交钩子,在修改/添加的文件中搜索非UTF-8编码(如果发现任何文件,则拒绝提交)

问题描述 投票:1回答:2

我正在使用Git for Windows(和TortoiseGit)。

我的目标是防止修改/添加至少有一个非UTF-8文件的提交。

  • 枚举修改/添加的文件:我找到了以下代码 { git diff --name-only ; git diff --name-only --staged ; } 这是最好(正确和最简洁)的方法吗?
  • 搜索非UTF-8文件:我找到了以下代码 { git diff --name-only ; git diff --name-only --staged ; } | xargs -I {} bash -c "iconv -f utf-8 -t utf-16 {} &>/dev/null || echo {} - is non-UTF8!" 如果我在我的存储库根文件夹中启动Git Bash - 它可以工作(显示每个非UTF-8文件)。所以我将.git/hooks/pre-commit.sample重命名为.git/hooks/pre-commit并复制粘贴上面的代码。在提交更改后,TortoiseGit内部没有任何特殊显示提交gui窗口。所以看起来预提交挂钩不能正常工作。
  • 如果存在任何非UTF-8文件,则拒绝提交:显示所有非UTP-8文件后,应拒绝提交。但我不知道如何做到这一点(显示一些退出代码 - 但如何?)。

所以任何帮助都表示赞赏。

windows bash git git-bash pre-commit-hook
2个回答
2
投票

所以答案是(对phd而言,以及对torek的有用说明):

    git diff --name-only --staged --diff-filter d | xargs -I {} bash -c 
 "iconv -f utf-8 -t utf-16 {} &>/dev/null || { echo {} - is non-UTF8!; exit 1; }"

此代码遍历所有在提交中更改的文件(删除除外 - 即添加,修改,复制和重命名)并检查是否存在任何非UTF8文件。列出所有找到的文件并中止提交。


1
投票

您现有的解决方案可能已足够。虽然这不是100%正确:这是剩下的问题,所有这些都是次要问题,你可以稍后(如果有的话)在你的闲暇时解决:

  • 你只需要git diff ... --staged(或--cached),因为Git将提交的是索引/登台区域中的任何文件,git diff将它与HEAD提交中的内容进行比较,并告诉你那里有什么不同。如果索引中的文件副本与HEAD中的文件副本不同,则应检查索引副本。
  • 从技术上讲,最好在这里使用git diff-index --cached,以便不遵守任何用户的git diff配置。也就是说,git diff-index是Git中的一个管道命令,这意味着它的目的是用于其他计算机程序:它只能基于参数以完全可预测的方式运行,而不是基于任何git config设置。但是如果你自己这样做,并且你配置git diff这样就会破坏你自己对git diff的使用,那么,这是你自己的错。 :-)
  • 您也可以考虑使用--diff-filter在此处排除已删除的文件。否则,您的检查器将始终失败(因为iconv将无法读取已删除的文件)。
  • 最重要的是:iconv将从工作树中读取文件。正如我在第一个要点中指出的那样,Git将承诺上演的内容,而不是工作树中的内容。

作为一个例子 - 在TortoiseGit中可能会或可能不会 - 考虑如果你这样做会发生什么:

$ git checkout master
$ printf '\300\300\300' > badfile    # put bad non-UTF-8 crud into file
$ git add badfile                    # copy file into index
$ echo 'good data' > badfile         # replace work-tree contents
$ git commit

这个提交将提交错误的内容 - \300的三个字节,没有换行符 - 在索引中,但你的预提交钩子将在好文件的内容上运行iconv -f utf-8 -t utf-16,读取good data,即当然好。

要解决此问题,您的预提交过滤器必须从索引中提取要提交的每个文件的数据。你如何做到这一点取决于你。最简单(但也许最慢)的方法是使用git checkout-index将整个索引内容提取到临时工作区。一个更好的方法可能是将每个in-index(in-staging-area)路径名转换为有效的索引说明符(即path/to/file变为:path/to/file)并使用git cat-file -p $specifier | iconv ...扫描每个。但所有这些都是相当低效的,特别是在Windows上。为了提高效率,您可能希望编写一个Python脚本,该脚本使用git cat-file --batch一次性提取它们,并在那里进行格式检查。

© www.soinside.com 2019 - 2024. All rights reserved.