如何正确地强制推送 Git?

1802

我已经设置了一个远程的非裸主仓库,并将其克隆到我的计算机上。我做了一些本地更改,更新了我的本地仓库,并将更改推回了我的远程仓库。到这一步为止,一切都很好。

现在,我不得不更改远程仓库中的某些内容。然后我又更改了本地仓库中的东西。我意识到对远程仓库的更改是不必要的。因此,我尝试从本地仓库向远程仓库进行git push,但我收到了如下错误:

为了防止您丢失历史,拒绝了非快进式更新合并远程更改后再次推送。有关详细信息,请参见git push --help中的“有关快速转发的注意事项”部分。

我认为可能是由于

git push --force

我希望强制让我的本地副本将更改推送到远程副本并使它们相同。它确实强制更新,但是当我回到远程存储库并进行提交时,我注意到文件包含过时的更改(先前主要远程存储库中的更改)。

如我在答案评论中提到的

[我]尝试了强制操作,但是当返回主机服务器以保存更改时,我得到了过时的暂存区。因此,当我提交存储库时,它们不同。而且,当我再次尝试使用git push时,我收到相同的错误。

我该怎么解决这个问题?


4
从 git1.8.5版本(2013年第四季度)开始,你将能够更加谨慎地执行“git push -force”操作。 - VonC
1
相关:强制Git在推送时覆盖远程文件 - user456814
14
正如我在自己的回答中详细说明的那样,git push --force确实是另一种有效的强制推送方式,并且会像在Git的默认push.default config settings下使用git push origin master --force一样成功地推送分支,尽管在Git 2.0之前和之后版本中具体推送哪些分支有所不同。 - user456814
8
现在这些日子里,git push --force 命令运行良好,供参考。 - rogerdpack
10
git push --force-with-lease 功能更强大 :), 它会在分支状态不符合预期时拒绝更新分支。(参考 https://developer.atlassian.com/blog/2015/04/force-with-lease/) - spoorcc
显示剩余2条评论
12个回答

3137

只需要执行以下操作:

git push origin <your_branch_name> --force

或者如果你有一个特定的仓库:

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

这将删除您之前提交的内容并推送您当前的内容。

也许不是很规范,但如果有人偶然看到这个页面,可能会想要一个简单的解决方案...

短标志

还要注意-f--force的缩写,因此

git push origin <your_branch_name> -f

这也可以工作。


76
你可以使用 git push origin +master 代替,这样你就能推送多个 refspecs 而不强制要求它们全部推送。 - nickgrim
12
请注意,如果您不小心使用 git push --force 命令,可能会导致您的主分支出现问题(取决于推送默认行为)...这可能有点糟糕 :D。 - Jeewes
20
从 Git 2.0 版本开始,git push --force默认行为是强制推送当前所检出分支到其远程对应分支,因此如果您检出了主分支,则与 git push origin master --force 是相同的。如果您使用 push.defaultmatching 设置,那么情况会有所不同,该设置是 Git 2.0 之前版本的默认设置。 matching 推送所有与远程同名的本地分支,因此强制推送可能不是您想要的操作... - user456814
3
push -f虽然很好,但不建议用于主分支,因为大多数公司的代码仓库禁用了对主分支的强制推送(-f)。我使用了“merge -s ours”命令。 - mihai
2
不要忘记,你的远程仓库权限(即 Azure DevOps)可能不允许你强制推送。在这种情况下,你需要管理员设置你的权限。 - LargeDachshund
显示剩余6条评论

313

而且如果 push --force 不起作用,你可以执行 push --delete。看看这个示例的第二行:

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历史记录!

换句话说:

  • 永远不要在公共仓库上进行force push操作.
  • 不要执行任何可能破坏他人pull的操作.
  • 永远不要在别人可能已经拉取的仓库重置(reset)重写(rewrite)历史记录。

当然,即使对于这个规则也有极为罕见的例外情况,但在大多数情况下,不需要这样做,并且它会给其他所有人造成问题。

反而应该进行还原(revert)操作。

并且一定要小心你推送到公共仓库的内容。 进行还原操作:

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

实际上,回滚恶意重置的源头HEAD都将包含相同的文件。


编辑以添加更新的信息和更多有关push --force的论据

考虑使用带租约的强制推送而不是推送,但仍然更喜欢回滚

push --force可能会带来的另一个问题是,如果有人在你之前推送了任何内容,但在你已经获取之后。如果你现在推送你的变基版本,那么你将会替换他人的工作

git push --force-with-leasegit 1.8.5中引入(感谢@VonC在评论中的问题)尝试解决这个特定问题。基本上,如果远程自你最新抓取以来被修改,它会报错并且不会推送。

如果你真的确定需要push --force,但仍想防止更多问题,那么这是很好的。我甚至可以说它应该是默认的push --force行为。但仍然远远不能成为强制push的借口。那些在你的变基之前获取的人仍将遇到许多麻烦,如果你回滚而不是变基,这些问题可以很容易地避免。

既然我们正在谈论git --push实例...

为什么有人想要强制推送?

@linquize在评论中提供了一个好的强制推送示例:敏感数据。你错误地泄露了不应该被推送的数据。如果你足够快,你可以通过强制推送来"修复"*它。

*除非你也进行垃圾收集或者某种方式清理它,否则数据仍将存在于远程。它也有被已经获取的其他人传播的明显潜力,但你知道我的意思。


1
问题在于,@rogerdpack,不是它是否可行。它是可以的。但这可能会导致巨大的灾难。某人越频繁地进行强制推送,而您从公共存储库更新(拉取)的次数越少,灾难就越大。它可能会摧毁你所知道的世界!!!111 至少包括那个特定的存储库所组成的世界。 - cregox
6
如果您有敏感数据,请强制推送。 - linquize
3
我认为他的意思是,如果你正在尝试从存储库中删除敏感数据,那么你想要重写历史记录。如果你回退,敏感数据仍然存在于早期提交中。话虽如此,如果其他人已经从存储库中拉取了数据,那么重写历史记录就不能阻止他们访问敏感数据 - 在那时已经太晚了。 - Stuart Golodetz
3
git push origin master --delete # do a very very bad bad thing git push origin master # regular push这实际上完美地解决了我的问题(在只有我和朋友的 repo 上)。也许对于公共 repo 来说这是错误的,但对于私人 repo 来说这是救命稻草。 - Can Poyrazoğlu
7
某些仓库管理器会自动执行此操作,也称为自动压缩等。在完成一个特性分支后强制推送以减少提交是常见且预期的行为。 - FlavorScape
显示剩余6条评论

28

如果我在本地分支A上,想要强制推送本地分支B到远程分支C,可以使用以下语法:

git push --force origin B:C

3
我发现即使我在本地分支B上,我仍需要执行 git push --force origin B:C 命令。在我的情况下,似乎只有使用 git push --force origin C 才会将本地主分支推送到远程C分支,无论我当前在哪个分支上。git version 2.3.8 (Apple Git-58) - Weishi Z
1
这对我在将存储库从以前的“master”分支移动到新的“main”分支时非常有帮助。只需使用“master:main”,它就按照我需要的方式工作了! - Ícaro

22

使用以下命令:

git push -f origin master

3
也许可以更详细地解释为什么这个答案比其他答案更可取,以及它的独特之处在哪里。 - Adam
1
哦,抱歉给你带来不便。我之前也遇到了同样的问题,这个命令解决了它,所以想和大家分享一下。 - mustafa Elsayed
24
和其他的命令一样,你只是改变了-f标志的位置而已… - svelandiag

19

首先,我不会直接在“主”存储库中进行任何更改。如果你真的想要一个“主”存储库,那么你应该只向其中推送内容,而不是直接更改它。

关于你遇到的错误,你尝试过从本地存储库执行git pull,然后再将其git push到主仓库吗?你目前正在做的事情(如果我理解正确)是强制推送,然后在“主”存储库中丢失你的更改。你应该先在本地合并这些更改。


1
是的,我尝试了一次拉取,但由于那次拉取,我正在失去数据。我想让我的主要存储库与我的本地存储库相同,而不必先从主要存储库更新。 - Spyros
3
在这种情况下,请使用 git push -f,但是如果您再次更改主要存储库,则必须返回到本地存储库并执行 git pull,以使其与最新更改同步。然后您可以继续工作并再次推送。 如果您遵循此“推拉”工作流程,则不会出现您所抱怨的错误类型。 - ubik
是的,我理解这是我的错:/ 我会尝试一下,稍后回来,谢谢 - Spyros
1
尝试强制推送,但当回到主服务器保存更改时,我得到了过时的分支。因此,当我提交后,仓库不一致。再次尝试使用git push时,我会收到相同的错误提示。 - Spyros

12

git push --force 可以完成工作,虽然 git push --force-with-lease 是更安全的命令。

git push --force 会覆盖远程分支,而 git push --force-with-lease 仅在本地副本了解远程分支上所有提交时才会覆盖远程分支。这种差异使得破坏其他人对项目所做的更改变得更加困难。


10

我之前也有同样的问题,但最终找到了解决办法。你很可能需要运行以下两个Git命令(将哈希替换为git提交修订号):

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

10

我真的建议您:

换句话说,保持一个裸仓库可从主服务器和本地计算机访问,以便有一个单一的上游代码库供拉取和推送使用。


你能否将代码推送到非裸的Git存储库? - hd1
@hd1 是的,自Git 2.4(2015年第二季度)以来就支持了:https://stackoverflow.com/a/42745909/6309,该链接引用了https://dev59.com/c5Lea4cB1Zd3GeqP4p85#34575157。 - VonC

6
如果您正在使用Github访问令牌进行身份验证,请尝试以下操作:
- 使用以下命令更改远程URL地址:git remote set-url origin https://YourTokenNum@github.com/UserName/ProjectName - 使用以下命令强制推送并设置上游分支:git push --force --set-upstream origin master

5

我们的解决方案是在保留历史记录的同时替换公司gitHub存储库中的主分支。

push -f 常常被禁用以维护分支历史记录。这个解决方案对我们很有效。

git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master

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。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接