如何找到新的强制推送提交 ID 涵盖的预提交 ID?
How to find pre-commit id covered by a new forced push commit id?
我将我的代码更改添加到 repo,我可以通过 git log -n1
查看提交 ID。
然后我使用 git add -u; git commit --amend; git push -f
.
将新更改组合到预提交 ID
然后我突然忘记了第二次更改的区别是什么。但是预提交 ID 在 git log
历史记录中消失了。
如何找到丢失的提交?
TL;DR: 使用 reflogs。
长
git commit --amend
操作具有“将旧提交推到一边”的效果。如果我们根据分支名称绘制提交,我们会得到这样的图片:
... <-F <-G <-H <--branch
这里的每个大写字母代表一个 Git 提交哈希 ID。 分支名称,在本例中为 branch
,保存 最新 提交 H
的哈希 ID,因此:
git rev-parse branch
打印出这个哈希 ID。 Git 能够使用此存储的哈希 ID 从提交数据库中读取提交 H
。
提交 H
本身在其元数据中存储了早期提交 G
的原始哈希 ID。因此,从数据库中读取 H
后,Git 可以找出此哈希 ID,并使用它从数据库中检索提交 G
。
检索到 G
后,Git 具有来自 G
的元数据,它给出了早期提交 F
的哈希 ID,因此 Git 可以检索从数据库提交 F
。这当然有元数据,包括另一个更早提交的哈希 ID,等等。
当我们以正常方式添加 new 提交时,Git 所做的是:
- 为新提交写一个新快照(我们将使用字母表中的下一个字母称这个新提交为
I
)。
- 写出提交
I
的元数据:我们的姓名、电子邮件地址、当前日期和时间等等。在此元数据中,Git 包含 当前 提交 H
的哈希 ID,作为提交 I
. 的父级
- 使用
git commit-tree
的内部版本将所有这些作为新提交写入对象数据库。写入提交的行为会产生新的哈希 ID:我们称之为 I
.
- 将提交
I
的哈希 ID 存储在 当前分支名称 .
第 4 步导致 branch
指向新提交 I
,而不是现有提交 H
。当我们绘制结果时,我们有:
... <-F <-G <-H <-I <--branch
如您所见,从末尾开始并向后工作的过程现在将找到提交 I
,然后提交 H
,然后提交 G
,依此类推.
git commit --amend
所做的是 绕过 当前提交 通过让新提交 I
直接返回到当前提交的 parent(s)。在这种情况下,由于 H
指向 G
,Git 将使新提交 I
直接指向 G
:
H
/
... <-F <-G <-I <--branch
提交 H
是否仍然存在,无论如何有一段时间了。但是找不到它的哈希 ID。如果它仍在您的屏幕上,或者在 window 中回滚,您可以这样获取它:Git 需要 哈希 ID;分支名称只是提供哈希 ID 的一种方式。如果您可以剪切并粘贴哈希 ID,那就没问题了。
但是上面的 reflog 这个词的意思是这样的。每当 Git 替换 存储在分支名称或特殊名称 HEAD
中的值时,Git 保存以前的值 在日志中。 此日志是可选的,但它默认为您的存储库“打开”(至少如果您使用常规 Git;如果您使用 Eclipse 或 JGit 或其他一些仅使用相同数据库格式的非 Git 程序)。所以当 git commit
和 git commit --amend
都覆盖存储在分支名称中的哈希 ID 时,它们会在日志中保存 以前的 哈希 ID。
没有参数的 运行 git reflog
将转储 HEAD
的引用日志。这是最活跃的 reflog,里面有最多的“东西”,所以它有更多的信息需要筛选。
运行 git reflog branch
,如果您在名为 branch
的分支上,则转储 branch
的 reflog。 (如果您使用 main
或 master
,请使用 git reflog main
或 git reflog master
。)这将显示对该分支名称的更新。
在这两种情况下,您都可以在 git commit --amend
之前找到提交的哈希 ID。这将是被推开的提交的哈希 ID。所以你现在可以 运行:
git diff <hash> HEAD
例如比较两个提交。
还有其他方法可以使用 reflog。见 documentation for git reflog
and the documentation for writing revision ID expressions.
我将我的代码更改添加到 repo,我可以通过 git log -n1
查看提交 ID。
然后我使用 git add -u; git commit --amend; git push -f
.
将新更改组合到预提交 ID
然后我突然忘记了第二次更改的区别是什么。但是预提交 ID 在 git log
历史记录中消失了。
如何找到丢失的提交?
TL;DR: 使用 reflogs。
长
git commit --amend
操作具有“将旧提交推到一边”的效果。如果我们根据分支名称绘制提交,我们会得到这样的图片:
... <-F <-G <-H <--branch
这里的每个大写字母代表一个 Git 提交哈希 ID。 分支名称,在本例中为 branch
,保存 最新 提交 H
的哈希 ID,因此:
git rev-parse branch
打印出这个哈希 ID。 Git 能够使用此存储的哈希 ID 从提交数据库中读取提交 H
。
提交 H
本身在其元数据中存储了早期提交 G
的原始哈希 ID。因此,从数据库中读取 H
后,Git 可以找出此哈希 ID,并使用它从数据库中检索提交 G
。
检索到 G
后,Git 具有来自 G
的元数据,它给出了早期提交 F
的哈希 ID,因此 Git 可以检索从数据库提交 F
。这当然有元数据,包括另一个更早提交的哈希 ID,等等。
当我们以正常方式添加 new 提交时,Git 所做的是:
- 为新提交写一个新快照(我们将使用字母表中的下一个字母称这个新提交为
I
)。 - 写出提交
I
的元数据:我们的姓名、电子邮件地址、当前日期和时间等等。在此元数据中,Git 包含 当前 提交H
的哈希 ID,作为提交I
. 的父级
- 使用
git commit-tree
的内部版本将所有这些作为新提交写入对象数据库。写入提交的行为会产生新的哈希 ID:我们称之为I
. - 将提交
I
的哈希 ID 存储在 当前分支名称 .
第 4 步导致 branch
指向新提交 I
,而不是现有提交 H
。当我们绘制结果时,我们有:
... <-F <-G <-H <-I <--branch
如您所见,从末尾开始并向后工作的过程现在将找到提交 I
,然后提交 H
,然后提交 G
,依此类推.
git commit --amend
所做的是 绕过 当前提交 通过让新提交 I
直接返回到当前提交的 parent(s)。在这种情况下,由于 H
指向 G
,Git 将使新提交 I
直接指向 G
:
H
/
... <-F <-G <-I <--branch
提交 H
是否仍然存在,无论如何有一段时间了。但是找不到它的哈希 ID。如果它仍在您的屏幕上,或者在 window 中回滚,您可以这样获取它:Git 需要 哈希 ID;分支名称只是提供哈希 ID 的一种方式。如果您可以剪切并粘贴哈希 ID,那就没问题了。
但是上面的 reflog 这个词的意思是这样的。每当 Git 替换 存储在分支名称或特殊名称 HEAD
中的值时,Git 保存以前的值 在日志中。 此日志是可选的,但它默认为您的存储库“打开”(至少如果您使用常规 Git;如果您使用 Eclipse 或 JGit 或其他一些仅使用相同数据库格式的非 Git 程序)。所以当 git commit
和 git commit --amend
都覆盖存储在分支名称中的哈希 ID 时,它们会在日志中保存 以前的 哈希 ID。
运行 git reflog
将转储 HEAD
的引用日志。这是最活跃的 reflog,里面有最多的“东西”,所以它有更多的信息需要筛选。
运行 git reflog branch
,如果您在名为 branch
的分支上,则转储 branch
的 reflog。 (如果您使用 main
或 master
,请使用 git reflog main
或 git reflog master
。)这将显示对该分支名称的更新。
在这两种情况下,您都可以在 git commit --amend
之前找到提交的哈希 ID。这将是被推开的提交的哈希 ID。所以你现在可以 运行:
git diff <hash> HEAD
例如比较两个提交。
还有其他方法可以使用 reflog。见 documentation for git reflog
and the documentation for writing revision ID expressions.