man手册中说log命令显示提交日志,而reflog命令则管理reflog信息。那么,什么是reflog信息?相比之下,它与log命令有何不同?log命令似乎更加详细。
man手册中说log命令显示提交日志,而reflog命令则管理reflog信息。那么,什么是reflog信息?相比之下,它与log命令有何不同?log命令似乎更加详细。
git log
显示当前的 HEAD 及其祖先。也就是说,它会打印出 HEAD 指向的提交,然后是它的父级,再然后是它的父级,以此类推。它通过递归查找每个提交的父级来遍历整个仓库的祖先。
(实际上,有些提交有多个父级。要查看更具代表性的日志,请使用类似 git log --oneline --graph --decorate
的命令。)
git reflog
根本不遍历 HEAD 的祖先。reflog 是 HEAD 所指向的提交的有序列表:它是您仓库的撤消历史记录。reflog 不是仓库本身的一部分(它存储在与提交本身不同的地方),不包括在 push、fetch 或 clone 中;它完全是本地的。
另外:了解 reflog 就意味着一旦提交,您就不会真正丢失仓库中的数据。如果您意外地重置到旧的提交,或者错误地进行了 rebase,或者任何其他可视化“删除”提交的操作,您可以使用 reflog 查看之前的位置,并使用 git reset --hard
返回到该引用以恢复先前的状态。请记住,引用不仅意味着提交,还包括背后的整个历史。
git log
显示可以从引用(头、标签、远程)访问的提交日志。git reflog
是您的存储库中在任何时间引用或引用过的所有提交的记录。这就是为什么在执行“破坏性”操作(如删除分支)时使用 git reflog
(默认情况下在 90 天后修剪的本地记录),以便获取被该分支引用的 SHA1。
请参阅 git config
:
gc.reflogexpire
gc.<pattern>.reflogexpire
git reflog expire
会删除早于此时间的reflog条目;默认为90天。
在"<pattern>
"(例如"refs/stash
")中间,该设置仅适用于与<pattern>
匹配的引用。
git reflog
通常被称为“你的安全网”
如果遇到问题,当git log
无法显示您要查找的内容时,一般建议是:
再次强调,reflog 是对于你的 SHA1 的本地记录。
与 git log
相对应:如果你将你的 repo 推送到一个upstream repo中,你将会看到相同的git log
,但不一定是相同的git reflog
。
reflog
的解释:
One of the things Git does in the background while you’re working away is keep a reflog — a log of where your HEAD and branch references have been for the last few months.
You can see your reflog by using
git reflog
:
$ git reflog 734713b... HEAD@{0}: commit: fixed refs handling, added gc auto, updated d921970... HEAD@{1}: merge phedders/rdocs: Merge made by recursive. 1c002dd... HEAD@{2}: commit: added some blame and merge stuff 1c36188... HEAD@{3}: rebase -i (squash): updating HEAD 95df984... HEAD@{4}: commit: # This is a combination of two commits. 1c36188... HEAD@{5}: rebase -i (squash): updating HEAD 7e05da5... HEAD@{6}: rebase -i (pick): updating HEAD
Every time your branch tip is updated for any reason, Git stores that information for you in this temporary history. And you can specify older commits with this data, as well.
reflog
命令还可以用于删除过时的条目或过期的 reflog 条目。来自 官方 Linux 内核 Git 文档 reflog
:
子命令
expire
用于修剪旧的 reflog 条目。要从 reflog 中删除单个条目,请使用子命令
delete
并指定确切的条目(例如git reflog delete master@{2}
)。
git log
不是提供了相同的信息吗?如果这显而易见,那我很抱歉,因为我对GIT非常陌生,希望在我的第一个OMG之前能够掌握一些基础知识。 - NoichHEAD
指针)以及它们所指向的提交记录。明白了吗?另外,log
命令也可以显示引用日志信息,但需要将--walk-reflogs
特殊选项标志作为参数传递给它。 - user456814我也对此很好奇,以下进行详细说明和总结:
git log
显示了你所在分支的所有提交历史记录。切换到其他分支,你将看到不同的提交历史记录。如果要查看所有分支的提交历史记录,请输入 git log --all
。
git reflog
显示了你的引用记录,正如 Cupcake 所说。每次提交或执行检出操作时都会有一个记录条目。使用 git checkout
在两个分支之间多次切换几次,然后在每个检出操作后运行 git reflog
。你将看到顶部的条目每次都更新为“checkout”条目。这些类型的条目在 git log
中是不可见的。
参考文献: http://www.lornajane.net/posts/2014/git-log-all-branches
我喜欢将git log和reflog之间的区别看作是私人记录和公共记录之间的区别。
使用git reflog,它会跟踪你在本地所做的所有事情。你提交了吗?Reflog会跟踪它。你进行了硬重置吗?Reflog会跟踪它。你修改了一个提交吗?Reflog会跟踪它。你在本地所做的一切,都有一个reflog条目。
但这对于日志来说并不是真的。如果你修改了一个提交,日志只显示新提交。如果你重置并回退了历史记录中的几个提交,那些被跳过的提交不会出现在日志中。当你将更改推送给另一个开发者或者GitHub之类的东西时,只有日志中跟踪的内容才会出现。对于另一个开发者来说,看起来好像重置从未发生过或修改从未发生过。
所以,是的,我喜欢“私人vs公共”这个比喻。或者也许一个更好的日志vs reflog比喻是“精细vs镶嵌”。Reflog显示了你所有的尝试和错误。日志只显示了你工作历史的干净而精细的版本。
看看这张图片以强调这一点。自仓库初始化以来已经进行了许多修改和重置。Reflog显示了所有内容。但是日志命令使其看起来好像只有一个提交与仓库相关:
另外,由于reflog跟踪了你修改和重置的提交,它允许你回到过去并找到那些提交,因为它会给出提交ID。假设你的存储库没有清除旧提交,这就允许你恢复在日志中不再可见的项目。这就是为什么当有人需要找回他们认为意外丢失的东西时,reflog有时会挽救某人的皮肤。
git log
会从当前HEAD开始,即指向某个分支(如master)或直接指向提交对象(sha代码),并将实际扫描.git/objects目录中每个提交对象内存在的parent字段,逐个提交地进行检查。
实验:将HEAD直接指向某个提交:git checkout a721d
(创建新仓库并用提交和分支填充。将a721d
替换为您的提交代码),然后删除分支rm .git/refs/heads/*
。
现在git log --oneline
将只显示HEAD及其提交的祖先。
另一方面,git reflog
使用的是在.git/logs中创建的直接日志。
实验:rm -rf .git/logs
,然后git reflog
为空。
无论如何,即使您失去了所有标签、所有分支和日志文件夹内的所有日志,提交对象仍在.git/objects目录中,因此如果找到所有悬挂提交,可以重建树:git fsck
。
实际上,reflog是一个别名
git log -g --abbrev-commit --pretty=oneline
所以答案应该是:这是一个特定的情况。
git log
命令中,-g
是--walk-reflogs
的缩写形式。这并没有解释任何内容。 - Adrian W
.git/logs/refs/<branch>
条目的格式为<old_rev> <new_rev> [...] <timestamp> [...]
。你可以尝试将它们连接起来并按时间戳排序。然而,有些行的new_rev
可能与下一行的old_rev
不匹配,在这种情况下,我怀疑引用日志将无效。然后,你可以尝试插入虚假条目来“修复”序列,但我觉得这太麻烦了。 - mcmlxxxvi