为什么git无法推动原点

时间:2017-01-18 20:07:09

标签: git

我有一个流程,可以在实时环境中进行本地更改并将其合并到开发分支(因此开发人员可以使用它们。)

这个过程就像这样 - 在实时目录中(这是一个主人的结账)

git fetch
git add -A
git checkout -b hotfix
git commit -m"Hotfix of live changes"
git fetch . hotfix:develop
git push origin develop

但推动收益率:

$ git push origin develop
To git@gitlab.[...]:group/repo.git
 ! [rejected]        develop -> develop (non-fast-forward)
error: failed to push some refs to 'git@gitlab.[...]:group/repo.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

我不明白为什么我的本地发展背后是原点发展。

使用git fetch。修补程序:开发基于我从本文中理解的内容。 (对我来说很重要的是我不会在这里检查发展。) Merge, update, and pull Git branches without using checkouts

总是更多地学习git ...: - )

2 个答案:

答案 0 :(得分:2)

好的,根据评论,实际的顺序是:

1   $ git checkout master
2   <some number of edits to various files>
3   $ git fetch
    [fetch messages occur here]
4   $ git add -A
5   $ git checkout -b hotfix
    [checkout message occurs here]
6   $ git commit -m"Hotfix of live changes"
    [commit output occurs here]
7   $ git fetch . hotfix:develop
    [more git fetch messages here]
8   $ git push origin develop
    [this step fails]

我添加了$命令提示符,左侧有一些数字用于标识各个步骤。除了第8步,我还假设所有步骤都成功。

在第1步中,您的索引和工作树与存储库中分支master的最尖端提交同步。但是master的提示提交不需要与分支develop的提示提交有任何关系,当我们进入步骤7和8时,这将变得很重要。(当我们进入第7步时,我会添加一些关于我们可以从其成功中推断出来的细节。)

此外,我们对其他 Git存储库中的内容一无所知,而是origin。据推测,您的master在某种程度上与他们的master相关,甚至可能是同步的。

现在,在第2步中,多个不同的开发人员混淆了工作树。 索引仍匹配master的提示,但工作树不同。顺便说一句,这一步并不是一种好的做法,因为事实上我们不知道谁做了什么:&#34;多个开发人员做了什么。&#34;我们将(通过Git的机制)能够找出总计&#34;事物&#34;,而不是谁做了什么部分 - 或者是最重要的部分,为什么他们做了那些事。

在第3步中,您让Git通过存储在远程名称origin下的URL联系处理其他存储库的Git。这将获得他们拥有的任何新提交和标记,以及使这些提交和标记完整和可用所需的任何其他数据。它会更新您的Git的origin/* 远程跟踪分支,现在您的 origin/masterorigin/hotfix(如果有的话)一个hotfix)和origin/develop匹配他们的 masterhotfix(如果有的话)和develop

再次,&#34;他们&#34;第3步是其他存储库,由另一个Git处理,在系统上以名称origin存储的URL处。 他们也是在步骤8中拒绝您git push的人,因此&#34;他们拥有的&#34;非常关键。您认为此步骤3非常重要,除非我们再也没有提及这些origin/*远程跟踪分支机构!

现在我们继续第4步,git add -A。这会将工作树中的所有文件复制到索引中。 (我们正在我们的存储库中工作;&#34;他们&#34;在步骤3和8中重新回到后台,而唯一的&#34;他们&#34;离开了各种开发人员。)我们不知道在第2步中修改了文件的人,或者他们的意图是什么,但我们可以使用Git将更新的索引与HEAD提交进行比较。

从逻辑上讲,将此步骤与步骤5交换会更有意义,尽管效果将完全相同。

现在在第5步中,我们创建了一个名为hotfix的新分支。这个新分支指向我们已经在同一个提交,即分支master的提示,我们自第1步以来没有任何改变。git checkout 不触摸索引或工作树中的任何内容。它只创建一个新分支并将我们放在该分支上。新分支指向master指向的相同提交哈希,因此,如果,现在,我们运行:

$ git rev-parse master; git rev-parse hotfix

我们将看到两次相同的哈希ID。 1 或者,如果我们将提交绘制为图形,我们可能会看到如下内容:

...--o--o--*   <-- master, HEAD->hotfix

其中*是当前提交,而o系列是分支master上的先前提交,现在也在分支hotfix上。

我们仍然不知道我们自己的develop点在哪里,更不用说origin/develop,因为我们没有采取任何步骤。

1 git rev-parse表示&#34;解析修订版&#34;,即将其转换为提交ID。每个分支或标记名称只标识一个特定提交。当您将它们添加到分支时,分支名称只具有移动的特殊属性以容纳提交。请注意,它们通常会向前移动 ,这就是“快进”的概念。来自。

我们现在转到第6步,进行新的提交。像往常一样,新提交是根据索引的内容进行的,我们在步骤4中设置该索引以匹配工作树的内容。 (交换步骤4和5会更有意义:首先创建新分支,然后更新索引。但只要两个步骤都成功,我们使用的顺序并不重要。)由于我们当前的分支现在是hotfix,我们最终会得到这个图形图:

...--o--o--o   <-- master
            \
             *   <-- HEAD->hotfix

现在的提交现在是我们刚刚提出的新提交,它完全在hotfix上。 master上的之前提交仍然在master,并且也在hotfix上(提交在所有指向它们的分支上,即使是间接的)

请注意,新提交的消息是&#34;实时更改的修补程序&#34;,这不是非常有用。我们可以git show提交将其与之前的(master}提交进行比较,但是我们不会告诉我们做出这些更改,更不用说为什么。比较例如日志消息:

fix special case hit-counter problem

When viewing a page that fribbles a kravitz, if the weebly
area of the jitterbox has glubiframes, the page hit-counter
increments by 3 instead of 1.  We now account for the kravitz
fribbling so that the second adjustment is -1, so that the
total hit counter adjustment is 1 instead of 3.

这不仅告诉我们为什么 git show在与kravitzes有关的事情中向我们展示-1而不是+1,它告诉我们问题得到解决。如果此修复程序引入 new 问题,我们知道从哪里开始查找。

我们现在转到第7步。这再次运行git fetch,但我们自己的Git现在不会连接到另一个Git,而是播放&#34;互联网电话&#34;连接,将提交从我们自己的存储库复制到我们自己的存储库。不需要实际复制,因此唯一的做法是更新引用 - 分支名称,在我们的例子中 - 由 refspec 参数指示,在本例中为hotfix:develop

如果第7步成功,那就会告诉我们很多关于develop之前的位置。此特定git fetch命令仅在&#34;快进&#34;中移动分支名称。时尚。这意味着我们可以重新绘制&#34;之前&#34;图有点。一定看起来像这样:

...--o--o--o   <-- develop, master
            \
             *   <-- HEAD->hotfix

或:

...--o--o   <-- develop
         \
          o   <-- master
           \
            *   <-- HEAD->hotfix

这样标签develop可以简单地向前滑动&#34; (如有必要,可以关闭),以便在git fetch步骤之后,它指向与<{1}}相同的相同的提交:

hotfix

如果&#34;之前&#34;图片有...--o--o--o <-- master \ * <-- develop, HEAD->hotfix 指向某个尚未在develop上的提交,我们会得到同样的&#34;拒绝 - 非快进&#34;我们在第8步中得到的错误。

我们hotfix远远并不重要,只是因为它在某个地方&#34;背后&#34; develop。它能够以纯粹向前的方向(向右,在这些图形图中)移动,可能非常快,以便跳过许多提交,指向与hotfix相同的提交。

但重要的是,我们仍然不了解hotfix

现在我们继续步骤8,实际上失败了。在这里,我们的Git调用与第3步中相同的其他Git。但是,这一次,我们的Git将我们的提交发送给他们,而不是将他们的提交交给我们。 (因此origin/develop代替push。)我们所拥有的一个新提交是我们在步骤6中添加的提交,因此我们发送的提交是一次

在发送了提交后,我们会要求他们将他们的 fetch设置为指向我们刚发送的新提交develop

他们说不。

他们说“不”的原因是他们,此操作是快进。现在我们已经向他们发送了我们的提交*,让我们一起猜测他们在他们的图表中的内容。它必须看起来像这样 - 我们无法确定,无需转到他们的系统并在他们的仓库上运行*命令,但我们可以做出相当不错的猜测:

git log --graph

如果他们要将 o <-- develop / ...--o--o--o <-- master \ * <-- [proposed develop] 移动到指向我们发送的新提交develop,他们将的提示处输掉提交 *。可能会有多个此类提交,但肯定至少有一个。他们必须将develop 向后移到这些提交上,才能到达我假设的develop,然后转发到{{1} }}。如果没有至少一次此类提交,他们会接受我们的提案,并将master指向我们刚发送的新提交*

现在,剩下的问题是:我们如何解决这个问题?有很多选择,但最重要的可能是完全停止使用第2步:-)因为第6步实际上是很糟糕的做法。但是如果你还不能这样做,那么你将需要进行真正的合并或重组,将新的提交(仍然标记为develop的提交)与他们自己的提示结合起来{ {1}}。

为此,您需要一个新的存储库,或者至少需要一个新的工作树(请参阅the git worktree documentation)。我们在这里说你选择使用新的存储库。您可以*现有存储库,也可以*现有存储库中 new 分支的现有提交。例如,要将本地develop提交推送到git clone上的新分支,请将步骤8替换为:

git push

(其中develop是尚未用作分支或标记名称的名称)。假设我的他们的存储库中的内容图表是准确的,这将产生:

origin

现在,在其他系统上,您可以git push origin develop:newbranch 各个分支并合并它们或者重新定义一些提交或其他任何内容。

我们可能还会注意到,在上面的八个步骤中,步骤3并不是非常有用,因为它现在是正确的。它会更新实时服务器上的存储库中的newbranch o <-- develop / ...--o--o--o <-- master \ * <-- newbranch ,但之后我们永远不会执行这些更新。我们不妨跳过它。如果我们不是直接在实时服务器上开发 - 我们不应该只是git checkoutorigin/master以及origin/develop或者git fetch我们在开发机器上需要的任何东西,构建并测试它,然后将结果发送到某个地方(可能是测试系统,然后再将它发送到最终服务器进行实际部署)。

答案 1 :(得分:0)

这是因为你的HEAD没有与原点干净地合并。换句话说,有人推送了不属于本地历史记录的更改,因此您需要在再次推送之前集成这些更改。 git pull并解决冲突应该这样做。

请参阅git的提示:

hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.