3

如何确定是什么阻止了通过以下命令从 git 中删除提交?

git reflog expire --expire=now --all

git gc --prune=now

细节

我想XYZ从我的克隆中完全删除一个提交(例如,使用 commit hash )。如果以上不是正确的命令(或者我的以下命令/推论中的任何一个不正确),请告诉我。

我知道XYZ在运行上述 prune 之后它仍然在我的克隆中,因为以下返回一个日志列表:

git log XYZ

我知道这XYZ不在任何分支中,因为以下内容不输出任何内容:

git branch --contains XYZ

我认为这XYZ不在任何藏匿处,因为以下内容不输出任何内容:

git stash list

XYZ,然而,实际上是在一个藏匿处,但一个 git 错误阻止了藏匿处被列出。

4

1 回答 1

8

如果没有存储并且您已经过期了 reflog,那么假设可以从某些 ref 访问提交似乎是合理的——但并非所有 ref 都是分支。

你可以试试这个:

git for-each-ref --format='%(refname)' |xargs -I {} git rev-list {} --format="%H {}" |grep ^<hash>

<hash>您要摆脱的提交的 ID 在哪里。在一个简单的测试中,我跑了

git for-each-ref --format='%(refname)' |xargs -I {} git rev-list {} --format="%H {}" |grep ^80c0ab

并得到像

80c0ab39850d7b3ef4969ab934d834f22959a317 refs/original/refs/heads/master

告诉我,我的目标提交由下面的 ref 保持活动状态refs/original- 在这种情况下,由git filter-branch


更新- 基于评论的一些后续行动。

您注意到上面的命令返回refs/stash,但存储列表 (per git stash list) 是空的。

问题是,存储列表使用了经过大量操作的 reflog。还有你用来清除 reflogs 的命令

git reflog expire --expire=now --all

将破坏密钥 reflog。所以现在stash命令不知道该做什么并且表现得好像没有存储,但是stashref 仍然存在,保留最新存储中的任何内容(或从创建该存储的提交可访问的完整提交历史)在当地活着[1]。

IMO 可以被认为是一个错误。默认情况下,计划的 reflog 到期不作任何stash处理(因为……嗯……这个原因)。也许您的论点是您特别说过要使所有reflogs 过期,但我认为“除 the 之外的所有 reflogs ”在这种情况下stash将是一个更有用的定义。--all

好吧,随便。

如果你确定你不关心被藏起来的东西

git update-ref -d refs/stash

然后继续你的清理工作。


[1] “本地活动”,因为至少默认情况下stash不共享。克隆 repo 或将其 refs 推送到空的遥控器中,很可能不会携带有问题的提交。但是,这取决于 git 将发送最小包的假设 - 并且 AFAIK 不能保证这样做。因此,如果您需要提交消失,那么最安全的做法是达到它在本地不存在的点,然后从该干净的本地 repo 重建任何遥控器(等)。

于 2018-09-05T17:34:49.153 回答