【问题标题】:Where are the git stash elements stored? Is the data structure really a stack?git stash 元素存储在哪里?数据结构真的是堆栈吗?
【发布时间】:2017-03-17 17:03:08
【问题描述】:

为了更好地理解 git stash,我想知道: git stash 的元素存储在哪里以及在什么数据结构中?在堆栈中?在有序集合中?


详情:

每个文档、文章和书籍(Git Internals 除外)都说 git stash 是一个堆栈

最近,我发现您可以从存储中以任意顺序检索和删除元素——这是一个非常有用的功能。由于此功能和A Hacker's Guide to Git,在我看来,存储区由按时间顺序排列的一组引用 组成。但是,在.git/refs/stash 中,仅以合并提交的形式存储了最新的 stash 元素(其中还包含创建 stash 元素的日期)。

是否有另一个 (top-secret pre-index stash-cache;) 数据结构包含所有存储元素?还是 git stash (list|pop|apply) 从其常规对象存储中检索元素?如何?

那么 stash 元素形成什么样的数据结构呢?合并提交的日期是否隐含地给出了元素的时间顺序?如果元素实际上存储在堆栈中,git如何以任意顺序检索和删除元素?

【问题讨论】:

  • 一个 stash 条目是一个由 refs stash{n} 引用的提交。在git stash的手册中可以找到一些线索。
  • 谢谢,ElpieKay。 git 在哪里内部存储 refs stash{n}?我只在 '.git/refs/stash' 中找到最新的参考资料。
  • 再次感谢 ElpieKay。我现在发现 {i} 是 reflog 语法,并且较旧的 stash 元素相应地存储在 reflog 中。我想我现在必须阅读关于 reflog 的内容.... ;)

标签: git data-structures language-agnostic


【解决方案1】:

作为ElpieKay wrote in a comment,除了当前 stash 之外的所有存储都存储在reference refs/stash 的reflog 中。请参阅the gitglossary 中“ref”和“reflog”的定义。请注意,像 masterdevelop 这样的分支名称是一种引用,分别是全名 refs/heads/masterrefs/heads/develop 的缩写。标签名称是另一种参考;标签v2.2 确实是引用refs/tags/v2.2

大多数引用都以refs/ 为前缀。事实上,各种 HEAD——HEAD 本身,以及 MERGE_HEADCHERRY_PICK_HEADORIG_HEAD 等等——是唯一的例外,而大多数 那些 并不 reflogs。 HEAD 是唯一一个这样做的。

通常,reflog 条目只是线性编号:HEAD@{1}master@{1} 是“HEADmaster 在其最近更新之前指向的提交”,master@{2} 是两步前的提交, 等等。这在gitrevisions 中有描述。为方便起见,current 值可以用@{0} 引用:master@{0}master 始终解析为相同的哈希 ID。如果refs/stash 引用的使用方式与其他引用相同,那么它将作为队列而不是堆栈工作——但它不是使用那样的。相反,git stash 代码明确删除早期条目。

由于编号始终是连续的,删除一个条目会导致所有更高的数字下降一个。例如,如果您手动删除master@{5},那么以前的master@{6} 现在是master@{5},以前的master@{7} 现在是master@{6},以此类推。

当然,添加一个新条目会将所有内容都提升一个。因此,当您创建一个新的存储时,以前是 stash 又名 stash@{0} 现在是 stash@{1}。以前是stash@{1},现在是stash@{2},以此类推。对于其他 reflog,例如 master,没有人称其为“推送”,它只是普通的队列在行动。

一旦你删除 stash@{0} aka stash,所有更高的条目——stash@{1}stash@{2} 等等——都会下降一个,所以现在stash已被“弹出”,之前的 stash@{1} 只是 stash。当然,您也可以git stash drop stash@{4} 删除该特定条目,保留 0 到 3 并重新编号 5 及以上。请注意,任何特定存储的git stash pop 仅表示“应用,如果似乎成功,则放弃”。

请注意,并非完全是偶然的,每个 reflog 条目附有一个时间戳。您可以编写 master@{yesterday}master@{3.hours.ago},Git 将根据时间戳找到相应 reflog 条目的哈希 ID。1 因为存储标识符只是 reflog 条目,所以相同的语法在那里有效. (我从来没有真正发现这一切在任何地方都有用,也许是因为我在工作时没有时间感,不记得现在是一周中的哪一天现在,更不用说我之前做某事的时候了. :-) ) 使用这些时间戳,大多数 reflogs expire:默认情况下,旧的reflog 条目将在 90 天后消失,或者只有 30 天,如果它命名的对象从同一引用的当前值中可访问2 但是,默认情况下,refs/stash 本身不受此到期限制。所有这些都是可配置的:查看the git config documentation 中的所有gc.reflogExpire 设置。


1如果您在一天内多次更新引用但每小时不超过一次,@{yesterday} 表示@{24.hours.ago}。如果您每小时更新一次以上,请再乘以 60:@{1440.minutes.ago}。如果您每分钟更新一次以上,请再次乘以 60:@{86400.seconds.ago}。分辨率没有比这更好的了。

2这就是 Git 如何保留 30 天,但最终会清除,例如被 git rebase 放弃的旧提交。 可达性 是由存储库中的标签、提交和树对象形成的有向无环图或 DAG 提供的一个关键概念。 (Blob DAG 中,但没有参与扩展它,因为它们始终是叶节点。因此,blob 本身可能是可访问的或不可访问的,但它不会影响任何 其他 对象。)

【讨论】:

    猜你喜欢
    • 2014-04-21
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 1970-01-01
    • 2013-03-04
    • 2011-09-29
    • 2015-11-15
    相关资源
    最近更新 更多