这个问题存在一些问题,也许这就是它被否决的原因,但我们可以从中有所作为。
让我们看一下在 git fetch 之前和之后绘制成图形的 Git 存储库中实际存储的内容,以了解我的意思。
我们将从这个开始:
A <-- master
/
...--o--* <-- origin/master
\
B--C <-- origin/dev
在这里,在本地存储库中,在运行 git fetch origin 之前,我们有:
- 一些共享提交,从提交
* 开始并向后工作;
- 一个“我们的”提交,提交
A,在我们的master,不在origin/master
- 两个提交是上游唯一的,在他们的
dev 这是我们的origin/dev:提交B 和C。
现在我们运行git fetch,它会打印一些输出,由于某种原因我们没有看到或忘记了这些输出。然后我们再次仔细检查我们的图表并发现这一点:
A <-- master
/
...--o--*--D <-- origin/master
\
E <-- origin/dev
也就是说,我标记为B 和C 的两个提交根本无法从任何origin/* 名称访问,而新的提交D 和E 已经出现。名称origin/master,这是我们Git 对其master 的记忆,现在标识提交D,而名称origin/dev 标识提交E。
很有可能——但从这种失忆的观点中无法确定——提交D 是压缩提交B 和C 的结果,可能还有一些我们从未有过的额外提交。提交E 可能是全新的。另一方面,我们只是不知道。
不过,我们可能有比这更多的信息。特别是,如果我们启用了 reflogs,我们将拥有 origin/master@{1} 和 origin/dev@{1}。这些将分别指向提交* 和C,我们将通过origin/master@{1} reflog 保留C 和B。
我们也可能有不同的起始画面。例如,也许我们的起始图像看起来像这样:
A <-- master
/
...--o--* <-- origin/master
\
B--C <-- dev, origin/dev
在这种情况下,我们的结束图片如下所示:
A <-- master
/
...--o--*--D <-- origin/master
\ \
\ E <-- origin/dev
\
B--C <-- dev
知道什么
这里有几点需要注意:
- 我们永远不会丢失我们自己的分支名称指向的任何提交。
- 我们从不更新我们自己的任何分支名称。
- 我们确实会更新我们的远程跟踪名称,但是当我们这样做时,如果启用了 reflog,它们的 previous 值会保存在这些名称的 reflog 中。
因此:
我想确保不会通过从远程存储库获取任何提交从我的本地存储库中删除(或压缩)。
这是自动的,如果“无提交”是指“除了远程跟踪名称之外,我没有其他名称的提交”。
我还需要告诉我,是否有任何提交在远程存储库中被删除(或压缩)。
在这里,您可以查看任何更新的远程跟踪名称(请注意,git fetch 告诉您它正在更新哪些名称)与其保存的 reflog 值之间的区别。例如,如果 origin/master 和 origin/dev 已更新,您可以将 origin/master@{1} 与 origin/master 进行比较。
此时,the gitrevisions documentation 中描述的几个特殊的syntaxes 就变得相当得心应手了。特别是两点和三点集差分和对称差分运算符告诉我们我们想知道的内容:
git rev-list origin/master@{1}..origin/master
生成提交列表添加到 origin/master,并且:
git rev-list origin/master..origin/master@{1}
生成提交列表从 origin/master 中删除。我们的存储库中仍然有所有这些提交,因为 reflog 名称指向它们;在 reflog 条目过期之前,它们不会消失。
我们可以将三点语法与--left-right 或类似实体一起使用,来枚举和识别添加和删除的提交,标记它们位于对称差异的哪一侧:
git rev-list --left-right origin/master@{1}...origin/master
使用所有这些信息,如果我们真的在乎,我们可以自动猜测哪些提交可能是其他提交的变基或压缩,但在某些情况下这是注定要失败的(例如,解决了合并冲突)。
另一个相关问题:如何让Git删除对应已删除远程提交的本地提交?
这更棘手,因为它取决于您的意思。然而,如果你的意思是我猜你的意思,git rebase 的--fork-point 操作实际上就是为了处理这个问题而设计的。 fork-point 代码使用上游分支的 reflog。详情请见Git rebase - commit select in fork-point mode。