在 git 钩子修改的文件上使用 skip-worktree?

Using skip-worktree on a file that is modified by git hooks?

我有一个 post-commit 挂钩,用于编辑特定的源文件(具体来说,将提交哈希写入 c# class 中的字符串)。脚本是:

#!/bin/sh
hashStr=`git log --pretty=format:'%H' -n 1`
str="public static class GitHash { public static readonly string CommitHash = \"$hashStr\"; }"
echo $str > MyApp\MyNamespace\gitHash.cs

相同的脚本在我的 post-rebase、post merge 等挂钩中。它工作正常并显示为 git 中的修改,直到我将 GitHash.cs 文件添加到 skip-worktree:

git update-index --skip-worktree MyApp/MyNamespace/GitHash.cs

现在文件根本没有被修改,并保持在我将它添加到 skip-worktree 时的状态。如果我将它从 skip-worktree 中删除,钩子将再次工作(文件已修改)。 如果我正确理解 skip-worktree,当我想在本地修改文件时可以使用它,但不想意外提交它们并且不想在我执行 git diff 时看到这些文件.但是,它似乎以某种方式阻止了钩子编辑此文件?

所以,如果我想通过 hooks 修改文件并且不显示在 git diff 上,我应该怎么做?

我意识到这与您开始的路径不同,但是:

如果文件纯粹是生成的文件,为什么还要将其存储在源代码管理中?如果您将其从提交中删除(并可能将其删除到 .gitignore)并将生成它作为构建过程的一部分而不是挂钩,那么您应该得到您所描述的行为。

从技术上讲,skip-worktree 位作为稀疏结帐的助手存在。以你现在的方式使用它是一种滥用。然而,另一位 assume-unchanged 是慢速 lstat 系统调用的助手,虽然您可以以相同的方式使用它,但这也是一种技术滥用。所以无论哪种方式,你都不太走运。

如果可能的话,通常最好根本不要这样做。例如,如果您的构建系统只能 创建 适当的信息——将其写入一个永远不会被提交的文件——这通常是可行的方法。 (这就是 。)但是,您可以让 post-commit 挂钩写入文件,同时设置其中一个或两个位,这就是您正在做的。这只是意味着文件不会进入新的提交:相反,索引挂在该文件的 old 副本上。

要将更新的文件放入新的提交中,您必须将文件复制到Git的索引你做出新的提交之前。但请记住,您所做的每一次提交都有一个新的、唯一的哈希 ID。这意味着您必须在知道之前存储哈希 ID。

换句话说,您可以存储在已提交文件中的哈希 ID 绝不是您可以进行的包含该文件的提交的哈希 ID。您 可以 得到那之前的那个。也许这就足够了:您可以 before 进行提交,存储 current 提交的哈希 ID,确保它匹配除了新哈希 ID 文件:

bit=skip-worktree
# or assume-unchanged: either will work, though both are technically abuse

git commit                    # make sure we commit what we have
hash=$(git rev-parse HEAD)    # get the hash ID of the current commit
echo "built from stuff that mostly matches $hash" > file.ext
git update-index --no-$bit file.ext
git add file.ext
git update-index --$bit file.ext
git commit -m "update build info"

但是你绝对不能在文件中存储具有正确哈希 ID 的提交的哈希 ID,因为你无法预测它将是什么:存储文件中的未来哈希 ID 更改未来提交的哈希 ID。1


1这里的一个可能的例外是如果您设法在散列函数中找到 fixed point