如果我在 Git 预提交挂钩中修改日期戳文件并简单地调用 "git add timeStamp.cs",我 运行 会有什么麻烦?

What trouble will I run into if I modify a date-stamp file in a Git pre-commit hook and simply call "git add timeStamp.cs"?

这个论坛上有几个线程在某种程度上涉及这个主题,但作为 Git 的初学者,我不理解它们,我无法让它们正常工作。我有一个 C# 项目,我想 link- 在提交日期和时间中使用 Git 预提交挂钩。当我尝试以下操作时,它似乎工作正常:

cmd.exe /c "getTimeStampAndUpdateTimeStampFile.exe"
git add timeStamp.cs

然而,我在互联网上搜索时发现的大多数代码片段都复杂得多并且通常涉及隐藏,但我不明白为什么需要它。有人能解释一下吗,简单地说,我的简单方法有什么缺点,什么时候会给我带来问题?

一样,其他选择可能是更好的主意,但要回答这个问题:

What trouble [could] I run into

我们需要了解 Git 不会根据您的 工作树 (您可以查看和使用文件的地方)中的内容构建提交,而是来自 index.

这里的 TL;DR 是一些 git commit 选项导致使用秘密的附加索引文件,这样你的 git add 可能会影响 one 提交,但 随后 提交。

索引,也称为暂存区或(现在很少)缓存,主要是1 只是 .git 目录中名为 index 的文件中的一个数据结构。也就是说,git commit 一般打开并读取 .git/index 以查看在新提交中放入什么。2

事实是,你可以——而且 Git 可以在内部——将自己从 索引重定向到某个 替代 索引.你这样做,或者 Git 自己做,通过设置环境变量 GIT_INDEX_FILE 来保存一些文件名。这会影响每个 git <em> 子命令 </em> 命令,包括 git add,因此 git add 会将文件复制到替代索引而不是主索引。

当你运行一个普通的,普通的git commit,Git:

  • 使用常规索引(因此 GIT_INDEX_FILE 未设置,或设置为名称 .git/index);
  • 运行是你的预提交挂钩,如果拒绝提交则提前退出;
  • 锁定索引以防止更改(在我们读取它时没有 git add!);
  • 使用索引中的任何内容构建实际提交,将新的提交哈希 ID 写入或通过 HEAD;和
  • 解锁索引。

但是你也可以运行git commit --only或者默认的git commit --include加上文件名,and/or使用git commit -a.这些具有从具有文件 "pre-added" 的索引进行新提交的效果。为了使这项工作正常进行,Git 构建了一个 替代的临时 索引。也就是说,the 索引——这个工作树的主要索引,无论它存在于哪个文件中——还没有被修改。在您开始这个特定的 git commit 命令之前,它仍然匹配其中的任何内容。替代索引填写自:

  • 如果您使用 git commit --onlyHEAD 提交:我们想要一个类似于 HEAD 但有一些更新的提交,或者
  • 当前索引,如果你使用 git commit --include:我们想要一个相当于 git adding 一些文件的提交,但是如果新提交 失败 出于某种原因,我们不想将文件添加到 (主)索引。

如果您使用 git commit -a,Git 现在 运行 是 git add -u 的内部等价物,以与 git add -u 更新相同的方式更新此临时索引任何指数。如果您指定了特定文件,Git 现在 运行 相当于每个文件的 git add。无论哪种方式,这个临时索引现在都已更新以保存提议的新提交。

所以现在,我们有一个替代的临时索引,用于保存应该进入新提交的内容。如果这个新的提交成功,Git 也需要更新 real 索引,所以 Git 可能也需要建立一个更新的真实索引。

此时有两个或三个索引文件:

  1. 主/实指数
  2. 我们的临时索引。
  3. 预计的新主指数。

如果我们的临时预计的新的——即我们使用git commit --include而不是git commit --only——临时和预计的主要是同一个文件:文件 2 和 3 都被命名为 .git/index.lock(或添加工作树的不同路径)。

Git 现在 运行 像往常一样是您的预提交挂钩,但是 GIT_INDEX_FILE 设置为指向文件 #2——在此期间使用的临时索引git commit。如果您的挂钩使用 git add,它会将这些文件添加到文件 #2。

如果提交失败,Git只是回滚所有内容:(主)索引保持不变。 git add 你 运行 中的钩子实际上被撤消了。

如果提交成功,但是,Git现在将索引文件#3——准备好的、更新的索引——重命名为主索引。您对文件 #2 所做的 git add 消失 除非文件 2 和 3 是同一个文件。这不一定非常有害——用户可以再次 运行 git add——但它确实很奇怪。


1mostly这个词有多种原因,但总的想法是:有一些文件,并且用于各种目的,您有时可以——或者 Git 可以——使用 不同的 文件。

2如果您在添加的工作树中,(主/默认)索引位于 .git 目录下的不同位置。每个工作树都有自己的私有默认索引。