11

这样做push --force总是有风险的,这里有一个例子说明它如何产生一些问题,比如远程丢失修订。

假设,有人Bob已将远程master分支从更新BC。还有另一个人Mike尚未获取此更新,HEAD而他master的仍然是B. 然后Mike执行push --force并突然回滚远程master再次B

mike@laptop $> git push --force origin
Counting objects: 19, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 2.27 KiB, done.
Total 12 (delta 8), reused 0 (delta 0)
remote: => Syncing... [OK]
To git@gitserver.com:path/to/project.git
   C..B  master -> master (forced update)

换句话说,在迈克这样做之前,远程大师就像A---B---C,他将其更改为A---B

如您所见,C这里的修订仅是远程的-它存在于 git-server 和Bob的笔记本电脑上,因为他将其推送到了 remote master。这意味着Mike的笔记本电脑C上没有这样的本地 ref。

问题1 :麦克如何设置遥控masterC

迈克试图再次解决这个问题,push --force就像类似问题提供的答案一样,但它不起作用,因为没有吸本地参考:

mike@laptop $> git push --force origin C:master
error: src refspec C does not match any.
error: failed to push some refs to 'git@gitserver.com:path/to/project.git'

问题 2 : Mike如何C从 git 服务器获取修订版?如果他不能那样做 - 为什么 git 设计成那样?在极少数情况下是否与安全有关?它究竟能防止什么问题?

通常fetch只检索分支和标签,但C不属于任何分支(这意味着没有任何远程分支C是父提交或HEAD属于)。

PS:我们假设Mike没有 ssh 访问 git server 的权限,也就是说没有办法从 server 端调用 git。

PPS:迈克不想让鲍勃知道那次事故,所以回答“让鲍勃再次推送这个提交”不是这个问题的意义所在。

4

4 回答 4

16

C任何在本地提交的人都可以使用git branch some-name CC命名,然后git push origin some-name:master(尝试)附加C回原点的主控。

任何没有的人根本C无法恢复C(即使它在原点的对象存储中)。

Mike 无法解决问题,除非使用包含提交的 repo C(可能是共享的,可能是BobC的,可能是其他一些在 master 上克隆的 repo )。

您无法推送本地没有的提交。本地一半git-push必须能够遍历历史以确定要上传的对象,如果没有可用的历史,它就无法做到这一点。

您无法从 ref 中获取无法访问的提交,因为实际上每个 git 安全层都在 ref-by-ref 的基础上进行安全性,而不是在逐个对象的基础上,并且因为没有真正的理由来引用远程松散物体。Git 的远程处理层完全围绕复制 refs 构建。

但是,如果服务器打开了该功能,您可以使用 git-archive 获取任意提交的内容。大多数都没有,即使你有,也没有足够的信息来重建提交对象。

(c) irc://freenode/#git, ojacobson

于 2013-09-20T06:50:17.247 回答
14

如果您使用的是 GitHub,您可以按照本文中的步骤在提交时创建一个C孤立的分支。

于 2016-01-05T18:36:20.907 回答
3

如果无法访问服务器,这……充其量是非常困难的。(我说“充其量很难”,因为可以编写一个不上传任何包的程序,然后发送一个C按数字提及的 rev 更新。我不知道这是否可行;它可能。)

但是,一般来说,服务器会C从某些客户端获取修订(大多数推送服务器都是--bare,这意味着实际上没有在服务器上执行任何工作)。该客户端缺少提交,并且在那里恢复提交非常容易(在 reflog 中查找,添加新分支或标签,推送)。

如果您对服务器具有 ssh 访问权限,请登录并使用git fsck来查找已删除的提交(或者如果您有缩写的 SHA-1,请使用它),然后使用git branchgit tag创建对它的引用。

编辑,每个问题编辑:实际上迈克确实有可能 commit C。他可以尝试,例如,看看他是否拥有它。但是失败已经告诉我们他没有。为什么他不能得到它?因为当他连接到服务器时,他说(实际上)“这是我的分支负责人,你的负责人是什么?” 服务器说(实际上)“哦,这些是我的,你想要一些吗?”。这就是协议中的全部内容——客户端不能通过 ID 请求特定的提交,至少不能通过这些接口。某些 Web 服务器访问方法确实允许您发送原始 SHA-1 值并请求相应的对象;您必须确定服务器是否正在运行任何此类服务。git rev-parse Cgit push --force origin C:master

至于“迈克不想让鲍勃知道那次事故”……嗯,有时你只需要坦白。:-)

于 2013-09-18T18:09:34.597 回答
0

这些 git 命令解决了这个问题。仅当您拥有完整的哈希时才有效。

# Fetch the remote commit and create a reference for it
git fetch origin C:refs/remotes/origin/foo-commit

# Checkout the remote branch we just created
git checkout foo-commit

# Force push foo-commit branch to master
git push -f origin master

一个不错的附加功能是它不会触及本地主分支。

于 2021-05-21T18:54:32.767 回答