git reflog

我们对 git log 应该很熟悉了,它是我们常用的用来查看提交记录的命令,而对另一个查看日志的命令 git reflog,可能就不那么熟悉了。我最近因为排查一个线上bug,定位到一段代码被注释掉了,从 log 日志上看,是在一次 merge 的过程中发生的,但因为 rebase 和 amend 等命令的存在,光看 log 有的时候是不可靠的,为了进一步确认该操作是如何发生的,我用到了 git reflog。顺便把 reflog 的用法整理了一份。

git log VS git reflog

git log shows the current HEAD and its ancestry. That is, it prints the commit HEAD points to, then its parent, its parent, and so on. It traverses back through the repo’s ancestry, by recursively looking up each commit’s parent.

(In practice, some commits have more than one parent. To see a more representative log, use a command like git log –oneline –graph –decorate.)

git reflog doesn’t traverse HEAD’s ancestry at all. The reflog is an ordered list of the commits that HEAD has pointed to: it’s undo history for your repo. The reflog isn’t part of the repo itself (it’s stored separately to the commits themselves) and isn’t included in pushes, fetches or clones; it’s purely local.

Aside: understanding the reflog means you can’t really lose data from your repo once it’s been committed. If you accidentally reset to an older commit, or rebase wrongly, or any other operation that visually “removes” commits, you can use the reflog to see where you were before and git reset –hard back to that ref to restore your previous state. Remember, refs imply not just the commit but the entire history behind it.

git log 是显示当前的HEAD和他的祖先的,递归是沿着当前指针的父亲,父亲的父亲……这样的原则。

git reflog 根本不遍历HEAD的祖先,他是HEAD所指向的一个顺序的提交列表。reflog并不是repo的一部分,它单独存储,而且不包含在pushes、fetches、或者clones里,它纯属是本地的。

reflog查看的是所有的 HEAD 改变的记录,约等于记录用户操作行为。reflog 可以很好地帮助你恢复你误操作的数据,例如你错误地 reset 了一个旧的提交,或者 rebase 等等,这个时候想要查看在错误操作之前的信息,log就做不到了,而reflog可以。然后使用 git reset –hard 去恢复之前的状态。

git log shows the commit log accessible from the refs (heads, tags, remotes)
git reflog is a record of all commits that are or were referenced in your repo at any time.
That is why git reflog (a local recording which is pruned after 90 days by default) is used when you do a “destructive” operation (like deleting a branch), in order to get back the SHA1 that was referenced by that branch.
See git config

参考:https://stackoverflow.com/questions/17857723/whats-the-difference-between-git-reflog-and-log

git reflog 命令

git 的版本表示法

HEAD@{2} means “where HEAD used to be two moves ago”, master@{one.week.ago}means “where master used to point to one week ago in this local repository”

HEAD@{2}表示HEAD指针在两次移动之前的情况;而 master@{one.week.ago}表示master在本地仓库一周之前的情况。

命令语法

1
git reflog <subcommand> <options>
1
2
3
4
git reflog [show] [log-options] [<ref>]
git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all | <refs>…​]
git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] ref@{specifier}…​
git reflog exists <ref>

“expire”子命令会删除掉更老的reflog条目。

“delete”子命令从reflog中删除一个条目。

“exists”子命令检查一个ref是否有一个reflog。

reflog 高级

reflog 跟 log 一样也可以自定义输出格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
%H: commit hash
%h: 缩短的commit hash
%T: tree hash
%t: 缩短的 tree hash
%P: parent hashes
%p: 缩短的 parent hashes
%an: 作者名字
%aN: mailmap的作者名字 (.mailmap对应,详情参照git-shortlog(1)或者git-blame(1))
%ae: 作者邮箱
%aE: 作者邮箱 (.mailmap对应,详情参照git-shortlog(1)或者git-blame(1))
%ad: 日期 (--date= 制定的格式)
%aD: 日期, RFC2822格式
%ar: 日期, 相对格式(1 day ago)
%at: 日期, UNIX timestamp
%ai: 日期, ISO 8601 格式
%cn: 提交者名字
%cN: 提交者名字 (.mailmap对应,详情参照git-shortlog(1)或者git-blame(1))
%ce: 提交者 email
%cE: 提交者 email (.mailmap对应,详情参照git-shortlog(1)或者git-blame(1))
%cd: 提交日期 (--date= 制定的格式)
%cD: 提交日期, RFC2822格式
%cr: 提交日期, 相对格式(1 day ago)
%ct: 提交日期, UNIX timestamp
%ci: 提交日期, ISO 8601 格式
%d: ref名称
%e: encoding
%s: commit信息标题
%f: sanitized subject line, suitable for a filename
%b: commit信息内容
%N: commit notes
%gD: reflog selector, e.g., refs/stash@{1}
%gd: shortened reflog selector, e.g., stash@{1}
%gs: reflog subject
%Cred: 切换到红色
%Cgreen: 切换到绿色
%Cblue: 切换到蓝色
%Creset: 重设颜色
%C(...): 制定颜色, as described in color.branch.* config option
%m: left, right or boundary mark
%n: 换行
%%: a raw %
%x00: print a byte from a hex code
%w([[,[,]]]): switch line wrapping, like the -w option of git-shortlog(1)