git push和git push -f之间的区别

6
请问有人可以帮我解释一下git push和git push -f之间的区别吗?我不知道哪个是推送文件到Github上所推荐的方式。

3
git help push 命令会提示:"通常,该命令会拒绝更新一个不是本地引用的祖先的远程引用,以覆盖它。[...] 此标志禁用这些检查。" - Arnaud Denoyelle
3
更明确地说,如果有人在你之前在同一个分支上推送了一些提交,那么你不能推送代码,因为Git无法猜测如何解决冲突。使用 git push -f 命令会撤回你同事的提交并用你的提交替换整个历史记录。这种方式不应该被使用。 - Arnaud Denoyelle
4
每次您使用 -f 选项,就会有一只小猫死去。不要使用它。没有例外。 - Andrejs Cainikovs
2
我看到了一些不良建议委员会的人在大肆活动。他们已经学会在评论中推销自己的产品,以免因此失去声誉。聪明。-f选项完全有其目的,与“撤回同事的提交”无关,是否使用它(即是否值得成本)是团队政策问题。 - Mark Adelsberger
3
“错误建议委员会”?选项“-f”的唯一目的是重写远程历史记录。如果必须使用它,说明你已经犯了某些可怕的错误,比如意外推送了你妻子的裸照。 - Andrejs Cainikovs
显示剩余2条评论
3个回答

16

git push -f 简写于 git push --force。当你在推送代码时改变了当前仓库的历史记录,使得普通的 git push 被 Git 拒绝时,可以使用它强制推送。(编辑: 不过这也只是故事的一半。强制推送也可以让你覆盖别人在你上一次拉取之后推送的提交)。使用场景:

  1. 你的仓库当前在提交 A 处。你在本地进行修改并提交 (提交 B)。
  2. 你将 B 推送到远程仓库。现在两者都在 B 处。
  3. 你决定再次进行修改,并用提交 B' 替换提交 B。
  4. 你想将提交 B' 推送到远程仓库。普通的 git push 将不起作用。你可以通过 git push --force 删除远程仓库中的提交 B 并推送 B'。

如果只有你在使用该远程仓库(或者在提交 B' 之间没有其他人进行过拉取),那么这样做是可以的。但是,在 GitHub 上,这不是个好主意。

希望这能帮到你。

(编辑: 你也可以查看GIT 文档 或 GitHub 的 帮助文档)


3
很好的答案,允许我提供一个文档链接 - Pastor Cortes
@Pastør Cortes:非常感谢。请随意将其添加到我的答案中。 - nCessity

8
您可以使用git help [command]来获取每个Git命令的帮助。以下是有关推送以及特别是选项-f的摘录:

-f, --force

通常,该命令会拒绝更新不是用于覆盖它的本地引用的祖先的远程引用。另外,当使用--force-with-lease选项时,该命令会拒绝更新当前值与预期值不匹配的远程引用。

此标志禁用这些检查,并可能导致远程存储库丢失提交;请小心使用。

我制作了这个插图,以便更好地解释它: enter image description here 在步骤1)中,Alice和Bob共享与origin相同的最新历史记录。
然后,Alice添加一个提交并使用git push将其推送(步骤2)。这是有效的,因为提交C具有提交B作为祖先。
然后,Bob在提交B之后在其本地分支上添加了提交D,然后尝试使用git push将其推送(步骤3)。
这是无效的:
  • 在Bob的分支上,D的祖先应该是B。
  • 在Origin上,B已经有一个不是D的后继 => 冲突。
Bob可以(但不应该)使用git push -f来替换origin的历史记录为A-B-D。这很糟糕,因为它会搞乱Alice的历史记录,其中B的后继仍然是C。
Bob应该在本地获取提交C(使用git fetch),然后在本地解决冲突(使用git mergegit rebase),然后推送结果(使用git push)。

1
你的图表没有反映出 force push 的主要用例。(值得一提的是,我认为它并不像你打算的那样清晰明了。)它说明了为什么不应该使用 -f 进行 常规 推送,但完全忽略了 -f 实际上是一个功能的原因。 - Mark Adelsberger

1
区别在于 git push -f 命令会强制推送。具体来说:
推送是请求将远程引用更新为本地引用的状态。默认情况下,只有本地引用是远程引用的后代(也就是说,如果通过父指针从本地引用可以到达远程引用),才允许这样做。这是分支增长的正常方式,它允许其他用户将添加的提交解释为建立在他们已经在分支上看到的提交之上的新版本。例如,如果您有:
A -- B -- C <--(origin/master)
           \
            D -- E <--(master)

你可以推送这个,每个人都会解释为“DE被添加到master”(或多或少)。
有时候,您可能希望以违反此规则的方式移动分支引用。通常,这意味着您已编辑了历史记录(但请参见下面的警告)。假设您有:
A -- B -- C <--(origin/master)
 \
  BC -- D <--(master)

在这张图片中,你可能将BC合并成一个提交,然后添加了提交D。默认情况下,git将拒绝尝试这样的推送;选项-f(或--force)告诉它尝试。请注意,服务器可能配置为拒绝强制推送。
这就带来了我提到的警告:如果你进行了强制推送,从引用历史记录中删除了提交(BC),并且任何其他人拥有一个克隆版本,其中相应引用的历史记录包括已删除的提交,则他们将处于错误状态(如果他们采取“错误的操作”来恢复,则会撤销你的工作)。因此,重要的是与其他受影响的用户协调任何历史编辑。有关更多信息,请参见git rebase文档中的“从上游rebase恢复”。

所以回答你的问题:以上是它们的不同之处,推荐的做法是通常只使用git push,仅在(a)有特定原因需要时使用git push -f,并且(b)得到受影响人员的同意。


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