1

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

git add $DIRECTORY

git add $FILE

它是如何工作的?

通过阅读progit 的 git internals section 可以获得一个粗略的想法。

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

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

4

1 回答 1

2

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

  1. 用目录内容列表替换每个目录。结果是由 指定的文件列表,add对现在已知不在目录中的文件(即,已删除)和具有特殊索引状态(--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)的平面文件。

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

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

于 2016-05-09T12:10:08.133 回答