免责声明:此问题仅供参考,并不代表我遇到的实际问题。我只是想弄清楚它的东西(因为我喜欢弄清楚东西,我知道你也是这样)。
所以我正在玩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
这意味着我进行了两次提交(da8534a
和5a1e68a
),然后是我用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
确认了(yelding 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.
在我的案例中没有意义。好吧,至少我没有得到它,因为obvisouly它确实改变了一些东西。
答案 0 :(得分:11)
此行为来自reflog设计理念与垃圾收集要求之间的交互。
对于垃圾收集器安全删除的提交,必须删除对该提交的所有引用 - 包括reflog条目中的引用。尽管出现reflog show
,但每个reflog条目实际上包含两个SHA1标识符:更改前的ref值和更改后的ref值。为了确保安全的垃圾收集,reflog expire
只删除两个SHA1中的一个标识无法访问的提交的任何条目。
在您的情况下,最近的reflog条目的更改前值是指无法访问的提交。即使由更改后的值标识的提交仍可访问,reflog expire
也会删除该条目。
此设计易于实施,导致日志不完整但准确。
--rewrite
选项不幸的是,删除引用仍然可以访问的提交的条目有几个问题:
--rewrite
选项通过以下方式更改行为来解决这些问题:
不幸的是,修改条目会导致日志不再准确反映ref的历史记录。例如,重写后更改原因可能不再有意义。这就是--rewrite
不是默认值的原因。