如何查看 Git 分支随时间的变化情况(包括历史记录重写)?

How can I see how a Git branch changed over time (including history rewrites)?

对于给定的回购和分支,有没有办法查看该分支随时间的变化情况,包括历史重写?例如:

4 月 1 日:提交 A -> B -> C -> D

4 月 2 日,Max Heiber—git push -f:提交 A -> B -> C'

4 月 3 日,其他人 -git merge feature 提交 A -> B -> C' -> D'

这就是我问的原因:

我们正在将功能合并到我们的 dev 分支中,但这些更改稍后会从 dev 中消失。我们发现原因是我们的一位开发人员正在做 git push -f 并且在他的 .gitconfig 中有这个:

[push] default = matching

这会强制推送他的所有分支,包括 dev 的陈旧版本。

花了一段时间才弄清楚这是怎么回事。在解决问题的同时,我们真正想要的是了解我们的历史如何以及为何发生变化。有没有可能得到这样的分支视图?

我不确定这是否适用于您的远程存储库,但它至少应该适用于您的本地存储库。

查看在开发分支上做了什么:

git reflog show dev

这应该会显示该分支在过去 30 天内的更改。

Git 并没有真正保存这些信息。如果您有 reflog,它会为 reflog 过期时间保存 something。这些时间默认为 30 天和 90 天,分别用于无法访问和可访问的提交。1 因此 将在您的本地 dev 上工作,并且因为 reflogs 是即使对于远程跟踪分支通常也启用,您还可以使用 git reflog show origin/dev 查看 您的 Git 在其 git fetch / git pull 操作。

过期通常是 运行 从 git gc 开始,所以如果 git gc 有一段时间没有 运行,你可以有相当多的额外信息。

如果您的服务器启用了 reflogs——默认情况下它们 未启用 ——您可以登录到您的服务器并在那里 运行 git reflog show dev

在所有情况下,您可能需要添加 --date=<format>(例如 --date=iso)以获得 {@<em>n</em>} 替换为 @{<em>date</em>}:

$ git reflog --date=iso master
11ae6ca master@{2016-06-17 13:32:00 -0700}: reset: moving to HEAD^
3d9eb53 master@{2016-06-17 13:31:44 -0700}: commit: Revert "fdmillion: repair example"
11ae6ca master@{2016-04-22 05:27:07 -0700}: commit (amend): add run-checks script
becf391 master@{2016-04-22 05:24:48 -0700}: commit: add run-checks script

这将为您提供每次引用更改的时间戳,这对于与 "who did what when" 相关联很有用。


1这在技术上是无稽之谈。 :-) 提交——好吧,所有 Git 对象,真的——要么可达,要么不可达,但 reflog 条目 使 它们可达,所以 shorthand 的这一特定位可能令人费解。实际定义是从相应引用的当前值可达。也就是说,当 git reflog expire 使引用过期时,它会查看:

  • 这是 refs/heads/foo
  • 的 reflog 条目
  • 分支 foo 名称是什么提交? (将此 H 称为头部)
  • 这个 reflog 条目名称是什么提交? (将此称为 E 以供输入)
  • EH的祖先吗? (参见 git merge-base --is-ancestor
  • 如果是,使用gc.reflogExpiregc.<pattern>.reflogExpire
  • 如果没有,使用gc.reflogExpireUnreachablegc.<pattern>.reflogExpireUnreachable

这两个非模式名称分别默认为90.days.ago30.days.ago(默认不设置模式值)。 refs/stash 有一个特例,设置为 never.

考虑到本地reflog可能会丢失,以防本地repo在强制推送后被删除,我试图在远程repo中找到被强制更新的分支的历史。

创建远程仓库的新克隆和 运行 git gc 以便打包所有可访问的提交和相关对象,而将不可访问的作为松散对象保留,这可以在.git/objects。但是我就是找不到任何 git 命令来列出这些无法访问的对象。 git rev-list 似乎无法列出无法访问的对象。所以我尝试了一个dumm方法将它们全部列出来,将前2个字节的文件夹名称和左边的38个字节的文件名一个一个地拼接成一个完整的sha1。然后用git cat-file -t <object>一个一个的找出所有的commit对象。然后 运行 git show <commit-object> 来查看所有内容。我认为在其中您可以找到分支在强制更新之前指向的提交。

当找到之前的提示提交时,丢失的历史记录可以取回。