这个问题可能重复,但我找不到完全相同的问题。
在我们的QA团队的git存储库中,我经常发现之前添加的测试用例丢失了。从主分支的histroy我再也找不到我的提交了。
当我比较我的个人分支的日志和主分支的日志时,曾经找到了根本原因,并且这是某人的强制推动,并且该家伙承认他对git merge不是很熟悉但是赶紧推出如此使用的强制选项。
但是如果没有这样的分支来备份这些提交历史呢?几天之后,每个团队成员都已撤离,以致承诺历史永远消失。
即使有这样的备份分支,比较和了解谁推动力量也是非常耗时的。
有没有办法获得力推日志?请注意作为一名普通员工,我不是git服务器的所有者/管理员,但我关心我的提交,并希望对那些删除它们的人进行警告。
在git
本身没有真正可靠的方法来检索那种信息。 (有些git托管软件可能会保留类似于垃圾推文的类似垃圾记录,但我不知道;如果你使用特定的托管软件包,你可以查阅它的文档。)
除了找到一个未接受新历史记录的克隆之外,即使它已经接受了新的历史记录,你也可以从克隆的reflog中获得所需的信息 - 但是reflog是本地的和临时的,所以这是不保证。
(根据您的遥控器的托管方式,您可能也可以参考其reflog,如果它保留它们并且您可以访问它们。但即使所有这些ifs都破坏了您的方式,也不能保证,因为reflog是临时的。)
这就是为什么git push -f
是一个危险的工具;如果开发人员对git的理解没有进展到他们理解它有多危险的程度,那么就有可能变得生硬,那么开发人员不应该被授予访问强制推送到与其他开发人员共享的refs的权限。
您可以配置一个git remote来拒绝所有非快进推送(即使强制);请参阅receive.denyNonFastForwards
文档中的git config
。
如果您需要更细粒度的控制,您再次必须依靠托管软件来提供它。
您将无法获得强制推送历史记录,但您至少可以窥探您自己的被破坏的提交。从您的本地克隆,使用git fsck
:
(master) :~/repo$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling blob 6edc1e217eaab8f72f67bcec2e4d1dfde299971e
dangling commit 9847c5942bf477989112ece202988bc3f8caad05
(master) :~/repo$ git merge 9847c59
// ... conflicts likely appear ... //
从这里开始,您可以解决冲突并在适当的情况下推迟更改。如果您与提交的位置不同,则此方法不起作用,即使这样,如果已经过了足够的时间,您的本地提交可能会因修剪而丢失。
这个相当“hacky”的解决方案可能有助于找到强制推送的修改提交,但我不确定它是否适用于所有可能的情况。
假设您在远程(裸)存储库中,您可以打印出存储在特定分支的reflog中的所有提交,并将它们与正常git log
的提交进行比较。差异应该给你强制推送提交。
请注意,对于裸回购,reflogs must be enabled。
作为一个例子,假设你已经承诺掌握,推动,然后修改和强制推 - 两次。那么你总共会有四次提交(如reflog所示),但实际日志中只有两次:
$ git log -g master | grep ^commit # Show reflog of master
commit 3f52cea357aaa6ba9db86c1526b025a7ee2906c1 (refs/remotes/origin/master, refs/heads/master)
commit 5afa0cfe6e16d4d45088aeb226ed052a5ad72b87
commit 0334c6f8ba13c1465c855cf0b7cf6c79df487740
commit 8bb40a9d6da838e151c8653b8d6be2b7afeb1902
$ git log master | grep ^commit # Show log of master
commit 3f52cea357aaa6ba9db86c1526b025a7ee2906c1 (refs/remotes/origin/master, refs/heads/master)
commit 0334c6f8ba13c1465c855cf0b7cf6c79df487740
$ git reflog # for reference - HEAD@{0, 2} were force pushes
3f52cea (HEAD -> refs/heads/master) HEAD@{0}: push
5afa0cf HEAD@{1}: push
0334c6f HEAD@{2}: push
8bb40a9
在bash中,我可以显示两者之间的差异(使用进程替换):
$ diff <(git log -g master | grep ^commit) <(git log master | grep ^commit) | grep "^<"
< commit 5afa0cfe6e16d4d45088aeb226ed052a5ad72b87
< commit 8bb40a9d6da838e151c8653b8d6be2b7afeb1902
我正在将上面的两个输出区分开来并且管道到grep
,这样我就能看到被修改的提交。