我想通过了解进入
时实际发生的事情来更好地理解git-plumbinggit 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 -w
clean
ed内容然后然后,索引会以某种方式获取更新,其中涉及git mktree。但到底发生了什么?目录的树是否仅包含添加的文件或以前提交的所有文件?接下来会发生什么?
答案 0 :(得分:2)
git add
没有一个等效的管道命令,但最接近的命令可能是git update-index
。 ProGit描述是正确的:
用目录的内容列表替换每个目录。结果是add
指定的文件列表,对目录中已知不的文件(即已删除)以及具有特殊索引的文件进行了一些特殊处理州(--assume-unchanged
和--skip-worktree
)。换句话说,这一步也可以参考当前的指数。
检查未分期但被忽略的(通过.gitignore
)文件并将其从列表中丢弃(带警告),除非给出-f
/ --force
。
(旁注:我没有在子目录上测试过这个问题,并且-f
可能不适用于递归扫描所选择的子目录条目,但实际上只能用于名称在命令行中给出。如果是这种情况,则必须将步骤2与步骤1结合起来,以便即使使用{{1}我们也不会忽略它们,也不会添加名称}。)
如果需要,请应用属性,根据需要制作临时清理的文件副本。
使用-f
获取写入存储库的已修改文件,并更新其索引条目,包括模式更新。 (对于在步骤3中清理的文件,您必须按照建议使用单独的git update-index --add --remove --replace
,并使用git hash-object -w
代替--index-info
。)
--add --remove --replace
命令根本不会进入此过程,因为索引本身只是一个平面文件,使用的文档格式很差(或者更确切地说,是几种格式之一;请参阅git mktree
)。
索引允许每个文件名最多四个条目,称为阶段:阶段0是普通缓存条目,阶段1到3是冲突合并。删除标记文件有几个特殊位,或--index-version
,--assume-unchanged
,--skip-worktree
和一些特殊的内部使用标志,即使Git没有存储目录 - 有目录的索引条目(让Git查看目录的--intent-to-add
字段,然后让Git快速跳过未修改的目录,前提是它可以信任操作系统来维护它。)
ctime
命令仅在将索引转换为一系列树对象时才起作用。 Git必须为索引中的每个子目录创建一个树,加上一个表示整体索引的顶级树。 (子项目,如果存在,已经在索引中作为" gitlink"条目,这是它们在包含它们的任何树中出现的方式。)