git reflog expire和git fsck --unreachable

Geo*_*let 18 git reachability reflog

免责声明:这个问题纯粹是信息性的,并不代表我遇到的实际问题.我只是想弄清楚它的东西(因为我喜欢弄清楚东西,我知道你也这样做).

所以我正在玩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
Run Code Online (Sandbox Code Playgroud)

这意味着我做了两次提交(da8534a5a1e68a),然后是ff576c1我修改过的第三次提交4eea1cd.

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

* 4eea1cd (HEAD, master) amend commit
* 5a1e68a test: foo
* da8534a initial commit
Run Code Online (Sandbox Code Playgroud)

从我(虽然我)知道提交的可达性,有一天(最有可能,默认情况下在30天内)git gc应该收集ff576c1.现在我不想等待30天才能看到这种情况,所以我开始运行一些命令,首先:

git fsck --unreachable --no-reflogs
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,这让我:

unreachable blob 5716ca5987cbf97d6bb54920bea6adde242d87e6
unreachable tree 1e60e555e3500075d00085e4c1720030e077b6c8
unreachable commit ff576c1b4b6df57ba1c20afabd718c93dacf2fc6
Run Code Online (Sandbox Code Playgroud)

所有人都相信我将要过期这种可怜的孤独ff576c1承诺,然后我会跑git reflog expire:

git reflog expire --dry-run --expire-unreachable=now --all
Run Code Online (Sandbox Code Playgroud)

哪个,那个时候,给了我:

would prune commit: test: bar
would prune commit (amend): amend commit
Run Code Online (Sandbox Code Playgroud)

起初我虽然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
Run Code Online (Sandbox Code Playgroud)

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

would prune commit: test: bar
Run Code Online (Sandbox Code Playgroud)

我仍然不明白,因为根据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.
Run Code Online (Sandbox Code Playgroud)

在我的情况下这没有意义.好吧,至少我没有得到它,因为obvisouly它确实改变了一些东西.

Ric*_*sen 11

这种行为来自reflog设计理念与垃圾收集要求之间的相互作用.

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

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

这种设计易于实现,并导致不完整但准确的日志.

--rewrite选项

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

  • 日志中留有间隙
  • 与仍然可到达的提交相关的有用信息将丢失

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

  • 和以前一样,删除由更改后的SHA1识别的提交无法访问的条目.
  • 修改了无法访问更改前提交的条目以桥接已删除条目留下的间隙(更改前的SHA1设置为上一个条目的更改后SHA1的值).

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