【问题标题】:Which plumbing commands achieve the same as git add?哪些管道命令与 git add 实现相同?
【发布时间】:2016-09-04 00:47:31
【问题描述】:

我想通过了解进入时实际发生的情况来更好地理解

git add $DIRECTORY

git add $FILE

它是如何工作的?

阅读progit's git internals section可以大致了解一下。

  • 如果$DIRECTORY 是一个目录,类似于find $DIRECTORY -type f -exec git add {} \;,即递归添加$DIRECTORY 中的所有文件。然后,git add $FILENAME 应用于每个文件。
  • 检查.gitignore(及其“上级”)
  • 检查 .gitattributes,如果适用,运行 clean 过滤器
  • git hash-object -wcleaned 内容

然后,索引以某种方式得到更新,这涉及到git mktree。但是那里到底发生了什么?目录的树是否仅包含添加的文件或之前提交的所有文件?接下来会发生什么?

【问题讨论】:

  • 是的,Git 是否会在每次 diffadd 等时对所有内容进行递归搜索?

标签: git-plumbing git git-add git-plumbing


【解决方案1】:

git add 没有一个等效的管道命令,但最接近的可能是git update-index。 ProGit 的描述是正确的:

  1. 用目录内容列表替换每个目录。结果是add 指定的文件列表,对现在已知 not 在目录中的文件(即,已删除)和具有特殊索引状态的文件( --assume-unchanged--skip-worktree)。也就是说,这一步也参考了当前的索引。

  2. 检查未暂存但被忽略(通过.gitignore)的文件并从列表中丢弃它们(带有警告),除非给出-f / --force

    (旁注:我没有在子目录上测试过这个,-f 可能不适用于递归扫描拾取的子目录条目,但仅适用于命令行上实际给出的名称。如果是这样在这种情况下,第 2 步必须与第 1 步结合使用,这样即使使用-f,我们也不会添加名称。)

  3. 如果有的话,应用属性,如果需要的话,制作临时清理的文件副本。

  4. 使用git update-index --add --remove --replace 将修改后的文件写入存储库,并更新其索引条目,包括模式更新。 (对于在第 3 步中清理的文件,您必须按照您的建议使用单独的 git hash-object -w,并使用 --index-info 而不是 --add --remove --replace。)

git mktree 命令根本不会进入此过程,因为索引本身只是一个使用记录不充分的格式(或更准确地说,是几种格式之一;请参阅--index-version)的平面文件。

索引允许每个文件名最多四个条目,称为 stages:stage 0 是普通缓存条目,stage 1 到 3 用于冲突合并。有几个特殊位用于标记文件已删除,或--assume-unchanged--skip-worktree--intent-to-add,以及一些特殊的内部使用标志,而且——即使 Git 不存储目录——也有索引目录条目(让 Git 查看目录的 ctime 字段,然后让 Git 快速跳过未修改的目录,前提是它可以信任操作系统来维护它)。

git mktree 命令仅在将索引转换为一系列树对象时发挥作用。 Git 必须为索引中的每个子目录制作一棵树,再加上一棵代表整个索引的顶级树。 (子项目,如果存在的话,已经在索引中作为“gitlink”条目,这是它们在包含它们的任何树中的显示方式。)

【讨论】:

  • 每次执行diffadd 等时,Git 是否会对文件系统中的所有内容进行递归搜索?
  • @Geremia:差不多,虽然细节差异很大。索引作为 cache 具有特殊的“加速”角色,如果相关目录上的时间戳与存储在索引本身中的时间戳匹配,则让 Git 跳过递归读取任何内容。对于宽和/或深的树,这可能会产生巨大的差异,因此,即使是未跟踪的目录也存储在缓存中(可选地在第二个“拆分”索引缓存中),在幕后。
猜你喜欢
  • 2015-05-28
  • 2020-08-16
  • 2023-01-26
  • 1970-01-01
  • 2014-11-11
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多