首页 > 解决方案 > 如果文件是在使用 squash 的 rebase 中添加和删除的,git 会从索引和历史记录中永久删除文件吗?

问题描述

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

标签: gitversion-controlrebase

解决方案


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

[files] 是否仍会在索引中

这不是一个明智的问题。

不过,另一部分更有用:

[文件] 还会在……历史的某个地方吗?

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

任何提交都无法更改,但您可以让 Git忘记提交。Git 通过从分支名称、标签名称和其他此类引用开始来查找提交:每个引用都包含一个哈希 ID,它是某个底层 Git 对象的一个​​哈希 ID,主要是提交对象,偶尔也会标记对象,用于带注释的标签。标记对象拥有另一个哈希 ID,通常是提交的 ID;提交对象包含额外的提交哈希 ID,这些 ID 标识了它们的前一个提交。

因此,“历史”包括从一个名字开始master,它包含一个哈希 ID:一些大而丑陋的字母和数字字符串,但我们就叫它吧H

        ... <-H   <-- master

CommitH本身包含另一个丑陋的大哈希 ID;让我们称之为G

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

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

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

等等,等等。那是历史!

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

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

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

git rebase所做的是将(一些)承诺复制到新的和改进的承诺中。假设我们变基dev为只有一个独特的,但新的和改进的提交。我们称之为一次提交I。我们只是将I的前身——commit 中的哈希 IDI让我们/Git 倒退——安排为 commit 的哈希 ID C

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

现在总共有四个提交dev

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

Git 会保留一些额外的、隐藏的日志条目(Git 称之为reflogs)一段时间,以防我们的 rebase 出现错误。虽然存在这些额外的 reflog 条目,但我们可以使用git reflog devorgit reflog HEAD来查找 commit 的哈希 ID E,并且可能也可以直接使用D。因此,reflogs 使提交保持活动状态。

Reflog 条目最终会过期。一旦过期,它们就会被删除。一旦删除,它们就不再保护提交。一旦所有的保护都消失了,提交——以及它们相关的快照——就会有资格进行垃圾收集或 GC。reflog 条目过期的默认值是 30 天和 90 天:90 天是可达条目的时间,30 天是不可达条目的时间,可达性的定义基于存储在引用中的当前哈希 ID这个特定的 reflog 存在。在您的情况下,重新调整基础dev以将所有旧提交折叠为一个新的和改进的替换,旧的提交被认为是不可达的,因此得到 30 天。

因为 Git 总是在创建对象,其中一些最终会被引用并保留下来,所以默认情况下至少 14 天的任何对象都会从垃圾收集器中幸免。垃圾收集器也不会一直运行:只要看起来 GC 有利可图, Gitgit gc --auto就会自动调用它。

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


推荐阅读