执行push --force
总是有点风险,这里有一个例子说明它如何产生一些问题,比如远程修改版本。
假设有一些人 Bob 已更新从master
到B
的远程C
分支。还有另一个人 Mike 尚未获取此更新,而HEAD
的{{1}}仍为master
。然后B
执行Mike
并突然将远程push --force
再次回滚到master
:
B
换句话说,在 Mike 之前,远程母版就像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
修订只是远程的 - 它存在于git-server和 Bob 的笔记本电脑上,因为他将其推送到远程{{1 }}。这意味着 Mike 的笔记本电脑上没有此类本地参考C
。
问题1 : Mike 如何将远程master
设置回C
?
Mike 已尝试再次使用master
解决C
问题,但它不起作用,因为没有糟糕的本地参考:
push --force
问题2 : Mike 如何从git服务器获取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'
修订版?如果他不能那样做 - 为什么git这样设计?在一些罕见的情况下是否涉及安全?它究竟阻止了什么问题?
通常C
仅检索分支和标记,但fetch
不属于任何分支(这意味着没有任何远程分支C
是父提交或{{ 1}} of of。
PS:我们假设 Mike 没有对git服务器的ssh访问权限,这意味着无法从服务器端调用git。
PPS: Mike 不希望 Bob 知道该事故,因此请回答“让 Bob 再次推送此提交”是不是这个问题是什么。
答案 0 :(得分:9)
任何在本地提交C
的人都可以使用git branch some-name C
为C
提供一个名称,然后git push origin some-name:master
将C
添加回主人C
原产地。
任何没有C
的人根本无法恢复C
(即使它位于原始对象商店中)。
迈克 无法解决问题,除非使用包含提交C
的可用内容(可能是共享内容,可能是 Bob ' s,可能是git-push
在主人身上时克隆的其他一些仓库。
您无法推送本地没有的提交。 {{1}}的本地一半必须能够遍历历史记录以确定要上传的对象,如果没有该历史记录,则无法执行此操作。
你无法获取无法从refs访问的提交,因为字面上每个git安全层都在ref-by-ref的基础上进行安全性,而不是逐个对象,并且因为没有真正的有理由远程引用松散的物体。 Git的远程处理层完全围绕复制refs构建。
但是如果服务器启用了该功能,您可以使用git-archive获取任意提交的内容。大多数都没有,即使你的,也没有足够的信息来重建提交对象。
(c)irc:// freenode /#git,ojacobson
答案 1 :(得分:9)
如果您使用的是GitHub,则可以按照this post中的步骤在孤立后在提交C
上创建分支。
答案 2 :(得分:2)
无法访问服务器,这是......非常困难,充其量。 (我说“硬得多”,因为它可能会编写一个上传无包装的程序,然后发送一个转换更新,按编号提到C
。我不知道这是否会起作用;它威力。)
但是,一般情况下,服务器将从某个客户端获取修订版C
(大多数推送服务器为--bare
,这意味着服务器上没有实际执行任何工作)。那个客户端缺少提交,并且很容易恢复提交(在reflog中找到,添加一个新的分支或标记,推送)。
如果您具有对服务器的ssh访问权限,请登录并使用git fsck
查找已删除的提交(或者如果您使用缩写的SHA-1只使用该提交),则使用git branch
或{ {1}}创建对它的引用。
编辑,每个问题编辑:Mike 实际上可能提交 git tag
。他可以尝试,例如,C
,看看他是否拥有它。但是git rev-parse C
失败已经告诉我们他没有它。他为什么不能得到它?因为当他连接到服务器时,他说(实际上)“这是我的分支机构,你的是什么?”并且服务器说(实际上)“哦,我的是这些,你想要其中的一些吗?”。这就是协议中的所有内容 - 客户端不能通过ID请求特定的提交,至少不是通过这些接口。某些Web服务器访问方法 do 允许您通过原始SHA-1值发送并请求相应的对象;您必须查明服务器是否正在运行任何此类服务。
至于“迈克不希望鲍勃知道这起事故”......好吧,有时你只需承认。 : - )
答案 3 :(得分: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
一个很好的额外之处是它不接触本地主分支。