我工作的公司一直在尝试使用三个主要分支(开发,测试版,主版)和个别功能分支的Git工作流程。这涉及将特征分支合并到“开发”中。和' beta'彼此独立,然后定期合并β'进入' master'发布。
问题:当我们将功能分支合并到' develop'时,它似乎会影响功能分支的提交历史记录,因此当我们尝试将同一分支合并到' beta&#时39;它还将包括来自' develop'的所有提交,这不是我们想要的。
有谁知道这里发生了什么?是否可以将分支合并到另外两个分支而不包含任何不需要的提交?我们工作流程的哪些变化可以防止这种情我知道没有代码示例或任何内容,但它不是那种类型的问题,我不确定如何提供更多有用的信息。
谢谢!
答案 0 :(得分:4)
在一个基本意义上,合并操作并不会影响任何分支。 (它当然会创建一个新的提交,它以通常的方式影响该分支。)Git的诀窍是保持以下五个同时存在的想法:
Git中最重要的是提交及其父链接。分支名称大多只是分心(但请参见第2点和第3点)。
分支名称只是特定提交的名称,我们称之为该分支的提示提交。
在进行新提交时,Git将当前提交作为其提交写入新提交。 1 如果新提交有多个父提交(参见下一点),则当前提交变为它的第一个父级。无论如何,Git会更新branch-name以指向新提交。这就是分支"成长"。
合并提交是一个包含两个(或更多)父提交的提交。这是"合并为名词",就像它一样。
进行合并的行为 - 我指的是合并提交 - 涉及执行三向合并操作,然后进行新的提交像往常一样,除了新提交有两个(或更多)父母。 "额外"父母是合并的提交。 2
合并操作 - "合并为动词" - 使用通过上述五点构建的历史记录。 Git发现了三个提交:
HEAD
。 (这很容易。)git rev-parse
的参数的任何ID git merge
。分支名称只是找到分支提示。任何两个提交的合并基础被宽松地定义为"图表重新组合的(第一个)点#34;:
...--o--*--o--o--o <-- branch1
\
o--o--o--o <-- branch2
名称branch1
指向顶行的提示(最右边)提交。名称branch2
指向底线的提示提交。这两个提交的合并基础是标记为*
的。 3
为了执行合并操作,Git然后在两个提示上区分(如在git diff
中)合并基础提交*
,给出两个差异。 Git然后组合差异,每个变化只复制一个副本:如果你(在branch1
上)和他们(在branch2
上)将单词color
改为colour
README
,Git只需更改一次。
存储在工作树中的结果源将成为合并提交的树。请注意,到目前为止,我们是将branch2
合并到branch1
还是branch1
合并到branch2
并不重要:我们将获得相同的合并基础,并且相同的两个提示,因此得到相同的两个差异,并以相同的方式组合这两个差异,以达到相同的工作树。但是现在我们用它的两个父母进行实际的合并 commit ,而现在它对我们所依赖的分支很重要。如果我们在branch1
,我们会在 branch1
上进行新提交,并推进名称branch1
:
...--o--o--o--o--o---M <-- branch1
\ /
o--o--o--o <-- branch2
新的合并提交有两个父母:一个是branch1
的旧提示,另一个是branch2
的提示。
因为我们现在有了一个新图表,后来的git merge
会找到一个新的合并基础。让我们说我们在两个分支上再做几次提交:
...--o--o--o--o--o---M--o--o <-- branch1
\ /
o--o--o--*---o--o--o <-- branch2
如果我们现在要求合并两个分支,Git首先找到基础。这是两个分支上的提交,最接近这两个提示。我再次将此提交标识为*
,并查看它的位置:它是以前作为branch2
提示的提交,当我们进行合并时。 / p>
请注意,无论我们进行合并的方式如何,情况仍然如此。
然而,我们进行实际的合并提交至关重要。如果我们使用git merge --squash
,不进行合并提交,我们将不获取此类图表。同样重要的是,任何一个分支机构都没有“重新定位”和“#34;合并后,由于git rebase
通过复制提交工作,git merge
基于提交标识和后续父指针工作。任何副本都是不同的提交,因此任何旧的提交都不会指向新的复制提交。 (在合并点之后重新提交可以在这些图中向右提交;但是,复制左边的提交是不行的。)
如果您不禁止git merge
进行快速前进&#34;操作,git merge
也可以跳过进行合并提交,而只是移动分支标签。在这种情况下,两个分支标签 - 您刚刚移动的标签和您要求合并的标签 - 最终指向相同的提交。一旦发生这种情况,就无法解开&#34;解开&#34;两个分支,除了将标签移回去。要阻止git merge
执行此快进而不是实际合并,请使用--no-ff
。
这是一个快进&#34;合并的例子。 (在引号中,因为没有实际的合并)。我们像往常一样使用分支分支开始 - 但当前分支branch1
上没有提交, 其他分支,branch2
:
...--o--* <-- branch1
\
o--o--o <-- branch2
如果坐在branch1
上,我们运行git merge branch2
- 请注意缺少--no-ff
- Git会注意到不需要实际合并。相反,它会做一个标签&#34;快进&#34;操作,向前滑动名称branch1
,直到它符合branch2
上的提示提交:
...--o--o
\
o--o--o <-- branch1, branch2
这张图无处可记录任何&#34;分离&#34;在两个分支之间,所以我们不妨理清纠结:
...--o--o--o--o--o <-- branch1, branch2
直到我们对branch2
进行新的提交:
...--o--o--o--o--* <-- branch1
\
o <-- branch2
这没有什么错误,但请注意现在不可能告诉我们提升的三个提交&#34;第一排被合并。
1 这适用于常规git commit
和git merge
,但不适用于git commit --amend
。 &#34;修改&#34;提交的变体像往常一样进行新的提交,但不是将当前提交设置为新提交的父级,而是设置当前提交的父级作为新提交的父母,他们(就像他们中的许多人一样,甚至可能根本就没有父母)。效果是将当前的提交推到一边,使得似乎提交已经改变,而事实上旧的提交仍然在存储库中。
2 超过两个父母的案例被称为&#34;章鱼合并&#34;我们可以在这里忽略它。 (对于重复的成对合并,它无法做任何事情。)
3 在复杂的图表中,可能存在多个这样的&#34;第一点&#34;。在这种情况下,所有最低共同祖先节点都是合并基础,对于Git,-s strategy
合并策略参数决定如何处理这种情况。 (当然,还有-s ours
策略,它忽略了所有其他提交,并且完全绕过了三向合并代码。但我在这里假设正常合并。)
答案 1 :(得分:1)
听起来有一个pull
是从功能分支完成的。这是在您的功能分支中显示的最常见方式之一。
但作为一般惯例,建议采用以下步骤,
在开始工作时结帐基于关闭的新功能分支 发展。
完成工作并在功能分支上提交所有内容。
执行git pull --rebase origin develop
以确保
功能分支已准备好进行合并。
查看开发分支。
执行git pull --rebase origin develop
并确保您的本地人
发展已更新。
执行git merge <feature branch name>
这应该是一种万无一失的做法。