手动使用git reflog expire
“推送”存储的底层机制——即任何名称不只是stash 或stash@{0},而是stash@{1}、stash@{2} 等的存储——是Git 的reflogs。每当引用发生更改时,reflog 都会记录引用的先前值。 (我会在下面定义reference,并在那里完成reflog的定义。)
大多数 reflog 条目通过可配置的 gc.reflogExpire 和 gc.reflogExpireUnreachable 设置自行过期(请参阅 the git config documentation 和 the git reflog documentation)。但是,refs/stash 引用很特殊:默认情况下,它的条目永不过期,而不是在 30 或 90 天后过期。
您可以手动运行git reflog expire 并覆盖其中任何一个。例如:
git reflog expire --expire-unreachable=40.days refs/stash
告诉 Git 使至少 40 天前的任何存储条目过期,所有这些条目始终无法访问(请参阅下文了解详细信息)。将--dry-run 添加到选项中以查看哪些会过期,而实际上不会使它们过期......尽管这里有一个小缺陷:它不打印它们的数字,即它从来没有说它是去折腾,比如说stash@{17}。
引用和引用日志
Git 的references 是分支名称、标签名称、远程跟踪分支名称以及 Git 拥有的所有其他名称的概括。引用只是将名称(例如 master 或 v1.2 或 stash)转换为 Git 的内部哈希 ID 之一。
分支名称只是一个完整名称以refs/heads/开头的引用。标签名称只是一个参考,其全名以refs/tags/ 开头。远程跟踪分支名称是一个引用,其全名以refs/remotes/ 开头(然后是远程的名称和另一个斜杠)。
一些参考名称,特别是分支,经常变化。例如,您的master 分支,实际上是refs/heads/master,每次向master 添加新提交时都会更改。每当 Git 为引用替换存储的哈希值时,它可能(取决于 reflogs 是否打开)保存 previous 哈希值。这些保存的条目是您的reflogs。
每个 reflog 条目都有一个时间戳。 Reflog 条目最终会过期并过期,因此您最终不会收到数千或数百万个 reflog 条目。
可达和不可达,以及为什么它们不适用于refs/stash
分支名称通常以向前的方式移动,例如,一次提交一次。也就是说,我们将 new 提交添加到一个分支,并且该分支上的所有 old 提交仍然在该分支上。有时我们会以“快速”前进的方式一次性提取所有提交并添加它们:所有新提交都在分支上,所有旧提交也仍在分支上。分支名称指向分支上的 tip 提交,在这张图中最右边的o:
...--o--o--o <-- branch
我们添加了更多的commits,分支名依然指向tip:
...--o--o--o--o--o--o <-- branch
但由于每个提交都指向其父提交,因此所有这些提交都是可访问的。
不过,有时我们会故意删除一个提交,并用另一个提交替换它。例如,如果我们有尚未推送的提交,我们可以使用git commit --amend 或git rebase -i 进行一些更改。当我们这样做时,旧的不会消失,只是得到。相反,他们被推到一边:
...--o--o--X <-- branch
变成:
X ...... branch@{1}
/
...--o--o--Y <-- branch
其中Y 是X 的替代品。
注意Y的父提交不是X,而是X的父提交。这意味着提交X 无法从Y 访问。
两个单独的“reflogExpire”配置项,对于可访问和不可访问的对象,指的是可以从引用的当前值开始找到的提交——对于我们名为branch的分支,那是refs/heads/branch——并且向后工作。提交Y 是可达的,os 也是如此,但X 不是。如果有一个 reflog 条目指向较早的 os 之一,它是可访问的,但 branch@{1} 指向 X,这是 不可访问的。
Git 的设计者本质上认为无法访问的提交是不值得的,所以他们的 reflog 条目应该更早过期。因此,不可达条目的默认值为 30 天,可达的条目为 90 天。
但是,refs/stash 引用根本不会正常前进。相反,它指向当前的存储,这是一种侧边的袋子:一个提交——实际上至少两次提交,有时更多——不在任何分支上(我称之为“存储袋”;见How to recover from "git stash save --all"?)。反过来,这意味着 no 以前的stash@{<em>n</em>} 可以从当前的refs/stash 访问,永远!因此,每个 stash reflog 条目在任何时候都是不可访问的。