GIT pre-commit hook 在 modified/added 文件中搜索非 UTF-8 编码(如果找到则拒绝提交)
GIT pre-commit hook which searches non-UTF-8 encodings among modified/added files (and rejects commit if it finds any)
我将 Git 用于 Windows(和 TortoiseGit)。
我的目标是防止 modified/added 中至少有一个非 UTF-8 文件的提交。
正在枚举 modified/added 个文件: 我找到了以下代码
{ 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 commit gui window 中没有任何特殊显示。所以看起来预提交挂钩无法正常工作。
如果存在任何非 UTF-8 文件则拒绝提交: 显示所有非 UTP-8 文件后应拒绝提交。但我不知道该怎么做(显示一些退出代码 - 但是如何?)。
非常感谢任何帮助。
所以答案是(感谢 phd and great thx to 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 文件。列出所有找到的文件并中止提交。
您现有的解决方案可能就足够了。虽然它不是 100% 正确:这里是剩余的问题,所有这些都是小问题,您可以稍后(如果有的话)在您有空的时候修复:
您只需要 git diff ... --staged
(或 --cached
),因为 Git 将提交 index/staging-area 中的任何文件,并且git diff
将其与 HEAD
提交中的内容进行比较,并告诉您那里有什么不同。如果索引中的文件副本与 HEAD
中的文件副本不同,您应该检查索引副本。
从技术上讲,最好在此处使用 git diff-index --cached
,以便不遵守任何用户的 git diff
配置。也就是说,git diff-index
是 Git 中的 plumbing 命令,这意味着它旨在被其他计算机程序使用:它 运行 在完全可预测的方式仅基于参数,而不是基于任何 git config
设置。但是,如果您是为自己执行此操作,并且您配置 git diff
以致它破坏了您自己对 git diff
的使用,那么,那是您自己的错。 :-)
您也可以考虑在此处使用 --diff-filter
来排除已删除的文件。否则,您的检查器将始终无法删除(因为 iconv
将无法读取已删除的文件)。
最重要的:iconv
将从工作树读取文件。正如我在第一个要点中指出的那样,Git 将提交 暂存的 ,而不是工作树中的内容。
举个例子——在 TortoiseGit 中可能可行也可能不可行——考虑一下如果你这样做会发生什么:
$ git checkout master
$ printf '000' > 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
此提交将 提交 索引中的错误内容——0
的三个字节没有换行符,但是你的预提交挂钩将运行iconv -f utf-8 -t utf-16
遍历good文件的内容,阅读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
一次提取它们,并在那里进行格式检查。
我将 Git 用于 Windows(和 TortoiseGit)。
我的目标是防止 modified/added 中至少有一个非 UTF-8 文件的提交。
正在枚举 modified/added 个文件: 我找到了以下代码
{ 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 commit gui window 中没有任何特殊显示。所以看起来预提交挂钩无法正常工作。如果存在任何非 UTF-8 文件则拒绝提交: 显示所有非 UTP-8 文件后应拒绝提交。但我不知道该怎么做(显示一些退出代码 - 但是如何?)。
非常感谢任何帮助。
所以答案是(感谢 phd and great thx to 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 文件。列出所有找到的文件并中止提交。
您现有的解决方案可能就足够了。虽然它不是 100% 正确:这里是剩余的问题,所有这些都是小问题,您可以稍后(如果有的话)在您有空的时候修复:
您只需要
git diff ... --staged
(或--cached
),因为 Git 将提交 index/staging-area 中的任何文件,并且git diff
将其与HEAD
提交中的内容进行比较,并告诉您那里有什么不同。如果索引中的文件副本与HEAD
中的文件副本不同,您应该检查索引副本。从技术上讲,最好在此处使用
git diff-index --cached
,以便不遵守任何用户的git diff
配置。也就是说,git diff-index
是 Git 中的 plumbing 命令,这意味着它旨在被其他计算机程序使用:它 运行 在完全可预测的方式仅基于参数,而不是基于任何git config
设置。但是,如果您是为自己执行此操作,并且您配置git diff
以致它破坏了您自己对git diff
的使用,那么,那是您自己的错。 :-)您也可以考虑在此处使用
--diff-filter
来排除已删除的文件。否则,您的检查器将始终无法删除(因为iconv
将无法读取已删除的文件)。最重要的:
iconv
将从工作树读取文件。正如我在第一个要点中指出的那样,Git 将提交 暂存的 ,而不是工作树中的内容。
举个例子——在 TortoiseGit 中可能可行也可能不可行——考虑一下如果你这样做会发生什么:
$ git checkout master
$ printf '000' > 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
此提交将 提交 索引中的错误内容——0
的三个字节没有换行符,但是你的预提交挂钩将运行iconv -f utf-8 -t utf-16
遍历good文件的内容,阅读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
一次提取它们,并在那里进行格式检查。