19

如果我使用push -f在远程存储库上重叠最后一次提交,即 A,而其他人在我推送之前拉了 A。

无论如何要撤消此操作,以免给他人造成麻烦?

push -f原创者“假装”什么都没碰过有用吗?

或者

git 如何决定本地 repo 是否与远程跟踪不同?

4

1 回答 1

49

有几种方法可以在推送之前找出原始 HEAD(ORIG_HEAD 可能不是其中之一):

终端回滚

如果你有幸让终端仍然打开,那么在推送时会有一些输出,如下所示:

...
To user@host:repo.git
 + abcdef0...1234567 HEAD -> branchname (forced update)

在这里,abcdef0是以前的 HEAD (你的A),1234567是你强迫它变成的。

git reflog

的输出git reflog告诉你你所做的事情的时间历史。您基本上想回到有问题的行(您在更改之前检查了您的分支)并从第一列中获取提交 ID。

这里最有用的命令是git reflog show remotes/origin/branchname. 这应该显示您的强制更新 ( 1234567) 和之前的提交 ID ( abcdef0) 作为前两行。

以前的参考

几个提交参考在这里可能有用:

  • @{1}(或者branchname@{1},如果您不在该分支上)是该引用的先前值。仅当您没有对本地分支进行任何其他提交时才有效。(但是@{2}@{3}等会让你走得更远。)
  • 同样,remotes/origin/branchname@{1}将是遥控器上 ref 的先验值。只有在其他人没有推送到遥控器时才有效。(关于上面的相同点@{n}。)

检查您的 ID 是否正确

如果您想确认从上述方法之一获取的 ID 是否正确,只需检查一下即可:

git checkout abcdef0

看看周围。如果git log看起来很熟悉(我还建议使用tig浏览您的存储库,您甚至可以运行tig abcdef0查看给定提交的日志),那么您可以确信您正在重置到正确的位置。

重置到之前的状态

一旦你有了之前的提交 ID,你可以重置为那个并再次强制推送:

git checkout branchname # if you're not on it already
git reset --hard abcdef0
git push -f

要不就:

git push -f origin abcdef0:branchname

这会将分支的状态恢复到强制推送之前的状态。(快速说明:第一个片段将更新您的本地分支以及远程;第二个片段仅更新远程。)

有什么影响?

如果人们在你强制推送后拉了分支,如果你强制推送回原来的分支,那么他们在后续更新时会遇到问题。如果他们没有对该分支进行任何提交,他们可以删除他们的本地分支并重新签出(在git fetch确保他们有最新的引用之后),或者以下将做同样的事情:

git fetch
git checkout branchname # if you're not on it already
git reset --hard origin/branchname

如果他们进行了本地提交,那么他们将需要将这些更改重新定位到正确的历史记录(并可能解决任何冲突):

git fetch
git checkout branchname # if you're not on it already
git rebase --onto origin/branchname 1234567

1234567上面的意思是“在(不正确的头部)之后(正确的头部)重放所有提交origin/branchname”。

于 2013-01-23T09:42:45.500 回答