git reflog和log有什么区别?

233

man手册中说log命令显示提交日志,而reflog命令则管理reflog信息。那么,什么是reflog信息?相比之下,它与log命令有何不同?log命令似乎更加详细。

7个回答

300

git log 显示当前的 HEAD 及其祖先。也就是说,它会打印出 HEAD 指向的提交,然后是它的父级,再然后是它的父级,以此类推。它通过递归查找每个提交的父级来遍历整个仓库的祖先。

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

git reflog 根本不遍历 HEAD 的祖先。reflog 是 HEAD 所指向的提交的有序列表:它是您仓库的撤消历史记录。reflog 不是仓库本身的一部分(它存储在与提交本身不同的地方),不包括在 push、fetch 或 clone 中;它完全是本地的。

另外:了解 reflog 就意味着一旦提交,您就不会真正丢失仓库中的数据。如果您意外地重置到旧的提交,或者错误地进行了 rebase,或者任何其他可视化“删除”提交的操作,您可以使用 reflog 查看之前的位置,并使用 git reset --hard 返回到该引用以恢复先前的状态。请记住,引用不仅意味着提交,还包括背后的整个历史。


41
注意:有时候由于日志记录不是永久保留的,而被删除,因此您可能会丢失数据。请参阅此答案以及git-refloggit-gc的文档以了解更多信息。通常来说,如果破坏性操作不超过两周,那么您很可能是安全的。 - mcmlxxxvi
@mcmlxxxvi 我有两个本地文件夹用于同一个仓库,我能合并这两个文件夹的引用日志吗? - Tmx
@Tmx,我不太明白你的情况 - 你所说的“同一仓库的两个本地文件夹”是什么意思? 如果你有两个克隆的相同仓库,并且它们都是最新的,而你想要“合并”它们的编辑历史,那么.git/logs/refs/<branch>条目的格式为<old_rev> <new_rev> [...] <timestamp> [...]。你可以尝试将它们连接起来并按时间戳排序。然而,有些行的new_rev可能与下一行的old_rev不匹配,在这种情况下,我怀疑引用日志将无效。然后,你可以尝试插入虚假条目来“修复”序列,但我觉得这太麻烦了。 - mcmlxxxvi

92
  • git log 显示可以从引用(头、标签、远程)访问的提交日志。
  • git reflog 是您的存储库中在任何时间引用或引用过的所有提交的记录。

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

gc.reflogexpire
gc.<pattern>.reflogexpire

git reflog expire会删除早于此时间的reflog条目;默认为90天。
在"<pattern>"(例如"refs/stash")中间,该设置仅适用于与<pattern>匹配的引用。

safety net

git reflog通常被称为“你的安全网

如果遇到问题,当git log无法显示您要查找的内容时,一般建议是:

"保持冷静,使用git reflog"

keep calm

再次强调,reflog 是对于你的 SHA1 的本地记录。
git log 相对应:如果你将你的 repo 推送到一个upstream repo中,你将会看到相同的git log,但不一定是相同的git reflog


21
这是《Pro Git书》中关于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之前能够掌握一些基础知识。 - Noich
4
Git日志记录了您的提交记录;而引用日志(reflog),如《Pro Git》书中所述,记录了您的引用(即分支指针和HEAD指针)以及它们所指向的提交记录。明白了吗?另外,log命令也可以显示引用日志信息,但需要将--walk-reflogs特殊选项标志作为参数传递给它。 - user456814
3
另外,由于你是Git的初学者,我强烈推荐你阅读《Pro Git》这本书,这是我学习Git大部分知识的来源。我建议你阅读第1-3章和第6-6.5章。我也强烈建议你学习如何进行交互式和非交互式的rebase操作。 - user456814
供日后参考,git reflog 显示最新的更改在前面。 - Milind R

17

我也对此很好奇,以下进行详细说明和总结:

  1. git log 显示了你所在分支的所有提交历史记录。切换到其他分支,你将看到不同的提交历史记录。如果要查看所有分支的提交历史记录,请输入 git log --all

  2. git reflog 显示了你的引用记录,正如 Cupcake 所说。每次提交或执行检出操作时都会有一个记录条目。使用 git checkout 在两个分支之间多次切换几次,然后在每个检出操作后运行 git reflog。你将看到顶部的条目每次都更新为“checkout”条目。这些类型的条目在 git log 中是不可见的。

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


12

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

私人与公共

使用git reflog,它会跟踪你在本地所做的所有事情。你提交了吗?Reflog会跟踪它。你进行了硬重置吗?Reflog会跟踪它。你修改了一个提交吗?Reflog会跟踪它。你在本地所做的一切,都有一个reflog条目。

但这对于日志来说并不是真的。如果你修改了一个提交,日志只显示新提交。如果你重置并回退了历史记录中的几个提交,那些被跳过的提交不会出现在日志中。当你将更改推送给另一个开发者或者GitHub之类的东西时,只有日志中跟踪的内容才会出现。对于另一个开发者来说,看起来好像重置从未发生过或修改从未发生过。

日志是精细的。Reflog是镶嵌的。

所以,是的,我喜欢“私人vs公共”这个比喻。或者也许一个更好的日志vs reflog比喻是“精细vs镶嵌”。Reflog显示了你所有的尝试和错误。日志只显示了你工作历史的干净而精细的版本。

看看这张图片以强调这一点。自仓库初始化以来已经进行了许多修改和重置。Reflog显示了所有内容。但是日志命令使其看起来好像只有一个提交与仓库相关:

Log is polished. Reflog is lapidary.

回到“安全网”概念

另外,由于reflog跟踪了你修改和重置的提交,它允许你回到过去并找到那些提交,因为它会给出提交ID。假设你的存储库没有清除旧提交,这就允许你恢复在日志中不再可见的项目。这就是为什么当有人需要找回他们认为意外丢失的东西时,reflog有时会挽救某人的皮肤。


1
我发现这个答案最容易理解了!谢谢。 - Omid
McGoogle说:lap·i·dar·y /ˈlapəˌderē/ 形容词--与石头和宝石有关,涉及雕刻、切割或抛光的工作。简而言之:未经过抛光或正在进行中。 - ruffin

3

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


-8

实际上,reflog是一个别名

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

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


12
git log命令中,-g--walk-reflogs的缩写形式。这并没有解释任何内容。 - Adrian W

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接