本章节主要介绍 git reflog 命令。 Git 使用一种称为引用日志或“reflogs”的机制来跟踪分支顶端的更新。 许多 Git 命令接受用于指定引用或“ref”的参数,它是指向提交的指针。 常见的例子包括:
git checkout
git reset
git merge
Reflogs跟踪本地仓库中Git引用的更新时间。除了分支提示引用日志之外,还为Git存储维护了一个特殊的reflog。Reflogs存储在本地仓库的.git目录中。git reflog目录可以在.git/logs/refs/heads/
和 .git/logs/HEAD
找到,如果在仓库中使用了git stash,还可以在.git/logs/refs/stash
中找到。
本章节将介绍:git reflog的扩展配置选项、git reflog的常见用例和缺陷、如何使用git reflog撤消更改,等等。
git reflog 基本用法
下面是最基本的 reflog 用法
这本质上是一个快捷方式,相当于:
这将输出 HEAD
reflog。 我们应该会看到类似于以下内容的输出:
eb1050b (HEAD -> feature_branch) HEAD@{0}: checkout: moving from main to feature_branch
1525c48 (origin/main, main) HEAD@{1}: checkout: moving from 2bf1773d87a7806cda25d4d313995bb08adbabf5 to main
2bf1773 HEAD@{2}: commit: rebas
b71dc26 HEAD@{3}: rebase: 增加撤销更改命令内容
31c9ba0 (origin/jiyik, jiyik) HEAD@{4}: rebase: checkout jiyik
eb1050b (HEAD -> feature_branch) HEAD@{5}: commit: Adds new feature
1525c48 (origin/main, main) HEAD@{6}: checkout: moving from main to feature_branch
1525c48 (origin/main, main) HEAD@{7}: commit (merge): 解决冲突
Reflog 引用
默认情况下, git reflog 将输出 HEAD ref 的 reflog。 HEAD 是对当前活动分支的符号引用。 引用日志也可用于其他引用。 访问 git ref 的语法是 name@{qualifier}
。 除了 HEAD 引用,其他分支、标签、远程和 Git 存储也可以被引用。
可以通过执行以下命令获取所有引用的完整引用日志:
要查看特定分支的引用日志,请将该分支名称传递给 git reflog show
执行上面的命令将显示 jiyik 分支的引用日志。
定时的reflog
每个 reflog 条目都有一个时间戳。 这些时间戳可以用作 Git 引用指针语法的限定符标记。 这可以按时间过滤 Git 引用日志。 以下是可用时间限定符的一些示例:
1.minute.ago
1.hour.ago
1.day.ago
yesterday
1.week.ago
1.month.ago
1.year.ago
2011-05-17.09:00:00
时间限定符可以组合(例如 1.day.2.hours.ago),此外还接受复数形式(例如 5.minutes.ago)。
时间限定符 refs 可以传递给其他 git 命令。
$ git diff main@{0} main@{1.day.ago}
此示例将当前 main 分支与 1 天前的 main 分支进行比较。 如果想知道某个时间范围内发生的更改,此示例非常有用。
git reflog 子命令和配置选项
git reflog 接受一些被视为子命令的附加参数。
Show - git reflog show
show 默认是隐式传递的。 例如下面命令:
和下面的命令是等价的
$ git reflog show main@{0}
另外,git reflog show 是 git log -g --abbrev-commit --pretty=oneline 的别名。
Expire - git reflog expire
expire 子命令清除旧的或无法访问的 reflog 条目。 expire 子命令有可能丢失数据。 这个子命令通常不被最终用户使用,而是由 git 内部使用。将 -n
或 --dry-run
选项传递给 git reflog expire 将执行“试运行”,它将输出哪些 reflog 条目被标记为要修改,但实际上不会修改它们。
默认情况下,reflog 到期日期设置为 90 天。 可以通过将命令行参数 --expire=time
传递给 git reflog expire 或通过设置 gc.reflogExpire 的 git 配置名称来指定过期时间。
Delete - git reflog delete
delete 子命令是不言自明的,将删除传入的 reflog 条目。 与 expire 一样,delete 有可能丢失数据,并且通常不会被最终用户调用。
恢复丢失的提交
Git 永远不会真正丢失任何东西,即使在执行历史重写操作(例如重新设置基准或提交修改)时也是如此。 对于下一个示例,让我们假设我们对我们的仓库进行了一些新的更改。 我们下面命令查看日志信息
$ git log --pretty=oneline
338fbcb41de10f7f2e54095f5649426cb4bf2458 extended content
1e63ceab309da94256db8fb1f35b1678fb74abd4 bunch of content
c49257493a95185997c87e0bc3a9481715270086 flesh out intro
eff544f986d270d7f97c77618314a06f024c7916 migrate existing content
bf871fd762d8ef2e146d7f0226e81a92f91975ad Add Git Reflog outline
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit add git-init and setting-up-a-repo docs
然后我们提交这些更改并执行以下操作:
$ git commit -am "some WIP changes"
在这一点上,我们通过执行下面的命令进入交互模式
$ git rebase -i origin/main
在rebase过程中,我们使用s rebase子命令将提交标记为挤压。在rebase期间,我们将一些提交压缩到最近的“some WIP changes ”提交中。
因为我们压缩了提交,git日志输出现在看起来像:
40dhsoi37656e19d4e4f1a9b419f57850ch87dah987698hs some WIP changes
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit add git-init and setting-up-a-repo docs
如果我们此时检查 git log ,似乎我们不再有标记为压缩的提交。 如果我们想对压缩的提交之一进行操作怎么办? 从历史中删除它的变化? 此时就可以使用 git reflog 。
$ git reflog
37656e1 HEAD@{0}: rebase -i (finish): returning to refs/heads/git_reflog
37656e1 HEAD@{1}: rebase -i (start): checkout origin/main
37656e1 HEAD@{2}: commit: some WIP changes
我们可以看到 rebase 的开始和结束有 reflog 条目,在这些条目之前是我们的“some WIP changes ”提交。 我们可以将 reflog 引用传递给 git reset 并重置为 rebase 之前的提交。
执行此重置命令会将 HEAD 移动到添加了“some WIP changes”的提交,实质上是恢复其他压缩的提交。
git reflog 总结
在本教程中,我们讨论了 git reflog 命令。涵盖的一些关键点是:
如何查看特定分支的 reflog
如何使用reflog撤销 git rebase
如何指定和查看基于时间的 reflog 记录
我们简要提到 git reflog 可以与其他 git 命令一起使用,例如 git checkout、git reset 和 git merge。 在各自章节中了解更多知识点。