git - 压缩提交是否也会从其他分支中删除单个提交

标签 git version-control

假设我有两个分支Amaster
现在在A分支我有这些承诺
abcde5 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所做的是复制提交CDE。让我们调用CC'的副本,依此类推。
旧的承诺仍然存在,因为它们是不变的,而且(几乎)永远:
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 branchgit 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 refloggit log --walk-reflogs)。

关于git - 压缩提交是否也会从其他分支中删除单个提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21247190/

相关文章:

git checkout git gui 中文件的修订版

git子模块foreach不工作

git - 在 Git 分支中保留特定文件的不同内容

version-control - 组织一个使用多种语言的项目?

git - 将 10000 个小文本文件放入代码库,会使 git 变慢吗?

Git rebase 可能的错误

git - 使用文件扩展名过滤 `git show <commitId>` 结果

git - 不能同时创建本地和远程分支(跟踪)

git - .gitignore 无法忽略以前未缓存的文件

Git 推送失败(LFS 上传丢失的对象)