如何正确强制推送Git?

How do I properly force a Git push?

我已经设置了一个远程非裸机的"主"repo并将其克隆到我的计算机上。我做了一些本地更改,更新了本地存储库,并将更改推回到远程repo。到那时一切都很好。

现在,我必须在远程回购中更改一些内容。然后我在本地回购中做了一些改变。我意识到不需要更改远程回购。因此,我尝试从本地回购到远程回购,但得到了如下错误:

To prevent you from losing history, non-fast-forward updates were
rejected Merge the remote changes before pushing again. See the 'Note
about fast-forwards' section of git push --help for details.

我想那可能是

1
git push --force

将强制本地副本将更改推送到远程副本并使其相同。它确实强制更新,但是当我返回到远程repo并提交时,我注意到文件包含过时的更改(主远程repo以前的更改)。

正如我在对其中一个答案的评论中提到的:

[I] tried forcing, but when going back to master server to save the changes, i get outdated staging. Thus, when i commit the repositories are not the same. And when i try to use git push again, i get the same error.

如何解决此问题?


只做:

1
git push origin <your_branch_name> --force

或者,如果您有特定的回购:

1
git push https://git.... --force

这将删除以前的提交并推送当前的提交。

这可能不合适,但如果有人偶然发现了这一页,他们可能会想要一个简单的解决方案…

短旗

同时注意,-f--force的缩写,所以

1
git push origin <your_branch_name> -f

也会起作用。


如果push --force不起作用,你可以做push --delete。查看此实例上的第2行:

1
2
3
git reset --hard HEAD~3  # reset current branch to 3 commits ago
git push origin master --delete  # do a very very bad bad thing
git push origin master  # regular push

但是当心…

永远不要回到公开的Git历史上!

换言之:

  • 永远不要推动公共存储库。
  • 不要这样做或做任何可能破坏别人的东西。
  • 不要在回购交易中有人已经退出的历史记录。

当然,即使是这个规则也有非常罕见的例外,但在大多数情况下,不需要这样做,它会给其他人带来问题。

改为执行还原。

而且要时刻小心你推动的公共回购。回复:

1
2
3
git revert -n HEAD~3..HEAD  # prepare a new commit reverting last 3 commits
git commit -m"sorry - revert last 3 commits because I was not careful"
git push origin master  # regular push

实际上,两个原点(从还原和邪恶重置)都将包含相同的文件。

编辑以添加更新的信息和更多关于push --force的参数。考虑使用租赁而不是推的方式来推动力,但仍倾向于恢复。

另一个问题可能是,有人在你之前推什么东西,但在你已经取出之后。如果您现在强制您的重新调整版本,您将替换其他人的工作。

git 1.8.5中引入的git push --force-with-lease(感谢@vonc对这个问题的评论)试图解决这个具体问题。基本上,如果在最近一次获取之后修改了遥控器,它将带来一个错误而不是推送。

如果你真的确定需要一个push --force,这是很好的,但仍然想防止更多的问题。我要说的是,这应该是默认的push --force行为。但这还远不是强迫江户的借口。在你的钢筋网之前取钢筋的人仍然会有很多麻烦,如果你改回钢筋网,很容易避免这些麻烦。

既然我们讨论的是git --push个例子…

为什么会有人想强行推?

@Linqueze为评论提供了一个很好的推动力示例:敏感数据。你错误地泄露了不应该被推送的数据。如果你足够快,你可以通过顶推来"修复"*

*除非您同时进行垃圾收集或以某种方式清理,否则数据仍将位于远程。还有一个明显的潜力就是它会被别人传播,而别人已经得到了它,但是你得到了这个想法。


首先,我不会直接在"主要"回购协议中做任何更改。如果你真的想有一个"主要"回购,那么你应该只推动它,永远不要直接改变它。

关于您所犯的错误,您是否从本地回购中尝试了git pull,然后从git push尝试了主回购?你目前正在做的(如果我理解的很好)是强制执行,然后在"主"回购中丢失你的更改。您应该先在本地合并更改。


如果我在本地分支A上,并且要强制将本地分支B推送到源分支C,那么可以使用以下语法:

1
git push --force origin B:C


我真的建议:

  • 只推动主回购

  • 确保主回购是一个裸回购,以避免主回购工作树与其.git基础不同步。请参见"如何将本地Git存储库推送到另一台计算机?"

  • 如果您确实需要在主(裸)repo中进行修改,请克隆它(在主服务器上),进行修改并将其推回到主(裸)repo中。

换句话说,保持一个可以从主服务器和本地计算机访问的裸式回购,以便有一个单独的上游回购从/到拉/拉。


使用以下命令:

1
git push -f origin master


这是我们在维护历史记录的同时替换公司Github存储库上的master的解决方案。

在公司存储库上掌握push -f通常被禁用以维护分支历史。这个解决方案对我们有效。

1
2
git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master
1
2
3
4
5
git checkout currentBranch  // move to target branch
git merge -s ours master  // merge using ours over master
// vim will open for the commit message
git checkout master  // move to master
git merge currentBranch  // merge resolved changes into master

把你的分支推到desiredOrigin上,创建一个pr


我也有同样的问题,但最终还是解决了。您最可能需要做的是运行以下两个git命令(将hash替换为git commit修订号):

1
2
git checkout <hash>
git push -f HEAD:master