Lye*_*UKH 6 git garbage-collection git-gc
启动后在后台发生了什么,
git gc git prune输出git gc:
Counting objects: 945490, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (334718/334718), done.
Writing objects: 100% (945490/945490), done.
Total 945490 (delta 483105), reused 944529 (delta 482309)
Checking connectivity: 948048, done.
Run Code Online (Sandbox Code Playgroud)
git prune的输出:
Checking connectivity: 945490, done.
Run Code Online (Sandbox Code Playgroud)
这两个选项有什么区别?
谢谢
tor*_*rek 13
git prune只删除松散,无法到达的陈旧对象(对象必须具有所有三个属性才能被修剪).无法访问的打包对象保留在其包文件中.可到达的松散物体仍然可以到达并且松散.无法访问但尚未过时的对象也保持不变.陈旧的定义有点棘手(详见下文).
git gc做得更多:它打包引用,打包有用的对象,到期reflog条目,修剪松散的对象,修剪删除的工作树和prunes/gc的旧git rerere数据.
我不确定你在上面的"在后台"是什么意思(背景在shell中有技术含义,这里的所有活动都发生在shell的前景中,但我怀疑你并不是指这些术语).
什么git gc是协调整个系列的收集活动,包括但不限于git prune.下面的列表是一组由前台运行的命令gc没有--auto(省略它们的参数,这依赖于在一定程度上git gc的参数):
git pack-refs:紧凑引用(转入.git/refs/heads/...和.git/refs/tags/...输入条目.git/packed-refs,消除单个文件)git reflog expire:使旧的reflog条目过期git repack:将松散的对象打包成打包的对象格式git prune:删除不需要的松散物体git worktree prune:删除用户已删除的已添加工作树的工作树数据git rerere gc:删除旧的rerere记录还有一些单独的文件活动git gc本身,但上面是主要序列.注意git prune发生后(1)到期reflogs和(2)运行git repack:这是因为被移除过期引用日志条目可能导致对象成为未引用的,因此不会被打包,然后得到修剪,使其完全消失.
在详细介绍之前,最好在Git中定义对象是什么,以及对象是松散还是打包的含义.我们还需要了解对象可以访问的含义.
每个对象都有一个哈希ID - git log例如你看到的那些丑陋的ID之一- 就是该对象的名称,用于检索目的.Git将所有对象存储在键值数据库中,其中名称是键,对象本身就是值.因此,如何Git的对象是Git的存储文件和承诺,而事实上,有四种对象类型: 一个提交对象持有的实际承诺.甲树对象包含套对,1人类可读名称等README或subdir与另一个对象的散列ID一起.如果树中的名称是文件名,则另一个对象是blob对象;如果名称是子目录的名称,则它是另一个树对象.blob对象保存实际的文件内容(但请注意,文件的名称位于链接到blob的树中!).最后一个对象类型是带注释的标记,用于带注释的标记,这里不是特别有趣.
一旦制成,就不会有任何对象被改变.这是因为对象的名称 - 它的哈希ID - 是通过查看对象内容的每个位来计算的.将任何一位从零更改为一,反之亦然,并且哈希ID会更改:您现在拥有另一个具有不同名称的对象.这就是Git检查没有文件被搞乱的方式:如果文件内容被更改,对象的哈希ID就会改变.对象ID存储在树条目中,如果更改了树对象,则树的ID将更改.树的ID存储在提交中,如果树ID已更改,则提交的哈希值将更改.因此,如果您知道提交的哈希值a234b67...并且提交的内容仍然是哈希值a234b67...,则提交中没有任何更改,并且树ID仍然有效.如果树仍然哈希到自己的名称,其内容仍然有效,因此blob ID是正确的; 所以只要blob内容哈希到它自己的名字,blob也是正确的.
对象可以松散,这意味着它们存储为文件.该文件的名称只是哈希ID.2 松散物体的内容是zlib缩小的.或者,可以打包对象,这意味着许多对象存储在单个包文件中.在这种情况下,内容不仅仅是放气,它们首先是delta压缩的.Git选择一个基础对象 - 通常是某个blob(文件)的最新版本 - 然后找到可以表示为一系列命令的其他对象:获取基本文件,删除此偏移处的一些文本,在另一个文本中添加其他文本偏移,等等.这里记录了包文件的实际格式,如果有点轻微的话.注意,不同于大多数版本控制系统,所述Δ-压缩发生在水平低于所存储的对象的抽象:GIT中存储全快照,然后做Δ-压缩后,对基础对象.Git仍然通过其哈希ID名称访问对象; 它只是读取该对象涉及读取包文件,找到对象及其底层的delta基础,并在运行中重建完整的对象.
有一个关于包文件,指出任何增量压缩的对象一般规则中一个包文件必须在其所有基地一样包文件.这意味着包文件是自包含的:从不需要打开多个附加包文件来从包含该对象的包中获取对象.(这个特殊的规则可以被故意违反,产生Git称为瘦包的东西,但那些仅用于通过网络连接将对象发送到已经具有基础对象的另一个Git.另一个Git必须"修复"或"胖"将薄包装成正常的包装文件,然后将其留给Git的其余部分.)
对象可达性有点棘手.让我们首先看一下提交可达性.
请注意,当我们有一个提交对象时,该提交对象本身包含多个哈希ID.它有一个用于保存与该提交一起的快照的树的哈希ID.它还具有一个或多个父提交的哈希ID ,除非此特定提交是根提交.根提交被定义为没有父项的提交,因此这有点循环:提交有父项,除非它没有父项.但是很明显:给定一些提交,我们可以将该提交绘制为图形中的节点,箭头从节点出来,每个父节点一个:
<--o
|
v
Run Code Online (Sandbox Code Playgroud)
这些父箭头指向提交的父级或父级.给定一系列单父提交,我们得到一个简单的线性链:
... <--o <--o <--o ...
Run Code Online (Sandbox Code Playgroud)
其中一个提交必须是链的开头:这是根提交.其中一个必须是结束,这是提示提交.所有内部箭头都指向后方(向左),因此我们可以在没有箭头的情况下绘制它,知道根位于左侧且尖端位于右侧:
o--o--o--o--o
Run Code Online (Sandbox Code Playgroud)
现在,我们可以添加一个分支的名字一样master.该名称只是指向提示提交:
o--o--o--o--o <--master
Run Code Online (Sandbox Code Playgroud)
无嵌入式箭头内提交都不能改变,因为没有在任何物体都不能更改.master但是,分支名称中的箭头实际上只是某个提交的哈希ID,这可能会发生变化.让我们用字母来表示提交哈希:
A--B--C--D--E <-- master
Run Code Online (Sandbox Code Playgroud)
该名称master现在只存储commit的提交哈希E.如果我们添加一个新的提交master,我们这样做是通过写出一个提交,其父级是E树,它的树是我们的快照,给我们一个全新的哈希,我们可以调用它F.承诺F点回归E.我们有Git写入F的哈希ID master,现在我们有:
A--B--C--D--E--F <-- master
Run Code Online (Sandbox Code Playgroud)
我们添加了一个提交并更改了一个名称master.通过从名称开始可以访问所有以前的提交master.我们读出了哈希ID F和读取提交F.这有哈希ID E,所以我们已经达到提交E.我们读取E以获取哈希ID D,从而达到D.我们重复,直到我们阅读A,发现它没有父母,并完成.
如果有分支,那只意味着我们有另一个名称找到的提交,其父项是名称中的提交之一master:
A--B--C--D--E--F <-- master
\
G--H <-- develop
Run Code Online (Sandbox Code Playgroud)
名称develop定位提交H; H发现G; 并G指回E.因此所有这些提交都是可以访问的.
提交多个父级 - 即合并提交 -如果提交本身可访问,则可以使所有父级都可以访问.因此,一旦您进行合并提交,您可以(但不必)删除标识已合并的提交的分支名称:现在可以从您执行合并操作时所在的分支的尖端访问它.那是:
...--o--o---o <-- name
\ /
o--o <-- delete-able
Run Code Online (Sandbox Code Playgroud)
这里底部行的提交可以name通过合并到达,就像最上一行的提交始终可以从中获取一样name.删除名称delete-able使它们仍然可以访问.如果合并提交是不存在,因为在这种情况下:
...--o--o <-- name2
\
o--o <-- not-delete-able
Run Code Online (Sandbox Code Playgroud)
然后删除not-delete-able有效地放弃底行的两个提交:它们变得无法访问,因此有资格进行垃圾收集.
此相同的可达性属性适用于树和blob对象.例如,Commit G有一个tree,其中tree有<name,ID>对:
A--B--C--D--E--F <-- master
\
G--H <-- develop
|
tree=d097...
/ \
README=9fa3... Makefile=0b41...
Run Code Online (Sandbox Code Playgroud)
因此,从提交G,树对象d097...是可达的; 从该树中,可以访问blob对象,blob对象9fa3...也是如此0b41....提交H可能具有相同的README对象,在同一个名称下(虽然是一个不同的树):这很好,只是让9fa3双倍可达,这对Git来说并不重要:Git只关心它是否可以访问.
外部引用 - 分支和标记名称以及在Git存储库中找到的其他引用(包括Git 索引中的条目以及通过链接的已添加工作树的任何引用),为对象图提供了入口点.从这些入口点开始,任何对象都是可访问的 - 具有一个或多个可以导致它的名称 - 或者无法访问,这意味着没有可以通过其找到对象本身的名称.我已经从这个描述中省略了带注释的标签,但它们通常是通过标签名称找到的,带注释的标签对象有一个它找到的对象引用(任意对象类型),如果标签对象本身可以到达那么一个对象可以到达.
因为引用只引用一个对象,但有时我们使用我们想要在之后撤消的分支名称来执行某些操作,Git会保留引用所具有的每个值的日志,以及何时.这些参考日志或reflogs让我们知道master它有昨天,还是什么在develop最后一周.最终这些reflog条目陈旧且陈旧,不再可能有用,git reflog expire并将丢弃它们.
是什么git repack呢,在较高的水平,现在应该是比较清楚的:事实证明许多松散的对象的集合到一个包文件全所有这些对象.但它可以做得更多:它可以包含前一个包中的所有对象.之前的包装变得多余,之后可以取下.它还可以省略包中任何无法访问的对象,将它们转换为松散的对象.当git gc运行git repack它依赖于选择这样做git gc的选择,因此,其准确语义变化在这里,但对于前景默认git gc是使用git repack -d -l,它具有git repack删除多余的包和运行git prune-packed.该prune-packed程序删除也出现在包文件中的松散目标文件,因此这将删除进入包中的松散对象.该repack程序传递-l到选项git pack-objects(它是建立在包文件中的实际的主力),其中这意味着省略从其它存储库借用对象.(对于大多数正常的Git用法,这最后一个选项并不重要.)
在任何情况下,从git repack技术上讲,它都会git pack-objects打印计数,压缩和写入消息.完成后,您有一个新的包文件,旧的包文件已经消失.新的pack文件包含所有可访问的对象,包括旧的可到达的打包对象和旧的可到达的松散对象.如果松散的对象从旧的(现在已拆除和已删除)包文件中弹出,则它们会加入其他松散(且无法访问)的对象,这些对象会使您的存储库混乱.如果它们在拆除过程中被摧毁,则只剩下现有的松散且无法到达的物体.
现在是时候了git prune:它找到松散的,无法访问的对象并将其删除.但是,它有一个安全开关,--expire 2.weeks.ago默认情况下,如果它们不是至少两周git gc,它不会删除这些对象.这意味着正在创建新对象的任何Git程序(尚未连接它们)都有一个宽限期.新对象可以松散且无法访问(默认情况下)十四天之前git prune将删除它们.因此,一个忙于创建对象的Git程序有十四天,在此期间它可以完成将这些对象连接到图形中.如果它决定那些物品不值得挂钩,它就可以离开它们; 从那时起14天,未来git prune将删除它们.
如果git prune手动运行,则必须选择--expire参数.默认情况下--expire不是2.weeks.ago,而是只是now.
1树对象实际上包含三元组:名称,模式,哈希.模式是100644或100755用于blob对象,004000用于子树,120000用于符号链接,等等.
2对于Linux查找速度,散列是前两个字符之后分裂:哈希名称ab34ef56...成为ab/34e567...在.git/objects目录中.这使每个子目录的大小保持在.git/objects小的范围内,这样可以驯服某些目录操作的O(n 2)行为.git gc --auto当一个对象目录变得足够大时,这与自动重新打包有关.Git假设每个子目录的大小与哈希值大致相同,因此它只需要统计一个子目录.
| 归档时间: |
|
| 查看次数: |
1986 次 |
| 最近记录: |