假设我有两个分支A
,master
。
现在在A分支我有这些承诺a
b
c
d
e
5 commits
然后用户压扁了提交,我不知道是怎么回事,但昨天在他的分支上我看到了1 commit with message squashed commits
今天我只看到git checkout -b B-backup
现在我想问一下,假设在挤压之前,我从hi branch创建了新的分支
那么,这些单独的提交是否会出现在备份分支中,或者如果他在将来压缩它们,它们也会消失?
最佳答案
这里有一个git的一般原理,可以回答您的问题:
提交是永久不变的:它们从不更改,也从不删除。
但是,有一个例外:有时它们确实会被删除。
为了得到答案,我们必须研究一个例外。
存储库中的提交可以表示为“定向非循环图”(DAG),每个提交都列出其父提交。新存储库中的第一次提交是一个“根”提交,没有父级,通常,以后的每个提交都有一个父级(“常规”提交)或两个或更多父级(“合并”提交)。因此,当您创建存储库及其初始提交时,您有一个没有父提交的提交节点和一个指向一个提交的分支标签master
:
o <-- master
如果随后添加新提交,则有两个节点;
master
指向第二个节点,第二个指向第一个节点:o<--o <-- master
请注意,提交不列出其子级。必须动态地发现它们。这里我们从
master
开始向后工作。如果我们添加一个新的分支
A
,从初始提交开始,并向该分支添加一个新的提交,它现在可能看起来像这样:o<--o <-- master
^
\--o <-- A
(请注意,根提交没有更改,因为它不必更改:最新提交将根列为其父提交,但根不会将最新提交列为子提交。这迫使git动态地发现分支图,但意味着提交可以永远保持不变。)
如果承诺永远不会改变,那么您应该问:什么会改变?显然,可以添加新的提交。为了能够找到这些新的提交,还必须更改其他内容,其他内容就是分支标签。
分支标签移动
每当您向存储库添加新的提交时,当前分支的标签(即
HEAD
告诉git您“on”的分支的标签);如果且仅当master
表示您在分支上时(在HEAD
目录中有一个名为HEAD
的实际文件),则“on branch.git
”会自动移动以指向新的提交。因此:o--o <-- master
\
o <-- HEAD=A
(同一张图,我只是不再尝试键入箭头,我添加了这样一个想法,即
HEAD
表示“on branchA
”),当您进行新的提交时,它会进入HEAD
表示的位置,而branch labelA
会移动:o--o <-- master
\
o--o <-- HEAD=A
添加更多提交时,分支标签也会继续移动:
o--o <-- master
\
o--o--o--o--o <-- HEAD=A
如果添加“合并”提交,分支标签仍会向前移动,但只有
HEAD
表示移动:o--o <-- master
\ `-----------.
o--o--o--o--o--o <-- HEAD=A
这里
master
仍然指向同一个旧提交;我们刚刚将它合并到A
中。有些步骤是复制的
当您
rebase
分支时,git会复制旧提交。假设我们有一个新的不同的回购协议,如下所示:A--B <-- master
\
C--D--E <-- HEAD=branch
(这次我使用了字母标签,而不是提交节点的
o
字符)。假设您在git rebase -i master
中执行branch
以“移动”提交链,使其“关闭”commitB
,而不是commitA
。在这种情况下,git所做的是复制提交C
、D
和E
。让我们调用C
、C'
的副本,依此类推。旧的承诺仍然存在,因为它们是不变的,而且(几乎)永远:
A--B <-- master
| \
\ C'-D'-E' <-- HEAD=branch
|
C--D--E [no label: "abandoned"]
但是,和往常一样,git移动分支标签以指向副本上新的最新提交(“tip”提交)。
旧的提交链仍然存在;它只是不再有标签。
这使得链符合“垃圾收集”的条件。
未标记(未引用)的提交最终会被垃圾收集
“unreferenced”提交是一种只能由
git fsck
之类的东西找到的提交,它扫描整个存储库以找到其中的所有内容。当没有分支或标记标签时,仍然可能存在git所称的“reflog s”引用,但reflog条目将过期(默认情况下,根据各种配置设置,在30到90天内)。因此,大约一个月后,那些曾经“在分支上”但已被放弃的提交,将垃圾收集起来。(命令
git gc
进行收集;默认情况下,其他各种git命令将根据需要自动调用此命令。)不过,在收集它们之前的任何时候,都可以添加对旧分支尖端的引用并阻止此收集。这包括在移动“常用”分支标签之前执行此操作。
因此,简短的回答是“是的,他们将在备份分支中。”
即使您没有事先创建备份分支,如果您以前有提交,您可能仍然在reflogs中有提交,您可以使用
git reflog
找到它们(尝试git reflog branch
和git reflog --all
以及普通git reflog
)。然后,您可以给它们附加一个标签,使它们比默认的重新登录过期时间更长:$ git reflog branch
222c4dd branch@{0}: reset: moving to origin/branch
9c0d6ac branch@{1}: commit: adjust file foo for stuff
222c4dd branch@{2}: reset: moving to origin/branch
fb45c22 branch@{3}: reset: moving to HEAD^
222c4dd
$ git log --oneline 9c0d6ac
[snip - let's say I decide that's the one I want]
$ git branch resurrect 9c0d6ac
旧的提交现在是“复活的”(对“常规”git命令可见,而不仅仅是
git reflog
或git log --walk-reflogs
)。
关于git - 压缩提交是否也会从其他分支中删除单个提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21247190/