当我执行git pull,添加,提交,推送时,会发生这种情况
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'http://foo:8080/tfsdev/foo/_git/Development.Services'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
当我添加-ff到git pull时,它会通过。 我认为fastforward是默认的,为什么会发生这种情况?
答案 0 :(得分:10)
当我向git pull添加-ff时,它会通过。我认为fastforward是默认的,为什么会发生这种情况?
你在这里混合了一堆不同的概念......这并不奇怪,因为git pull
也混合了一堆不同的概念,试图方便主要是导致混乱。 (好吧,偶尔也方便。:-))
使用git pull
通常会运行git merge
,这通常会执行快进而不是合并。这样,您的分支机构就可以了解从远程调用的任何git pull
(通过git fetch
),以便您添加的提交,也只会添加到(不会替换或删除) - 来自)他们的承诺。但git push
不与git pull
相反,它与git fetch
相反:不做任何事情合并。
当您执行pull
+做东西(提交或其他)+ push
序列时,您正在与其他也在进行拉提交推送序列的人竞争。谁赢了,就得推。这部分真的很简单。当你没有获胜时,问题就出现了!
当你是唯一一个跑步的人时,很容易赢得这场比赛。如果没有其他人在推动这个分支,你将永远赢得比赛。这里发生的事情是你不是唯一一个跑步的人,而你输了。
遗憾的是,完整的答案很复杂,而且你没有充分展示能够回答这个具体案例的情况。所以,让我们来看看究竟发生了什么。
如果git status
说on branch master
,或git branch
打印* master
,则您当前的分支为master
。大多数Git命令适用于您当前的分支,git pull
在这里也不例外。
git pull
命令只运行另外两个Git命令。第一个是始终 git fetch
。第二个,你可以改变。
git pull
运行git fetch
第一个git pull
运行的命令是git fetch
。它运行有限的 git fetch
,告诉git fetch
仅为您的当前分支提供所需的提交和其他项目。如果您只是运行git fetch
,Git会带来所有内容,这可能会花费更长的时间,但这意味着您可以与所有内容保持同步。
git fetch
命令是关于使用当前分支的常用Git规则的例外。在某些情况下,它仍然会查看您当前的分支,但git fetch
通常更新您的远程跟踪分支。在大多数情况下,您将只有一个名为origin
的所谓远程,并且正在运行git fetch
会带来origin
的所有内容并更新您的origin/master
},origin/develop
和其他origin/
分支。这些是名为origin
的远程跟踪分支。
因此,如果您自己运行git fetch
,它将更新您的所有origin/*
远程跟踪分支机构。如果您运行git pull
,它将以基于您当前分支的方式更新仅一个的方式运行git fetch
。这些更新始终是安全的:它们将新的提交带入您的存储库,这对您的存储库中的所有现有提交都没有影响。
为了让人感到困惑,git fetch
将所有更新写入名为FETCH_HEAD
的文件,您将在the git fetch
documentation中看到该文件。但它还更新你的远程跟踪分支,除非你有一个非常旧版本的Git(早于Git版本1.8.4)。对于那些使用古代Gits(1.7.x)的人来说,git fetch
的所有内容origin
都会对其进行更新,但由git pull
运行的内容不会更新。
git pull
运行其他东西这里的事情有点乱。 git pull
的第二部分是 git merge
或git rebase
。默认值为git merge
,即使git rebase
通常更好。 您必须提前选择git pull
应使用哪个命令。但您使用哪个 ?要确定的唯一方法是查看即将发生的事情。如果您选择新的提交,可以使用git log
和其他Git命令查看它们。
要了解进入的内容,您必须将其引入。这是git fetch
的作用。 git fetch
步骤引入新提交,安全,将它们安全地置于这些远程跟踪分支之后。 现在您可以决定是合并还是改组。
git pull
命令可让您在之前决定。因此,选择你想要它做哪一个 - 合并,或者rebase-and pull,然后它将获取然后执行。要使其执行rebase,请运行git pull --rebase
,或者设置当前分支以使git pull
默认执行此操作。
(此设置为每个分支,因此您必须为每个分支设置它。还有一个配置条目告诉Git设置" rebase模式"自动为Git创建的每个分支 - 但在我看来,只需自己运行git fetch
,然后自己运行第二个命令就可以了。这让你有机会看你所得到的东西,以及在出现问题时不那么容易混淆。)
git merge
我们假设git pull
运行的第二件事是git merge
。此 可以在您当前的分支上运行。但git merge
本身有点复杂。
当您合并时,您通常通过分支名称选择一些提交,并且经常通过远程跟踪分支名称(如origin/master
) - 并要求Git找出几个事项。此合并的目标很容易说明:合并将您完成的工作与其他人的工作相结合,以使用这两组工作进行新的提交。
要弄明白你做了什么,以及他们(无论他们是谁)做了什么,Git必须找到合并基础。此合并基础或多或少是您和他们共享的第一个提交。这意味着是时候绘制提交图的一部分了。这是一些可能性。
...--o--* <-- master
\
o <-- origin/master
o
代表提交,右边有更新的提交。我已使用*
标记了合并基础提交。在这里,您的master
指向合并基础提交,origin/master
指向较新的提交。
在这种情况下,git merge
能够做到这一点&#34;快进&#34;事情。也就是说,因为合并基础 是master
的提示,所以不需要实际的合并。 Git只需向下滑动名称主服务器,以便它指向与<{1}}相同的相同提交:
origin/master
现在我们也可以理顺这条线,并且只有:
...--o--o
\
o <-- master, origin/master
如果您现在运行...--o--o--o <-- master, origin/master
,基本上没有任何反应,因为您的结尾没有任何新内容。最后一次提交是您已经从git push origin master
获得的。
但是,如果我们有这个呢?
origin
在这里,Git必须进行真正的合并。 Git将提交...--o--*--o <-- master
\
`-o <-- origin/master
与您的*
提交(最右边的最右边master
)和o
提交(底线上的origin/master
)进行比较)。也就是说,Git运行o
两次。然后它尝试组合两组更改,如果成功,则进行&#34; merge commit&#34;的新提交。味:
git diff
此提交已准备好...--o--*--o--o <-- master
\ /
`-o <-- origin/master
到git push
,在与其他任何人同时尝试origin
到git push
的竞赛中。
你甚至可以从头开始:
origin
现在没有任何东西可以合并:名称...--o--o--* <-- master, origin/master
和名称master
都指向同一个提交,因此合并基础提交已经是{{1 (以及origin/master
)。现在没有任何东西可以融合,在无所事事之后,也没有什么可以推动的。你甚至不必尝试比赛,更不用说赢得比赛了。
现在您的master
和origin/master
排队了,您可以进行新的提交。当你这样做时,你的 master
将会超过&#34; origin/master
:
master
(我将底部origin/master
向下移动,以便我可以指向...--o--o o--o <-- master
\ /
o <-- origin/master
。)
o
做什么我在上面提到origin/master
与git push
不相反;它更像是push
。
当你运行pull
时,你的Git会调用其他一些Git。在这种情况下,这就是远程fetch
上的Git。然后它会移交您已经提交的任何新提交和请求:&#34;请将您的git push
设置为此最新提交。&#34;
换句话说,我们要求他们的 Git更改他们的 origin
- 我们调用master
- 匹配我们的 master
。
看看上面的那些图纸。当我们执行快进时,我们将origin/master
移动到我们已从master
获取的提交。当我们什么也没做,我们什么也没做。在任何一种情况下,都没有新的提交:没有什么可以打扰的。无论如何我们做推送,我们会对另一个Git说:&#34;这里没有什么新内容,但请设置master
以便它指向对于这个特定的提交,就像我们一样。&#34;
如果我们做了做了一次新的提交 - 正如我们对合并确实做了一些事情,或者我们做了新的提交 - 我们做为他们提供了新的东西。我们会将他们的新提交交给他们,然后让他们将origin/master
设置为与master
相同。
当然,我们也会在推动其他人的比赛。
如果没有其他人 赢得推送比赛,他们的master
仍然会匹配我们的master
。我们要求推动,好吧,看看上面的图纸。移动master
(我们的origin/master
的名称)前进以匹配我们的origin/master
,为什么,这是我们之前看到的那些快速前进操作之一!
如果推送会进行快进,通常会成功。
但是如果其他人赢了怎么办?如果,在我们运行master
和master
之后,我们花了一些时间做出提交,同时还有其他人进来并推到我们面前呢?
好吧,现在我们有了这个:
git fetch
但这并不是非常正确,因为他们在他们的 git merge
上有新的提交。 他们有其他人推送的提交。我们需要运行...--o--o o--o <-- master
\ /
o <-- origin/master
并获取它们。让我们这样做,现在 - 现在master
使用我们拥有的新提交 - 更新了我们的git fetch
:
git fetch
现在,为了推动,我们必须合并或重组。我将绘制合并案例。 (请注意,合并基础是最底层的最左侧提交。)
origin/master
如果我们进行此合并,现在我们可以推送,因为现在我们的...--o--o o--o <-- master
\ /
o-----o <-- origin/master
是&#34;快速前进&#34;他们的...--o--o o--o--o <-- master
\ / /
*-----o <-- origin/master
。
当然,在我们合并的同时,我们也在与其他可能试图推动的人竞争。如果我们输掉比赛,我们可能需要再次获取和合并。
(在所有这些情况下,master
可能比master
更好。请参阅其他StackOverflow关于rebase的答案。)