github - 在没有额外提交消息的情况下将多个功能分支合并到 master 中?
问题描述
假设你有一个 master 分支:
A--B--C
特征 1 分支:
A--B--C--D
功能 2 分支:
A--B--C--E
当我们git merge Feature1
进入 master 时,它合并得很好,但是当尝试合并 Feature2 时,我们会看到 vi 要求我们输入合并的提交消息。有没有办法合并这些分支而无需额外的合并提交?除了功能提交之外,它们与 master 共享相同的历史记录。
master 上的最终历史记录应如下所示:
A--B--C--D--E
取决于哪个提交日期(D 或 E)是第一个
解决方案
背景
- 在 git 中,历史是通过记录每个提交的父级来建立的——通常,“正常”提交有一个父级,“合并提交”有两个父级,但实际上可以有任意数量的父级,包括零。
- 每个提交都由其内容和元数据的哈希标识 - 包括提交者和时间,以及它的父级列表。如果没有获得新的提交哈希,您将无法更改该数据的任何部分,因此所有提交实际上都是不可变的。
- git 中的“分支”实际上只指向一个提交,git从那里向后跟踪历史。
git看到的场景
每个提交指向其父级或父级,每个分支指向一个提交。
请注意,此图上的角度没有任何意义,它们只是将其以 2D 形式显示。
+--D <--(feature1)
v
A <--B <--C <--(master)
^
+--E <--(feature2)
快进合并
默认情况下,git 将尽可能“快进”历史记录。这意味着它只是移动分支指针而不触及任何提交。
这就是你合并第一个特性分支时看到的内容:git 将“master”指针快进指向提交 D,而忽略其他所有内容:
+--(master)
V
+--D <--(feature1)
v
A <--B <--C
^
+--E <--(feature2)
哪个(记住角度没有任何意义)我们也可以这样绘制:
A <--B <--C <--D <--(master, feature1)
^
+--E <--(feature2)
合并提交
当我们来合并第二个特性分支时,我们不能再快进了——将“master”指向提交 E 会丢失提交 D。所以 git 的另一个选择是创建一个“合并提交”——一个提交更多比一位家长。然后,“master”的指针可以指向这个新的提交。
这就是为什么在第二次合并时提示您输入消息的原因,因为 git 正在创建一个新提交(我们称之为“M2”),因此 D 和 E 都将在其历史记录中:
A <--B <--C <--D <--(feature1)
^ ^
| |
| M2 <--(master)
| |
| v
+----E <--(feature2)
我们也可以这样画:
+--(feature1)
v
A <--B <--C <--D <--M2 <--(master)
^ |
| v
+---------E <--(feature2)
请注意,我们也可以强制 git 在之前的合并中执行此操作,使用git merge --no-ff
,这会给我们更多类似的东西:
+----D <--(feature1)
| ^
v |
A <--B <--C <--M1 <--M2 <--(master)
^ |
| v
+----------E <--(feature2)
变基
那么,我们如何创造一个看起来像这样的历史呢?
A <--B <--C <--D <--E <--(master)
从表面上看,我们不能:E 的父级记录为 C,而不是 D,并且提交是不可变的。但是我们可以做的是创建一个新的提交,它看起来像 E,但它的父级是 D。这就是这样git rebase
做的。
在快进功能 1 之后,我们有这个:
A <--B <--C <--D <--(master, feature1)
^
+--E <--(feature2)
如果我们现在git rebase master feature2
,git 将创建一个新版本的所有从 feature2 可访问的提交,这些提交还不能从 master 访问。它将尝试创建应用相同更改的提交,并默认复制提交消息甚至原始作者和时间戳,但它们将有新的父级。
然后它将 feature2 指向这些新的提交;在我们的例子中,结果将如下所示:
A <--B <--C <--D <--(master, feature1)
^ ^
| +--E2 <--(feature2)
|
+--E
原始提交 E 现在无法从任何分支访问,并将被清理。但是现在我们可以避免合并提交:新的提交 E2 处于我们可以再次快进 master 的位置:
A <--B <--C <--D <--(feature1)
^
+--E2 <--(feature2)
|
+ <--(master)
重绘:
+--(feature1)
v
A <--B <--C <--D <--E2 <--(master, feature2)
推荐阅读
- scala - Apache Kafka - 如何等待订阅完成
- reactjs - ReactReduxContextValue 尝试访问调度类型错误
- reactjs - 在 react-native (fetch, axios 等) 中进行一个 API 调用的最佳方法?
- android - 如何在 Kotlin 中接收和解析 HTTP Json 文件
- python - 使用 matplotlib 在日志图中设置 yaxis 标签
- angular - 拖放表中的行而不交换
- angular - 某些打字稿库中使用的“@”前缀是什么意思
- kubernetes-helm - “helm list --all”的输出为空
- excel - 返回带有标题的已过滤 Excel 表格
- android-service - Android服务需要定期上网