当我读到git-rebase时,我理解重新提交的提交应该丢失。我说应该是因为我注意到了,知道重新设定的sha,我可以回想起来 假设我有以下三个提交
A -> B -> C
其中C
的sha是cshaid
。然后,如果我以fixing-up
交互式地将C
B
变为git rebase -i HEAD~2
,然后使用git log
检查结果,我会获得预期结果,这意味着
A -> B'
其中B'
的sha与B
的sha不同
但是,再次显示git log cshaid
会显示
A -> B -> C
问题:这是一种已知行为吗?我尝试阅读git rebase --help
但找不到相关信息。为什么重新提交承诺并不是简单的忘记?我的意思是,只有当你知道自己在做什么并且能够做到这一点时,rebase才是一种危险的操作,这就是拥有脏索引(或者保存这些无用提交的地方)的重点?我错过了什么吗?
重现步骤(并更好地理解我的怀疑)。如果您愿意重现这种情况,请尝试:
mkdir sampledir && cd sampledir && git init
touch file && git add -A . && git commit -m "Initial"
git commit -am "First modification"
git commit -am "Second modification"
git log
,您会看到三次提交,请记住Second modification
git rebase -i HEAD~2
,fixup
Second modification
加入First modification
git log
,您会看到两个提交,其中First modification
的sha现在与第5步不同git log sha-for-"Second modification"
将显示与此列表中第5点完全相同的树答案 0 :(得分:4)
是的,这是预期的行为。未引用的提交最终将被垃圾收集,从而从磁盘中清除。它们被保存了好几天(默认情况下为14天),但在此之前的14天计时器甚至开始计时,对象必须已经从reflog中过期(默认情况下,无法访问的对象在30天后过期)。
相关的StackOverflow问题:
答案 1 :(得分:3)
......我知道重新提交的提交应该丢失
他们不是迷失,他们(故意)“被遗弃”(我的任期)。
确实rebase
复制了旧提交的内容。实际上,除了特殊的优化等之外,它基本上与执行git cherry-pick
相同(并且交互式rebase脚本对每个“pick”操作使用git cherry-pick
,并且对“squash”和“modash”提交修改样式提交修理“操作”。
然后,存储库中的提交何时以及是否可见完全取决于其他内容。通常git log
以您所在分支的名称开头,如HEAD
中所记录的那样(.git
目录中有一个名为HEAD
的文件,其中包含字符串{ {1}},这就是git知道你是“在分支主人身上”的原因。) 1
给定一个分支名称,git通过“读取引用”将其转换为(单个)提交:
ref: refs/heads/master
然后$ git rev-parse master # note: you can also rev-parse HEAD directly
676699a0e0cdfd97521f3524c763222f1c30a094
命令可以通过SHA-1读取提交对象。该提交对象有一些父SHA-1,log
也读取它们,依此类推,直到它到达没有父项的提交(“root”提交)。
因此,给定根提交git log
,第二次和第三次提交A
和B
- 加上标签C
,指向master
:
C
(这里的箭头表示谁指向谁,它的方式与你的绘图相反!),git可以从A <-- B <-- C <-- HEAD=master
开始A
找到(到达)提交C
并且向后工作。
rebase复制C
并在B
折叠,按预期给出C
:
B'
A <-- B <-- C
^
\
B'
显示B'
的原因是标签git log
被“剥离”了提交master
并且“粘贴到”提交{{1} }}。更确切地说,分支C
(B'
) 2 的文件将被master
的新SHA-1重写:
.git/refs/heads/master
正如我所听到的那些答案所指出的那样,“废弃的”提交(以及存储库中的任何其他被遗弃的对象)最终被“垃圾收集器”B'
删除。
A <-- B <-- C [no label, "abandoned"]
^
\
B' <-- HEAD=master
不被垃圾收集。并且,如果您创建引用git gc
的分支或代码标签,则在C
移动C
标签之前或之后, 标签也会保留存储库中的rebase
,可通过“普通”名称访问,您将看到master
(查看所有分支和标记名称,而不仅仅是C
中的名称)
1 git log --all
文件可以包含原始SHA-1。在这种情况下,你有git称之为“分离的HEAD”:你的SHA-1提交而不是它的分支名称。
2 分支和标记名称(实际上,任何引用都可以)“打包”,在这种情况下,单独的文件会消失。这节省了空间,并且您不应该依赖于单独文件的存在。但是,一旦分支变为“活动” - 进行了大量更新 - 单独的文件将重新出现,因为更新该文件比更新packed-refs文件更快更容易。
答案 2 :(得分:2)
git rebase
会删除对过时提交的引用,但不会导致立即删除它。在正常操作过程中定期自动执行的git gc
将(最终)从.git/objects
中删除实际的提交数据(尽管reflog
将保留对提交的活动的引用一段时间)。
这是一项安全功能;它使用git实际丢失数据变得非常困难。如果你真的想确保某些东西不见了 - 例如,如果你不小心提交了一个巨大的文件并且想要恢复磁盘空间 - 你需要使reflog条目到期并手动运行git gc
:
git reflog expire --expire=now --all
git gc --aggressive --prune=now
答案 3 :(得分:1)
我知道重新提交的提交应该丢失。
不。提交不要迷路。在繁忙的回购中,git最终将垃圾收集任何参考文件完全无法访问的内容并且已经持续了一个月或更长时间,但除了git gc
之外,git操作只会添加到历史记录图中。
移动标签对您的仓库中的实际历史记录完全没有影响。