我有一个Git仓库,远程origin
在3个主机上进行了镜像。
$ git remote -v
origin git@github.com:username/repo.git (fetch)
origin git@github.com:username/repo.git (push)
origin git@gitlab.com:username/repo.git (push)
origin git@bitbucket.org:username/repo.git (push)
一切都在提交A的状态下,无处不在。
$ git rev-parse HEAD
A
$ cat .git/refs/remotes/origin/master
A
我提交了B分支并推送它,现在每个人都在B分支。
$ git push origin master
To github.com:username/repo.git
A...B master -> master
To gitlab.com:username/repo.git
A...B master -> master
To bitbucket.org:username/repo.git
A...B master -> master
$ git rev-parse HEAD
B
$ cat .git/refs/remotes/origin/master
B
我注意到上一个提交中有一个错误,所以我进行了修复并修改了提交记录。这使得我的本地代码与远程代码不同步。
$ git rev-parse HEAD
C
$ cat .git/refs/remotes/origin/master
B
我喜欢避免盲目地使用--force
推送,所以我使用--force-with-lease
,但是这种方式会出现有趣的失败情况。
$ git push --force-with-lease origin master
To github.com:username/repo.git
+ B...C master -> master (forced update)
To gitlab.com:username/repo.git
! [rejected] master -> master (stale info)
To bitbucket.org:username/repo.git
! [rejected] master -> master (stale info)
问题是,只有当远程 ref 在上次我与之通信时的提交与本地记录在 .git/refs/remotes/origin/master
中的 sha1 相同时,--force-with-lease
才会考虑这个 push 是安全的。一旦第一个镜像(GitHub)被更新,git 就会将我的本地 remote ref 更新到提交 C,导致推送尝试到 GitLab 和 Bitbucket 失败,因为我们现在期望它们处于提交 C。
我想搞清楚这个问题,所以首先我强制将 GitHub 镜像回滚到提交 B。
$ git push origin +B:refs/heads/master
To github.com:username/repo.git
+ C...B B -> master (forced update)
Everything up-to-date
Everything up-to-date
现在我需要更加具体地说明我希望将远程推送到哪个提交。文档显示,您可以使用 --force-with-lease=<refname>:<expect>
来精确指定要更新的引用和当前期望它所在的提交,因此我尝试了一下。
$ git push --force-with-lease=origin/master:B origin master
To github.com:username/repo.git
! [rejected] master -> master (non-fast-forward)
To gitlab.com:username/repo.git
! [rejected] master -> master (non-fast-forward)
To bitbucket.org:username/repo.git
! [rejected] master -> master (non-fast-forward)
显然我做错了什么,也许是 <refname>
写错了?我感觉离成功很近了,但我错过了什么?
git push --force-with-lease=$(git rev-parse origin/master):B origin master
(即使用原始提交ID而不是名称)。我不确定Git在这种特殊情况下何时进行名称到ID的转换。 - torek