如果文件是在带有 squash 的 rebase 中添加和删除的,git 是否会从索引和历史记录中永久删除文件?

Will git permanently remove files from index and history if the files were added and removed within a rebase with squash?

有人在 develop 分支上添加了一个他们不应该添加到我们的 repo 的目录,我已经删除了这些文件。现在,如果我回去做一个变基并压缩从添加之前到添加之后的提交,是否就像文件从未添加到回购协议中一样,或者它们是否仍然在索引或历史记录中的某个地方?

索引永远不会永久存在。它主要是 临时 数据结构,Git 使用它来构建您所做的 next 提交。您可以随时使用 git addgit rm 更改它; git checkout 和类似的命令从提交中填充它。所以这部分问题:

will [files] still be in the index

这不是一个明智的问题。

不过,另一部分更有用:

will [files] still be in ... history somewhere?

Git 中的历史 提交;提交 历史记录。

任何提交都不能更改,但您可以获得 Git 到 忘记 提交。 Git 通过从分支名称、标签名称和其他此类引用开始查找提交:每个引用都恰好包含一个哈希 ID,属于某个底层 Git 对象——主要是提交对象,偶尔也有标签对象,用于带注释的标签.标记对象持有另一个哈希 ID,通常是提交的哈希 ID;提交对象包含额外的提交哈希 ID,用于标识其前身提交。

因此,"history" 包含一个像 master 这样的名称,其中包含一个哈希 ID:一些大而难看的字母和数字串,但我们就称它为 H :

        ... <-H   <-- master

提交 H 本身包含另一个丑陋的大哈希 ID;我们称它为 G:

     ... <-G <-H   <-- master

提交 G 本身包含另一个丑陋的大哈希 ID。我们称这个为 F:

... <-F <-G <-H   <-- master

等等,等等。那是历史!

要在 存储库 中查找历史记录,我们只需从所有终点开始并向后工作:

        D--E   <-- dev
       /
A--B--C
       \
        F--G--H   <-- master

Commit A 是第一个,因此它不会更早地连接到任何东西。提交 A-B-C 两个 分支上。提交 Edev 的结尾,提交 Hmaster 的结尾。通过从 E 开始并向后工作,我们访问了五个提交。通过从 H 开始并向后工作,我们访问了六个,其中三个与我们从 dev 访问的相同。所以总共有八个提交:三个共享,两个 dev 独有,三个 master.

独有

git rebase所做的是复制(一些)提交新的和改进的。假设我们将 dev 变基为只有 一个 独特但经过改进的新提交。让我们称之为一次提交 I。我们只是安排 I 的前身——提交 I 中的哈希 ID 让我们 / Git 倒退——成为提交 C:[=55= 的哈希 ID ]

        D--E   [abandoned]
       /
A--B--C--I   <-- dev
       \
        F--G--H   <-- master

现在 dev 上总共有四次提交。

提交 DE 仍然存在 。我们不能改变他们!但是我们也无法 找到 它们,因为我们通过从所有 名称 开始并向后工作来找到提交。没有名字将我们引向 E;没有名字将我们带到 D.

Git 保留一些额外的、隐藏的日志条目——在 Git 调用的 reflogs 中——保留一段时间,以防我们的 rebase 出错.虽然存在这些额外的 reflog 条目,但我们可以使用 git reflog devgit reflog HEAD 来查找提交 E 的哈希 ID,也可能直接查找 D 的哈希 ID。因此,reflogs 使提交保持活动状态。

Reflog 条目最终会过期。一旦过期,它们就会被删除。一旦删除,它们就不再保护提交。一旦 所有 保护消失,提交——及其关联的快照——将有资格进行 垃圾收集,或 GC。 reflog 条目到期的默认值为 30 天和 90 天:90 天是 reachable 条目的时间,30 天是 unreachable 条目的时间条目,reachable 的定义基于存储在引用中的当前散列 ID,该引用通过该引用存在。在您的情况下,重新设置 dev 以将所有旧提交折叠为一个新的和改进的替换,旧的被认为无法访问,因此有 30 天的时间。

因为 Git 总是在创建 new 对象,其中一些最终会被引用并保留下来,默认情况下任何未至少存在 14 天的对象都会被保留来自垃圾收集器。垃圾收集器也不会一直 运行:Git 运行s git gc --auto 自动 每当看起来像GC 将是有利可图的。

由于 30 天超过 14 天,您的旧提交将在 rebase 后 30 天后的某个时间收集。为了让它更快发生,您可以立即手动使 reflog 过期,并手动 运行 随后 git gc。但大多数情况下你应该让 Git 去做。