git reflog 和 log 有啥区别?

Posted

技术标签:

【中文标题】git reflog 和 log 有啥区别?【英文标题】:What's the difference between git reflog and log?git reflog 和 log 有什么区别? 【发布时间】:2013-07-25 07:53:15 【问题描述】:

手册页说 log 显示提交日志,而 reflog 管理 reflog 信息。 reflog 信息到底是什么,日志没有什么?日志似乎要详细得多。

【问题讨论】:

【参考方案1】:

git log 显示当前的 HEAD 及其祖先。也就是说,它会打印 HEAD 指向的提交,然后打印其父级、父级等。它通过递归查找每个提交的父级来遍历 repo 的祖先。

(实际上,一些提交有多个父级。要查看更具代表性的日志,请使用git log --oneline --graph --decorate 之类的命令。)

git reflog 根本没有遍历 HEAD 的祖先。 reflog 是 HEAD 指向的提交的有序列表:它是您的 repo 的撤消历史记录。 reflog 不是 repo 本身的一部分(它与提交本身分开存储)并且不包含在推送、获取或克隆中;这纯粹是本地的。

除此之外:理解 reflog 意味着一旦提交,您就不会真正丢失 repo 中的数据。如果您不小心重置为较旧的提交,或错误地重新设置基准,或任何其他在视觉上“删除”提交的操作,您可以使用 reflog 查看您之前的位置,然后git reset --hard 回到该 ref 以恢复您之前的状态。请记住,refs 不仅意味着提交,还意味着它背后的整个历史。

【讨论】:

请注意:您有时可能会丢失数据,因为 reflog 条目不会永远存在 - 它们会在某些条件下被清除。请参阅this answer 以及git-reflog 和git-gc 的文档。一般来说,如果破坏性操作不超过 2 周前,您很可能是安全的。 @mcmlxxxvi 我有两个本地文件夹用于同一个 repo,我可以合并这两个文件夹的 reflogs 吗? @Tmx,我不太明白你的情况——你说的同一个仓库的两个本地文件夹是什么意思?如果您有两个相同 repo 的克隆,它们是最新的,并且您想“合并”它们的编辑历史记录,.git/logs/refs/<branch> 条目的格式为 <old_rev> <new_rev> [...] <timestamp> [...]。您可以尝试按时间戳连接和排序。但是,某些行的new_rev 可能与下一行的old_rev 不匹配,在这种情况下,我怀疑引用日志将无效。然后,您可以尝试插入虚假条目来“修复”序列,但这对我来说似乎太麻烦了。【参考方案2】: git log 显示可从 refs(heads、tags、remote)访问的提交日志 git reflog 是您的存储库中随时引用或曾经引用的所有提交的记录

这就是为什么在您执行“破坏性”操作(如删除分支)时使用git reflog(默认情况下在 90 天后修剪的 本地 记录),以便获得返回该分支引用的 SHA1。 见git config:

gc.reflogexpire
gc.<pattern>.reflogexpire

git reflog expire 删除早于这个时间的 reflog 条目;默认为 90 天。 在中间使用“&lt;pattern&gt;”(例如“refs/stash”)时,该设置仅适用于与&lt;pattern&gt; 匹配的引用。

git reflog 通常被称为“your safety net”

如果遇到麻烦,一般建议是:当 git log 没有显示您要查找的内容时:

Keep calm and use git reflog

同样,reflog 是您的 SHA1 的本地记录。 与git log 不同:如果你将你的repo 推送到upstream repo,你会看到相同的git log,但不一定是相同的git reflog

【讨论】:

【参考方案3】:

这是explanation of reflog from the Pro Git book:

Git 在您工作时在后台做的一件事是保留一个 reflog — 记录您的 HEAD 和分支引用在过去几个月中的位置。

你可以使用git reflog查看你的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

每当您的分支提示因任何原因而更新时,Git 都会在此临时历史记录中为您存储该信息。您也可以使用此数据指定较旧的提交。

reflog 命令也可用于从 reflog 中删除太旧的条目或使条目过期。来自official Linux Kernel Git documentation for reflog

子命令 expire 用于修剪旧的 reflog 条目。

要从 reflog 中删除单个条目,请使用子命令 delete 并指定确切的条目(例如 git reflog delete master@2)。

【讨论】:

但是git log 不是为您提供相同的信息吗?抱歉,如果这看起来很明显,我对 GIT 很陌生,想在我的第一个 OMG 之前获得一些基础知识。 Git 日志是您的提交的记录。正如 Pro Git 书所述,reflog 是您的 references(基本上是您的分支指针和您的 HEAD 指针)的记录,以及它们已经提交的指着。那有意义吗?附带说明一下,log 也可以向您显示 reflog 信息,但您必须将一个特殊的选项标志作为参数传递给它,--walk-reflogs 另外,由于您是 Git 初学者,我强烈建议您阅读 Pro Git 书籍,这是我学到的关于 Git 的大部分知识。我推荐第 1-3 章和第 6-6.5 章。我还强烈建议您学习如何以交互方式和非交互方式进行变基。【参考方案4】:

我也很好奇这个,只是想详细说明和总结一下:

    git log 显示您所在分支的所有提交的历史记录。签出一个不同的分支,你会看到不同的提交历史。如果您想查看所有分支的提交历史记录,请输入 git log --all

    git reflog 显示您的参考记录,正如 Cupcake 所说。每次提交或签出时都会有一个条目。尝试使用git checkout 在两个分支之间来回切换几次,并在每次结帐后运行git reflog。您会看到每次更新的顶部条目作为“结帐”条目。您在 git log 中看不到这些类型的条目。

参考资料: http://www.lornajane.net/posts/2014/git-log-all-branches

【讨论】:

【参考方案5】:

我喜欢将 git log 和 reflog 之间的区别视为私人记录和公共记录之间的区别。

私人与公共

使用 git reflog,它可以跟踪您在本地所做的一切。你答应了吗? Reflog 跟踪它。你做了硬重置吗? Reflog 跟踪它。你amend a commit了吗? Reflog 跟踪它。您在本地完成的所有操作,在 reflog 中都有相应的条目。

这不适用于日志。如果你修改了一个提交,日志只显示新的提交。如果您进行重置并跳过历史记录中的一些提交,那么您跳过的那些提交将不会显示在日志中。当您将更改推送给其他开发人员或GitHub 或类似的东西时,只会显示日志中跟踪的内容。对另一位开发人员来说,重置似乎从未发生过,或者修改从未发生过。

日志已打磨。 reflog 是宝石级的。

是的,我喜欢“私人与公共”的类比。或者也许更好的log vs reflog 类比是“抛光与宝石”。 reflog 显示了您所有的试验和错误。该日志仅显示您的工作历史的干净和完善的版本。

看一下这张图片以强调这一点。自存储库初始化以来,已经发生了许多修改和重置。 reflog 显示了所有这些。然而,日志命令使它看起来好像只有一次针对 repo 的提交:

回到“安全网”理念

此外,由于 reflog 会跟踪您修改的内容并提交您reset,它允许您返回并找到这些提交,因为它会为您提供提交 ID。假设您的存储库尚未清除旧提交,这允许您恢复日志中不再可见的项目。这就是当某人需要找回他们认为无意中丢失的东西时,reflog 有时最终会挽救他们的皮肤的方式。

【讨论】:

我发现这个答案最容易理解!谢谢。【参考方案6】:

git log将从当前HEAD开始,即指向某个分支(如ma​​ster)或直接提交对象(sha代码),并实际扫描.git/objects 目录中的对象文件在提交后使用每个提交对象中存在的 parent 字段提交。

实验:将 HEAD 直接指向某个提交:git checkout a721d(创建新的 repo 并用提交和分支填充它。用你的一些提交代码替换 a721d)并删除分支 rm .git/refs/heads/* 现在git log --oneline 将只显示 HEAD 及其提交祖先。

另一方面,git reflog 使用的是在 .git/logs

中创建的直接日志

实验:rm -rf .git/logsgit reflog 为空。

无论如何,即使您丢失了日志文件夹中的所有标签、所有分支和所有日志,提交对象也在 .git/objects 目录中,因此如果您发现所有悬空提交,您可以重建树:git fsck

【讨论】:

【参考方案7】:

其实reflog是一个别名

 git log -g --abbrev-commit --pretty=oneline

所以答案应该是:这是一个特定的案例。

【讨论】:

git log 中,-g--walk-reflogs 的缩写形式。所以,这并不能解释什么。

以上是关于git reflog 和 log 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Git log和reflog

Git常用命令比较之git log与git reflog命令的比较

Android git reflog 或 git log打印日志的乱码解决方案

GitGit 基础命令 ( 查看提交记录 git log | 版本回滚 git reset | 撤销回滚 git reflog )

GitGit 基础命令 ( 查看提交记录 git log | 版本回滚 git reset | 撤销回滚 git reflog )

git reset 和 git revert 有啥区别?