我有一个流程,可以在实时环境中进行本地更改并将其合并到开发分支(因此开发人员可以使用它们。)
这个过程就像这样 - 在实时目录中(这是一个主人的结账)
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 ...: - )
答案 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/master
,origin/hotfix
(如果有的话)一个hotfix
)和origin/develop
匹配他们的 master
,hotfix
(如果有的话)和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 checkout
和origin/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.