手册页说log显示提交日志,reflog管理reflog信息。究竟什么是reflog信息,它有什么日志没有的?日志似乎更详细。


下面是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中太旧的表项或过期表项。来自reflog的官方Linux内核Git文档:

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


Git日志显示了从refs(头,标签,远程)访问的提交日志。 Git reflog记录了任何时候在你的repo中被引用或被引用的所有提交。

这就是为什么当你执行“破坏性”操作(比如删除一个分支)时使用git reflog(默认90天后修剪的本地记录),以获得该分支引用的SHA1。 参见git配置:

gc.reflogexpire
gc.<pattern>.reflogexpire

Git reflog expire删除比这个时间更老的reflog条目;默认为90天。 “<模式>”(例如:"refs/stash"),该设置只适用于匹配<pattern>的引用。

Git reflog通常被称为“您的安全网”

以防万一,一般的建议,当git日志没有显示你要找的东西时,是:

“保持冷静,使用git reflog”

同样,reflog是SHA1的本地记录。 与git日志相反:如果你将你的回购推到上游的回购,你会看到相同的git日志,但不一定是相同的git reflog。


git日志显示当前HEAD和它的祖先。也就是说,它打印HEAD指向的提交对象,然后是它的父对象,它的父对象,等等。它通过递归查找每个提交的父节点,遍历回购的祖先节点。

(在实践中,一些提交有多个父文件。要查看更有代表性的日志,可以使用git log——oneline——graph——decoration这样的命令。)

git reflog根本不遍历HEAD的祖先。reflog是HEAD所指向的一个有序的提交列表:它是你的repo的撤销历史。reflog不是repo本身的一部分(它被单独存储到提交本身),并且不包括在push、fetch或clone中;这纯粹是本地的。

另外:理解reflog意味着一旦repo被提交,就不会真正丢失数据。如果你不小心重置到旧的提交,或者错误地重设基准,或者任何其他视觉上“删除”提交的操作,你可以使用reflog来查看之前的位置,然后git重置——硬回到那个引用来恢复之前的状态。记住,引用不仅意味着提交,还意味着它背后的整个历史。


我对此也很好奇,我想详细阐述和总结一下:

git log shows a history of all your commits for the branch you're on. Checkout a different branch and you'll see a different commit history. If you want to see you commit history for all branches, type git log --all. git reflog shows a record of your references as Cupcake said. There is an entry each time a commit or a checkout it done. Try switching back and forth between two branches a few times using git checkout and run git reflog after each checkout. You'll see the top entry being updated each time as a "checkout" entry. You do not see these types of entries in git log.

引用: http://www.lornajane.net/posts/2014/git-log-all-branches


实际上,reflog是

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

所以答案应该是:这是一个具体的情况。


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

私人vs公共

使用git reflog,它会跟踪您在本地所做的所有事情。你答应了吗?Reflog跟踪它。你硬复位了吗?Reflog跟踪它。你修改commit了吗?Reflog跟踪它。你在本地做的所有事情,在reflog中都有一个条目。

这对对数来说不成立。如果修改了提交,日志只显示新的提交。如果您执行重置并回跳历史记录中的一些提交,那么您跳过的那些提交将不会显示在日志中。当您将更改推送给另一个开发人员或GitHub或类似的东西时,只会显示日志中跟踪的内容。对于另一个开发人员来说,这看起来就像从未发生过重置或修正。

圆木经过打磨。这是一种宝石。

所以,是的,我喜欢“私人vs公共”的类比。或者一个更好的原木vs reflog类比是“抛光vs宝石”。reflog显示了你所有的尝试和错误。日志只是展示了你工作历史的一个干净的版本。

看看这张图片来强调这一点。自存储库初始化以来,发生了许多修改和重置。这一切都体现在重新发行上。然而,log命令使它看起来好像只有一次针对repo的提交:

回到“安全网”的概念

此外,由于reflog会跟踪你修改过的东西并提交你重置的东西,它允许你返回并找到那些提交,因为它会给你提交id。假设您的存储库没有清除旧提交,这允许您复活日志中不再可见的项。这就是为什么当人们需要拿回他们认为自己无意中丢失的东西时,reflog有时会拯救他们的皮肤。


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

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

另一方面,Git reflog使用在.git/logs中创建的直接日志

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

不管怎样,即使你丢失了所有标签、所有分支和logs文件夹中的所有日志,提交对象仍然在.git/objects目录中,所以如果你发现所有悬挂的提交,你可以重建树:git fsck