合并 git 中 2 个不同分支中的 2 个同名文件
Merging 2 files with the same name in 2 different branches in git
我目前在名为 branch1
的分支中有一个名为 test1
的文件,该分支是从 master
创建的,另一个名为 test1
的文件位于名为 [=15= 的分支中] 也是从 master
创建的。
如果我合并 master 中的 2 个分支,写在两个文件中的代码会发生什么?
如果您在同一个地方对两个文件进行了更改,将会发生合并冲突。
如果您没有在同一个地方对两个文件进行更改,它将毫无问题地合并(可能在另一个位置发生冲突)。
您可以通过编辑冲突文件、删除提交标记、添加文件并提交来解决冲突。
作为 amer answered(正确),您将在两个合并的 一个 中遇到合并冲突。您将不得不做一些事情来处理合并冲突。做什么取决于你。不过,值得指出的是,为什么 你会得到 一个 合并冲突,而不是两个,以及为什么会发生合并冲突。
Git的合并并不是真正关于分支。这是关于 提交 。大多数 Git 都是关于提交的,git merge
在这里也不例外。
让我们在这里注意提交是什么以及做什么。每个提交都有两部分:它的数据——所有文件的保存快照——和它的元数据,或者关于提交的信息。
保存的快照非常简单:如果您克隆存储库并使用 --no-checkout
,您将得到一个空的 work-tree([=274= 没有可编辑或可用的副本]任何 文件)。然后你选择一些提交——任何地方的任何提交——并告诉 Git 检查那个特定的提交,可能是通过它的原始哈希 ID。现在,您拥有所有文件的副本,就像他们在提交时的样子一样。
一般来说,这就是 git checkout
或 new-in-Git-2.23 git switch
命令的用途:你选择一些提交并说 给我所有文件来自该提交。它们会进入您的 工作树 或 work-tree,您可以在其中查看它们并对其进行处理。您还可以将其他 un-Git-ified 文件放入您的 work-tree,例如编译文件或输出或其他任何内容。这些文件保持 未跟踪(我不会在这里详细介绍,但它们不在 Git 中,它们只是位于您的 work-tree unless/until 你 删除它们)。
提交中的 元数据 记录了诸如谁提交的信息——他们的姓名和电子邮件地址——以及他们提交的时间。这是您在 git log
输出中看到的内容。
不过,有一部分元数据专门针对 Git 本身。每个提交都有一个唯一的哈希 ID,每个 Git 都一致同意:一个哈希 ID 用于 that 提交,而不用于任何其他提交。所以很容易判断你是否有一些提交:你只需将它的哈希 ID 给 Git,你的 Git 要么有它,在这种情况下,它有 that 提交,或者你的 Git 没有它,在这种情况下你必须找到其他一些 Git 帽子有它。
无论如何,每个提交都将其先前或 parent 提交的哈希 ID 作为其元数据的一部分进行存储。大多数提交只有一个。合并提交有点特殊,因为它们有 两个 parent(或更多,但大多数只有两个)。
这些 parent 提交——或 parents,用于合并——是 Git 存储历史的方式。每个快照只是一个快照,但每个快照还说:而我之前的快照是______(用哈希ID填空)。对于合并,这是 firstparent。对于常规提交,它是唯一的 parent(因此也是第一个 parent)。因此,通过回到每个提交的第一个 parent,Git 可以追溯随时间发生的事情。放两张快照:左边是旧快照,右边是新快照,然后比较它们。 What's different? 这种差异告诉您发生了什么:旧版本和新版本之间发生了什么变化。
一旦您了解了有关提交的内容,我们只需要再添加一件事即可使分支正常工作。 在Git中,一个分支名称记录了最新提交的哈希ID,我们希望调用“部分分支的名称”。 主要是这样——这就是分支名称为我们和 Git 所做的事情。它记录了 last 提交。提交本身记录了历史。
因此,给定一系列提交,在一个只有三个提交和一个分支名称的非常小的存储库中,我们有,例如:
A <-B <-C <--master
最后 次提交是 C
。我们使用名称 master
来存储它的实际哈希 ID——这实际上是一些丑陋的 random-looking 字母和数字串,我们永远猜不到。 CommitC
本身存储了较早commitB
的哈希ID,因此C指向B
;提交 B
存储早期提交 A
.
的哈希 ID
提交 A
是特殊的:它根本不指向回,因为它是第一次提交,不能指向更早的提交。这就是 Git 知道 停止 返回的方式:当它不能返回时。
我们可以,给定一个 Git 存储库,进入并查找所有提交,并查看哪些是最后提交的,但是拥有一个可以快速找到它们的名称会更快。当我们开始拥有多个分支时,这一点也变得很重要。让我们从一个大约有八次提交的小型存储库开始:
...--G--H <-- master
现在让我们添加一个新的分支。我们将从让新的 name also select commit H
开始。我们需要一种方法来知道我们正在使用哪个分支,因此我们将特殊名称HEAD
附加到其中一个分支名称:
...--G--H <-- master, feature1 (HEAD)
现在我们将添加一个新的提交,它会获得一些新的 random-looking 哈希 ID,我们将其称为 I
:
I <-- feature1 (HEAD)
/
...--G--H <-- master
当我们添加 new 提交时,Git 自动更新分支名称 以指向新提交。更新哪个分支名称?一个 HEAD
是 attached-to。其他人都留在原地。
现在通过 H
的所有提交都在 两个 分支上,而提交 I
*仅在 feature1
上。让我们再做一次提交,然后创建一个新分支 feature2
select 提交 H
,并开始使用那个:
I--J <-- feature1
/
...--G--H <-- master, feature2 (HEAD)
现在让我们向 feature2
添加两个提交:
I--J <-- feature1
/
...--G--H <-- master
\
K--L <-- feature2 (HEAD)
现在,假设在提交 I
或 J
中,我们创建了一个 new 文件 test1
,但尚未提交 H
。假设在提交 K
或 L
中,我们 还 创建了一个名为 test1
.
的新文件
正在合并
我们现在要将这两个功能合并到 master
中,一次合并一个。没有明显的原因,1 我们将使用 --no-ff
选项:
git checkout master
git merge --no-ff feature1
实现这个。
当我们git checkout master
时,我们将Git指向:
- 提取由名称
master
标识的提交——提交 H
——到我们的 work-tree(以及 Git 的 index,我们不会在这里讨论);和
- 设置我们的 work-tree 匹配,这意味着 删除 文件
test1
,它在提交 L
中——有一个使用该名称保存快照文件——但不在提交中 H
.
所以,现在我们有:
I--J <-- feature1
/
...--G--H <-- master (HEAD)
\
K--L <-- feature2
我们准备好 运行 git merge --no-ff feature1
。
Git 现在发现 三个提交 ,而不仅仅是两个。感兴趣的三个提交是:
我们当前的提交,HEAD
。这真的很容易找到,因为 HEAD
附加到分支名称并且分支名称指向提交,所以 Git 找到提交 H
.
我们命名的另一个提交。这也很简单:我们说过要合并 feature1
。名称 feature1
标识提交 J
。 (看看图就知道了!)
合并基地。合并基础由 提交图 定义,由一个提交到另一个提交的 inter-connections 形成。虽然我们不会详细介绍所有细节,但您可以将其视为 最好的 共享 提交,即 上的最佳提交=274=]两个分支。从 J
开始——根据名称 feature1
找到——我们向后工作;从 H
开始,正如 master
所发现的那样,我们也向后工作。当某些提交在 both 分支上时,这是一个 shared 提交。最新的此类提交——这里没有正确定义 newest,但在大多数情况下很明显——通常是 best 提交。2
在这种情况下,合并基础显然是提交 H
本身。
1我将在此处进行的合并是您在 GitHub 上使用其“合并请求请求”按钮获得的那种。从 Git 命令行,您可以获得更多选项。 --no-ff
选项强制 command-line Git 进行真正的合并,而不是使用它的 short-cut “快进 not-really-a-merge” 选项。
2从技术上讲,Git 所做的是在有向图中找到最低公共祖先 (LCA)。在一棵树中,总有一个well-defined LCA,但是Git的提交图不一定是一棵树:它只是一个有向无环图或DAG .两次提交可能没有 LCA,或者可能有不止一个 LCA,合并对这些情况做不同的事情。
合并,第 2 部分
找到合并基础后,Git现在 运行s 两个 比较两个提交,看看有什么变化 操作。比较 #1 将合并基础与 --ours
提交进行比较,即与 HEAD
进行比较。所以 Git 会做:
git diff --find-renames <hash-of-H> <hash-of-H> # what we changed on master
显然,提交 H
与提交 H
相同。什么都没有改变!
然后,Git 做第二次 diff,看看“他们”(我们)在另一边改变了什么:
git diff --find-renames <hash-of-H> <hash-of-J> # what they changed on feature1
那么merge的作用就是合并这两组变化。在我们更改了一些文件而他们没有更改的地方,Git 接受了我们的更改。他们更改了一些文件,而我们没有,Git 接受了他们的更改。 这些组合更改会应用到 merge-base 快照。 这样,我们保留所有工作并添加他们的工作——但无论我们和他们不同 对某些文件或多个文件进行更改,Git 将显示 合并冲突。
在这种情况下,--ours
diff 是完整的tely empty:我们没有改变任何东西。因此,无论“他们”——实际上,我们 feature1
——做了什么,Git 都会进行这些更改。这包括添加一个新文件 test1
。这种合并进行得很顺利,所以 Git 自己进行新的合并提交。
新合并提交的 第一个 parent 是我们在 master
上的当前提交 H
。新合并提交的第二个 parent 是他们在 feature1
上的提交 J
。我们可以画出来——这里的图没有正确显示第一次提交和第二次提交,但是如果需要的话我们可以记住它,或者询问 Git 关于两个 parent 的问题,看看哪个是第一个, 或者其他什么。
结果如下所示:
I--J <-- feature1
/ \
...--G--H------M <-- master (HEAD)
\
K--L <-- feature2
请注意 other 分支名称是如何移动的:我们仍在 master
,它已移动到指向 M
,并且 feature1
仍然命名为提交 J
和 feature2
仍然命名为提交 L
.
合并冲突
如果我们现在 运行 另一个 git merge
——这次是 feature2
——Git 将再次找到三个提交:
- 当然,我们和他们的提交是提交
M
和 L
。
- 合并基础是最好的共享提交。
看图。 master
和 feature2
都有哪些提交?提交 G-H-I-J-M
全部在 master
—H
上 两种 方式,直接来自 M
的第一个 parent,间接地从 J
到 I
再到 H
通过 M
的第二个 parent——因此 G
有两种方式,等等,但我们真正关心的是 H
和 G
在那里。
同时,feature2
结束于 L
,回到 K
,然后回到 H
。所以提交 H
和 G
都是共享的。不过,提交 H
是 最好的 之一。然后,合并基础再次提交 H
.
Git 将再次 运行 两个 git diff
s,都带有 --find-renames
(检查重命名的文件)并且都从 H
到两个分支提示。所以 Git 将把 H
中的快照与 M
中的快照进行比较,看看我们改变了什么。
我们从 H
到 M
改变了什么?好吧,在 M
中,我们添加了通过比较 H
与 J
得到的所有更改。因此,我们在 feature1
中 更改 的任何文件都在 M
中更改。但是我们还在 I
或 J
中添加了一个新文件 test1
,所以这个 change-set 说 add all-new file test1
.
当我们比较 H
与 L
时,也表示 添加一个 all-new 文件 test1
。所以两个变更集都说要添加一个新文件。
Git 将这种冲突称为 add/add 冲突 。 在 work-tree , Git 只是将两个文件的全部内容作为冲突留给您。您必须以某种方式解决此冲突。你如何去做取决于你。无论您选择将什么放入文件 test1
,您现在都可以 运行:
git add test1
和 Git 将假定文件 test1
中的内容是该冲突的 正确 解决方案。
一定要编辑文件!如果你不这样做,它只是其中有冲突标记,Git 认为这是 正确答案! 可能不是。
一旦您解决了所有冲突,并确定合并结果是正确的——例如,您已经完成了您需要做的任何测试——您可以通过 运行ning 安全地完成合并:
git merge --continue
或:
git commit
(git merge --continue
只是确保您仍在完成合并,然后 运行s git commit
为您服务,所以他们最终会做同样的事情——除非您已经即完成或终止合并。)
Git 现在将进行 另一个 合并提交;我们将其称为提交 N
,并像这样绘制它:
I--J <-- feature1
/ \
...--G--H------M--N <-- master (HEAD)
\ /
K-----L <-- feature2
N
的第一个parent是M
,N
的第二个parent是L
。现在有 三种 种方法可以从 N
到 H
,并且图中的 所有 提交都在 master
.
现在删除名称 feature1
和 feature2
是安全的,因为 Git 可以通过向后查找这些提交——包括 J
和 L
来自提交 N
。如果您想保留直接快速地找到提交 J
和 L
的能力,您 没有 删除名称,但它们不是更长必要,就像它们在合并操作之前一样。
我目前在名为 branch1
的分支中有一个名为 test1
的文件,该分支是从 master
创建的,另一个名为 test1
的文件位于名为 [=15= 的分支中] 也是从 master
创建的。
如果我合并 master 中的 2 个分支,写在两个文件中的代码会发生什么?
如果您在同一个地方对两个文件进行了更改,将会发生合并冲突。
如果您没有在同一个地方对两个文件进行更改,它将毫无问题地合并(可能在另一个位置发生冲突)。
您可以通过编辑冲突文件、删除提交标记、添加文件并提交来解决冲突。
作为 amer answered(正确),您将在两个合并的 一个 中遇到合并冲突。您将不得不做一些事情来处理合并冲突。做什么取决于你。不过,值得指出的是,为什么 你会得到 一个 合并冲突,而不是两个,以及为什么会发生合并冲突。
Git的合并并不是真正关于分支。这是关于 提交 。大多数 Git 都是关于提交的,git merge
在这里也不例外。
让我们在这里注意提交是什么以及做什么。每个提交都有两部分:它的数据——所有文件的保存快照——和它的元数据,或者关于提交的信息。
保存的快照非常简单:如果您克隆存储库并使用
--no-checkout
,您将得到一个空的 work-tree([=274= 没有可编辑或可用的副本]任何 文件)。然后你选择一些提交——任何地方的任何提交——并告诉 Git 检查那个特定的提交,可能是通过它的原始哈希 ID。现在,您拥有所有文件的副本,就像他们在提交时的样子一样。一般来说,这就是
git checkout
或 new-in-Git-2.23git switch
命令的用途:你选择一些提交并说 给我所有文件来自该提交。它们会进入您的 工作树 或 work-tree,您可以在其中查看它们并对其进行处理。您还可以将其他 un-Git-ified 文件放入您的 work-tree,例如编译文件或输出或其他任何内容。这些文件保持 未跟踪(我不会在这里详细介绍,但它们不在 Git 中,它们只是位于您的 work-tree unless/until 你 删除它们)。提交中的 元数据 记录了诸如谁提交的信息——他们的姓名和电子邮件地址——以及他们提交的时间。这是您在
git log
输出中看到的内容。不过,有一部分元数据专门针对 Git 本身。每个提交都有一个唯一的哈希 ID,每个 Git 都一致同意:一个哈希 ID 用于 that 提交,而不用于任何其他提交。所以很容易判断你是否有一些提交:你只需将它的哈希 ID 给 Git,你的 Git 要么有它,在这种情况下,它有 that 提交,或者你的 Git 没有它,在这种情况下你必须找到其他一些 Git 帽子有它。
无论如何,每个提交都将其先前或 parent 提交的哈希 ID 作为其元数据的一部分进行存储。大多数提交只有一个。合并提交有点特殊,因为它们有 两个 parent(或更多,但大多数只有两个)。
这些 parent 提交——或 parents,用于合并——是 Git 存储历史的方式。每个快照只是一个快照,但每个快照还说:而我之前的快照是______(用哈希ID填空)。对于合并,这是 firstparent。对于常规提交,它是唯一的 parent(因此也是第一个 parent)。因此,通过回到每个提交的第一个 parent,Git 可以追溯随时间发生的事情。放两张快照:左边是旧快照,右边是新快照,然后比较它们。 What's different? 这种差异告诉您发生了什么:旧版本和新版本之间发生了什么变化。
一旦您了解了有关提交的内容,我们只需要再添加一件事即可使分支正常工作。 在Git中,一个分支名称记录了最新提交的哈希ID,我们希望调用“部分分支的名称”。 主要是这样——这就是分支名称为我们和 Git 所做的事情。它记录了 last 提交。提交本身记录了历史。
因此,给定一系列提交,在一个只有三个提交和一个分支名称的非常小的存储库中,我们有,例如:
A <-B <-C <--master
最后 次提交是 C
。我们使用名称 master
来存储它的实际哈希 ID——这实际上是一些丑陋的 random-looking 字母和数字串,我们永远猜不到。 CommitC
本身存储了较早commitB
的哈希ID,因此C指向B
;提交 B
存储早期提交 A
.
提交 A
是特殊的:它根本不指向回,因为它是第一次提交,不能指向更早的提交。这就是 Git 知道 停止 返回的方式:当它不能返回时。
我们可以,给定一个 Git 存储库,进入并查找所有提交,并查看哪些是最后提交的,但是拥有一个可以快速找到它们的名称会更快。当我们开始拥有多个分支时,这一点也变得很重要。让我们从一个大约有八次提交的小型存储库开始:
...--G--H <-- master
现在让我们添加一个新的分支。我们将从让新的 name also select commit H
开始。我们需要一种方法来知道我们正在使用哪个分支,因此我们将特殊名称HEAD
附加到其中一个分支名称:
...--G--H <-- master, feature1 (HEAD)
现在我们将添加一个新的提交,它会获得一些新的 random-looking 哈希 ID,我们将其称为 I
:
I <-- feature1 (HEAD)
/
...--G--H <-- master
当我们添加 new 提交时,Git 自动更新分支名称 以指向新提交。更新哪个分支名称?一个 HEAD
是 attached-to。其他人都留在原地。
现在通过 H
的所有提交都在 两个 分支上,而提交 I
*仅在 feature1
上。让我们再做一次提交,然后创建一个新分支 feature2
select 提交 H
,并开始使用那个:
I--J <-- feature1
/
...--G--H <-- master, feature2 (HEAD)
现在让我们向 feature2
添加两个提交:
I--J <-- feature1
/
...--G--H <-- master
\
K--L <-- feature2 (HEAD)
现在,假设在提交 I
或 J
中,我们创建了一个 new 文件 test1
,但尚未提交 H
。假设在提交 K
或 L
中,我们 还 创建了一个名为 test1
.
正在合并
我们现在要将这两个功能合并到 master
中,一次合并一个。没有明显的原因,1 我们将使用 --no-ff
选项:
git checkout master
git merge --no-ff feature1
实现这个。
当我们git checkout master
时,我们将Git指向:
- 提取由名称
master
标识的提交——提交H
——到我们的 work-tree(以及 Git 的 index,我们不会在这里讨论);和 - 设置我们的 work-tree 匹配,这意味着 删除 文件
test1
,它在提交L
中——有一个使用该名称保存快照文件——但不在提交中H
.
所以,现在我们有:
I--J <-- feature1
/
...--G--H <-- master (HEAD)
\
K--L <-- feature2
我们准备好 运行 git merge --no-ff feature1
。
Git 现在发现 三个提交 ,而不仅仅是两个。感兴趣的三个提交是:
我们当前的提交,
HEAD
。这真的很容易找到,因为HEAD
附加到分支名称并且分支名称指向提交,所以 Git 找到提交H
.我们命名的另一个提交。这也很简单:我们说过要合并
feature1
。名称feature1
标识提交J
。 (看看图就知道了!)合并基地。合并基础由 提交图 定义,由一个提交到另一个提交的 inter-connections 形成。虽然我们不会详细介绍所有细节,但您可以将其视为 最好的 共享 提交,即 上的最佳提交=274=]两个分支。从
J
开始——根据名称feature1
找到——我们向后工作;从H
开始,正如master
所发现的那样,我们也向后工作。当某些提交在 both 分支上时,这是一个 shared 提交。最新的此类提交——这里没有正确定义 newest,但在大多数情况下很明显——通常是 best 提交。2
在这种情况下,合并基础显然是提交 H
本身。
1我将在此处进行的合并是您在 GitHub 上使用其“合并请求请求”按钮获得的那种。从 Git 命令行,您可以获得更多选项。 --no-ff
选项强制 command-line Git 进行真正的合并,而不是使用它的 short-cut “快进 not-really-a-merge” 选项。
2从技术上讲,Git 所做的是在有向图中找到最低公共祖先 (LCA)。在一棵树中,总有一个well-defined LCA,但是Git的提交图不一定是一棵树:它只是一个有向无环图或DAG .两次提交可能没有 LCA,或者可能有不止一个 LCA,合并对这些情况做不同的事情。
合并,第 2 部分
找到合并基础后,Git现在 运行s 两个 比较两个提交,看看有什么变化 操作。比较 #1 将合并基础与 --ours
提交进行比较,即与 HEAD
进行比较。所以 Git 会做:
git diff --find-renames <hash-of-H> <hash-of-H> # what we changed on master
显然,提交 H
与提交 H
相同。什么都没有改变!
然后,Git 做第二次 diff,看看“他们”(我们)在另一边改变了什么:
git diff --find-renames <hash-of-H> <hash-of-J> # what they changed on feature1
那么merge的作用就是合并这两组变化。在我们更改了一些文件而他们没有更改的地方,Git 接受了我们的更改。他们更改了一些文件,而我们没有,Git 接受了他们的更改。 这些组合更改会应用到 merge-base 快照。 这样,我们保留所有工作并添加他们的工作——但无论我们和他们不同 对某些文件或多个文件进行更改,Git 将显示 合并冲突。
在这种情况下,--ours
diff 是完整的tely empty:我们没有改变任何东西。因此,无论“他们”——实际上,我们 feature1
——做了什么,Git 都会进行这些更改。这包括添加一个新文件 test1
。这种合并进行得很顺利,所以 Git 自己进行新的合并提交。
新合并提交的 第一个 parent 是我们在 master
上的当前提交 H
。新合并提交的第二个 parent 是他们在 feature1
上的提交 J
。我们可以画出来——这里的图没有正确显示第一次提交和第二次提交,但是如果需要的话我们可以记住它,或者询问 Git 关于两个 parent 的问题,看看哪个是第一个, 或者其他什么。
结果如下所示:
I--J <-- feature1
/ \
...--G--H------M <-- master (HEAD)
\
K--L <-- feature2
请注意 other 分支名称是如何移动的:我们仍在 master
,它已移动到指向 M
,并且 feature1
仍然命名为提交 J
和 feature2
仍然命名为提交 L
.
合并冲突
如果我们现在 运行 另一个 git merge
——这次是 feature2
——Git 将再次找到三个提交:
- 当然,我们和他们的提交是提交
M
和L
。 - 合并基础是最好的共享提交。
看图。 master
和 feature2
都有哪些提交?提交 G-H-I-J-M
全部在 master
—H
上 两种 方式,直接来自 M
的第一个 parent,间接地从 J
到 I
再到 H
通过 M
的第二个 parent——因此 G
有两种方式,等等,但我们真正关心的是 H
和 G
在那里。
同时,feature2
结束于 L
,回到 K
,然后回到 H
。所以提交 H
和 G
都是共享的。不过,提交 H
是 最好的 之一。然后,合并基础再次提交 H
.
Git 将再次 运行 两个 git diff
s,都带有 --find-renames
(检查重命名的文件)并且都从 H
到两个分支提示。所以 Git 将把 H
中的快照与 M
中的快照进行比较,看看我们改变了什么。
我们从 H
到 M
改变了什么?好吧,在 M
中,我们添加了通过比较 H
与 J
得到的所有更改。因此,我们在 feature1
中 更改 的任何文件都在 M
中更改。但是我们还在 I
或 J
中添加了一个新文件 test1
,所以这个 change-set 说 add all-new file test1
.
当我们比较 H
与 L
时,也表示 添加一个 all-new 文件 test1
。所以两个变更集都说要添加一个新文件。
Git 将这种冲突称为 add/add 冲突 。 在 work-tree , Git 只是将两个文件的全部内容作为冲突留给您。您必须以某种方式解决此冲突。你如何去做取决于你。无论您选择将什么放入文件 test1
,您现在都可以 运行:
git add test1
和 Git 将假定文件 test1
中的内容是该冲突的 正确 解决方案。
一定要编辑文件!如果你不这样做,它只是其中有冲突标记,Git 认为这是 正确答案! 可能不是。
一旦您解决了所有冲突,并确定合并结果是正确的——例如,您已经完成了您需要做的任何测试——您可以通过 运行ning 安全地完成合并:
git merge --continue
或:
git commit
(git merge --continue
只是确保您仍在完成合并,然后 运行s git commit
为您服务,所以他们最终会做同样的事情——除非您已经即完成或终止合并。)
Git 现在将进行 另一个 合并提交;我们将其称为提交 N
,并像这样绘制它:
I--J <-- feature1
/ \
...--G--H------M--N <-- master (HEAD)
\ /
K-----L <-- feature2
N
的第一个parent是M
,N
的第二个parent是L
。现在有 三种 种方法可以从 N
到 H
,并且图中的 所有 提交都在 master
.
现在删除名称 feature1
和 feature2
是安全的,因为 Git 可以通过向后查找这些提交——包括 J
和 L
来自提交 N
。如果您想保留直接快速地找到提交 J
和 L
的能力,您 没有 删除名称,但它们不是更长必要,就像它们在合并操作之前一样。