强制执行“git push”以覆盖远程文件

1106

我想推送我的本地文件到远程仓库,并且不必处理合并冲突。我只希望我的本地版本优先于远程版本。

如何使用Git实现这一目标?


179
"git push origin --force" 对你没有起作用吗? - user849425
3
可能是覆盖远程Git仓库的重复问题。请参考该链接。 - BuZZ-dEE
不清楚你是否只想覆盖.git文件还是相关的工作副本。 如果是git仓库,git push是答案。如果你想更新远程工作副本,则必须使用post-receive hook。 - Pierre-Olivier Vares
1
一个可能导致强制推送无法工作的原因是,远程仓库可能已经明确禁用了它(为了确保由于白痴和/或恶意贡献者而丢失任何东西):使用 config receive.denyNonFastforwards 查找。 - Frank N
我尝试过 git push origin some_branch --force,但它总是返回“Everything is up-to-date”消息。但是,git push origin your_branch:some_branch --force 才是我缺少的部分。希望这可以帮到你! - Akhil
显示剩余2条评论
6个回答

1447
您可以使用以下方式将本地版本强制推送到远程仓库:
git push -f <remote> <branch>

(例如git push -f origin master)。省略<remote><branch>将强制推送所有已设置--set-upstream的本地分支。

请注意,如果其他人共享此存储库,则其修订历史记录将与新修订冲突。如果他们在更改点之后有任何本地提交,这些提交将变为无效。

更新:我想补充一下。如果您正在创建其他人将要审查的更改,则创建一个包含这些更改的分支并定期进行变基以使其与主开发分支保持同步不是常见的情况。只需让其他开发人员知道这将定期发生,这样他们就会知道预期发生什么。

更新2:由于观看者数量越来越多,我想添加一些关于在upstream遇到强制推送时该怎么做的额外信息。

假设我已经克隆了您的存储库,并添加了一些提交,如下所示:

            D----E  主题
           /
A----B----C         开发

但是后来开发分支被rebase影响,当我运行git pull时,将收到以下错误:

正在解包对象:100%(3/3),完成。
来自<repo-location>
 * 分支            开发     -> FETCH_HEAD
正在自动合并<files>
冲突(内容):<locations>中的合并冲突
自动合并失败;解决冲突后提交结果。

在这里,我可以解决冲突并commit,但那会让我的提交历史变得非常丑陋:

       C----D----E----F    主题
      /              /
A----B--------------C'  开发

使用git pull --force可能看起来很有吸引力,但要小心,因为它会留下孤立的提交:

            D----E   主题
A----B----C' 开发

因此,最好的选择可能是执行git pull --rebase。这将要求我像以前一样解决任何冲突,但对于每个步骤,我将使用git rebase --continue而不是提交。最终提交历史记录将会更好:

            D'---E'  主题
           /
A----B----C'         开发

更新3:您还可以使用--force-with-lease选项作为“更安全”的强制 推送,如Cupcake在他的答案中提到的那样

使用“租约”进行强制推送允许推送失败,如果您没有预期的远程提交(从技术上讲,如果 您还没有将它们获取到您的远程跟踪分支中),那么这是有用的,因为这样您就不会意外地覆盖您甚至不知道的其他人的提交,并且只想覆盖自己的提交:

git push <remote> <branch> --force-with-lease

你可以通过阅读以下任何一篇文章了解如何使用--force-with-lease


8
既然这是被选中的答案,我在这里做一下评论。当你独自工作时使用强制方式并不是问题。例如,我的云主机从它自己的git开始。如果我在本地工作并构建一个项目,我想将其放到我的云主机(OpenShift)上,那么我就有了两个不同的git项目。一个是本地的,一个是OpenShift的。我可以像自己喜欢的一样设置本地的,但现在想在OpenShift上预览它。然后,您第一次使用-f标志将本地代码推送到OpenShift,从而实现将本地的git推送到OpenShift上。 - Wade
1
只要你想推送到的远程分支是你最近一次推送的分支,你也可以执行 git push -f - Michael
将强制推送所有本地分支。为什么会推送除活动分支以外的任何内容? - Cees Timmerman
1
我尝试过 git push origin some_branch --force,但它总是返回“Everything is up-to-date”消息。但是,git push origin your_branch:some_branch --force 才是我缺少的部分。希望这可以帮到你! - Akhil
我曾经遇到过同样的问题,但是现在我收到了这个消息(特定于Github):remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication. - vtsimp
我遇到了同样的问题,但是目前我收到了这个消息(GitHub特定):remote: 请参阅https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls以获取有关当前推荐的身份验证方式的信息。 - vtsimp

160

你想要强制推送

你基本上想要做的是强制推送你的本地分支,以覆盖远程分支。

如果你想要更详细地了解以下每个命令的解释,请参考下面的详细部分。你基本上有4个不同的选项来使用Git进行强制推送:

git push <remote> <branch> -f
git push origin master -f # Example

git push <remote> -f
git push origin -f # Example

git push -f

git push <remote> <branch> --force-with-lease

如果你想要更详细的解释每个命令,那么请看下面的长答案部分。
警告:强制推送将用你推送的分支状态覆盖远程分支。在使用之前,请确保这是你真正想要做的,否则可能会覆盖你实际想要保留的提交。
强制推送细节
指定远程和分支
你可以完全指定特定的分支和远程。-f标志是--force的简写形式。
git push <remote> <branch> --force
git push <remote> <branch> -f

省略分支
当省略分支时,Git会根据您的配置设置来确定分支。在Git 2.0之后的版本中,新的存储库将具有默认设置,以推送当前检出的分支。
git push <remote> --force

在2.0之前,新的存储库将具有默认设置以推送多个本地分支。所涉及的设置是remote.<remote>.pushpush.default设置(见下文)。

省略远程和分支

当远程和分支都被省略时,只有git push --force的行为由您的push.default Git配置设置决定:

git push --force

从Git 2.0版本开始,默认设置为“simple”,基本上只会将当前分支推送到其上游远程分支。远程分支由分支的“branch..remote”设置确定,否则默认为原始仓库。
在Git 2.0版本之前,默认设置为“matching”,基本上只会将所有本地分支推送到远程具有相同名称的分支(默认为origin)。
您可以通过阅读“git help config”或git-config(1)手册页面的在线版本来了解更多“push.default”设置。
使用“--force-with-lease”更安全地进行强制推送
使用“lease”进行强制推送可以在远程存在您未预期的新提交时(从技术上讲,如果您尚未将其获取到远程跟踪分支),使强制推送失败。这对于您不想意外覆盖其他人的提交(您甚至还不知道)而只想覆盖自己的提交非常有用。
git push <remote> <branch> --force-with-lease

你可以通过阅读以下任何一篇文章来了解更多关于如何使用--force-with-lease的详细信息:

  • {{link1:git push文档}}
  • {{link2:Git:如何忽略快进并将原始[分支]还原到较早的提交?}}

2
你说得没错,但这种方法真的只应该在特殊情况下使用。 - Scott Berrevoets
1
@ScottBerrevoets:“我更喜欢推送我已有的内容并让其覆盖远程内容,而不是集成它。” 我给了OP他所要求的东西。 - user456814
2
我知道,但是楼主可能不清楚这样做的后果。你在技术上回答了问题,但我认为警告不要这样做也是必要的。 - Scott Berrevoets
1
@ScottBerrevoets 我正在尝试让版主将我的答案合并到规范中,因为我提到了新的 --force-with-lease 选项 ;) - user456814
1
FYI:合并自http://stackoverflow.com/questions/24768330/git-push-is-rejected-but-i-dont-want-to-integrate - Shog9
显示剩余3条评论

37

另一种避免强制推送可能会对其他贡献者造成问题的选项是:

  • 将您的新提交放入专用分支中
  • 将您的master重置为origin/master
  • 将专用分支合并到master,始终保留来自专用分支的提交(意味着在master顶部创建新修订,这些修订将镜像您的专用分支)。
    请查看“使一个分支像另一个分支的git命令”以获取模拟git merge --strategy=theirs的策略。

这样,您可以将主分支推送到远程而无需强制任何操作。


结果与“push -force”有何不同? - alexkovelsky
9
任何强制推送都会重写历史记录,迫使其他使用该代码库的用户重置自己的本地代码库以匹配新推送的提交。这种方法只创建新的提交,不需要强制推送。 - VonC
1
我建议您在回答中添加一个标题:“您不想强制推送” :) - alexkovelsky
@alexkovelsky 好观点。我已相应地编辑了答案。 - VonC

23

适用于我:

git push --set-upstream <remote> <branch> -f

13

git push -f有一定的破坏性,因为它会重置团队中其他成员所做的任何远程更改。一个更安全的选项是

git push --force-with-lease

--force-with-lease的作用是只有当分支处于预期状态时才更新它,也就是说没有人在上游更新过该分支。实际上,这是通过检查上游引用是否符合我们的期望来实现的,因为引用是哈希值,并隐式地将其父节点链编码为值。

您可以告诉--force-with-lease要检查什么,但默认情况下将检查当前的远程引用。实际上,这意味着当Alice更新她的分支并将其推送到远程存储库时,指向该分支头的引用将被更新。现在,除非Bob从远程进行拉取,否则他本地对远程的参考将过时。当他使用--force-with-lease进行推送时,Git将检查本地引用与新的远程引用,并拒绝强制推送。 --force-with-lease实际上只允许您强制推送,如果在此期间没有其他人向远程推送更改。它相当于带着安全带的--force


5
// make sure your local branch is up to date
git checkout fix-build
git pull origin fix-build

// push your local branch to overwrite remote branch 'main'
git push -f origin fix-build:main

提示:对我来说,被接受的答案不起作用。我不确定是由于Git版本的原因。


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