【问题标题】:git reflog expire and git fsck --unreachablegit reflog expire 和 git fsck --unreachable
【发布时间】:2012-02-07 21:36:40
【问题描述】:

免责声明:此问题仅供参考,并不代表我遇到的实际问题。我只是想弄清楚一些东西(因为我喜欢搞清楚,我知道你也喜欢)。

所以我在玩 git,试图使修改后的提交过期。我的 reflog 看起来像这样:

4eea1cd HEAD@{0}: commit (amend): amend commit
ff576c1 HEAD@{1}: commit: test: bar
5a1e68a HEAD@{2}: commit: test: foo
da8534a HEAD@{3}: commit (initial): initial commit

这意味着我做了两次提交(da8534a5a1e68a),然后是第三次提交 ff576c1,我用 4eea1cd 进行了修改。

正如预期的那样,我的git log 看起来像这样:

* 4eea1cd (HEAD, master) amend commit
* 5a1e68a test: foo
* da8534a initial commit

根据我(尽管我)对提交的过期性的了解,某天(很可能,默认为 30 天)git gc 应该收集到ff576c1。现在我不想等待 30 天才能看到这种情况发生,所以我开始运行一些命令,首先:

git fsck --unreachable --no-reflogs

正如预期的那样,这又给了我:

unreachable blob 5716ca5987cbf97d6bb54920bea6adde242d87e6
unreachable tree 1e60e555e3500075d00085e4c1720030e077b6c8
unreachable commit ff576c1b4b6df57ba1c20afabd718c93dacf2fc6

所有人都确信我将结束那个可怜的孤独ff576c1 提交,然后我运行git reflog expire

git reflog expire --dry-run --expire-unreachable=now --all

那个时候,给了我:

would prune commit: test: bar
would prune commit (amend): amend commit

起初我虽然我的HEAD 没有引用master,但正如您在我之前给出的git log 输出中看到的那样,它确实如此。此外,cat .git/HEAD 证实了这一点(大喊 ref: refs/heads/master)。无论如何,尽管这很愚蠢,因为4eea1cd 是我的master 分支的负责人。

所以我在这里,很困惑这两个命令不会给我相同的提交,并且想知道 4eea1cd 怎么可能无法访问,因为它是我的 master 分支的实际提示。

知道发生了什么吗?

编辑:我刚刚注意到如果我将--rewrite 选项添加到git reflog expire,就像这样:

git reflog expire --dry-run --expire-unreachable=now --all --rewrite

然后我只得到修改后的提交:

would prune commit: test: bar

我还是不明白,因为根据git help reflog

   --rewrite
       While expiring or deleting, adjust each reflog entry to ensure that
       the old sha1 field points to the new sha1 field of the previous
       entry.

这对我来说没有意义。好吧,至少我不明白,因为显然它确实改变了一些东西。

【问题讨论】:

    标签: git reachability reflog


    【解决方案1】:

    这种行为来自于 reflog 设计理念和垃圾收集需求之间的交互。

    要让垃圾收集器安全删除提交,必须删除对该提交的所有引用——包括 reflog 条目中的引用。尽管reflog show 的出现,每个reflog 条目实际上包含两个SHA1 标识符:更改前的ref 的值和更改后的ref 的值。为确保安全的垃圾回收,reflog expire 只需删除两个 SHA1 之一标识无法访问的提交的任何条目。

    在您的情况下,最新 reflog 条目的更改前值是指无法访问的提交。即使更改后值标识的提交仍然可以访问,reflog expire 也会删除该条目。

    这种设计实现起来很简单,并且会产生不完整但准确的日志。

    --rewrite 选项

    不幸的是,删除引用仍然可访问的提交的条目有几个问题:

    • 日志中留有空隙
    • 与仍然可访问的提交相关的有用信息丢失

    --rewrite 选项通过以下方式更改行为来解决这些问题:

    • 与以前一样,由更改后 SHA1 标识的提交无法访问的条目将被删除。
    • 修改前更改提交无法访问的条目以弥补已删除条目留下的空白(更改前 SHA1 设置为前一个条目的更改后 SHA1 的值)。

    不幸的是,修改条目会导致日志不再准确反映 ref 的历史记录。例如,更改原因可能在重写后不再有意义。这就是为什么--rewrite 不是默认值的原因。

    【讨论】:

    • 哦,我明白了,现在一切都说得通了。谢谢。
    猜你喜欢
    • 2021-05-29
    • 1970-01-01
    • 2016-08-05
    • 2020-08-16
    • 2013-03-06
    相关资源
    最近更新 更多