【Git教程】(六)分支合并 —— 合并过程,各类合并冲突及解决思路 ~

这篇具有很好参考价值的文章主要介绍了【Git教程】(六)分支合并 —— 合并过程,各类合并冲突及解决思路 ~。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

合并分支,GIT教程,git,大数据,分布式,自动化,java,开发语言

使用 merge 命令来进行分支合并是 Git 中最重要的操作之一。虽然这一操作的底层算法很复杂,但调用起来却很简单。我们可以通过指定分支名称来选择待合并修改的分支。然后, Git 会基于合并的内容来创建一次新的提交。

下面,我们来看下图中的这个例子:在一群开发者在一个名为 feature 分支上开发新功能的同时,另一位开发者则刚刚修复了 master 分支上的某个错误(提交E) 。 然后过了不多久,feature 部分的任务也完成了,并将交付使用。因此 master 分支的下一个版本中应该同时包含被修复的部分和新的 feature 部分。这时候,我们要对这些分支使用 merge 命令,其结果会产生一次合并提交(即这里的提交 F), 该提交将会有两个父级提交 (D 和 E)。

> #on the branch "master"
> git merge feature

合并分支,GIT教程,git,大数据,分布式,自动化,java,开发语言


1️⃣ 合并过程中发生的事

Git的设计目标之一就是为了能让开发者之间的分布式协作变得尽可能容易一些。因此从 很大程度上来说,merge 命令应能自动对分支进行合并,完全不需要用户交互。但这是怎么做到的呢?

例如在下图中,我们会看到某一个文件有两个不同版本,它们分别属于分支a 和分支b。 我们很容易就能看出这其不同之处位于哪几行。但究竟哪一个才是正确的呢?是 “Freitag” 还是 “Montag”? 是 “Git” 还是 “Fit”? 合并算法应该如何作出决定呢?

合并分支,GIT教程,git,大数据,分布式,自动化,java,开发语言

问题关键就藏在其提交历史之中。这里的窍门就是要找到它们最后一个共同的祖辈提交。 换一种相对简单点的说法,就是要找到其提交路径上岔出分支的那个点。只要我们将该源版本与眼前的这两个分支的版本比对一下,整个画面就会变得更为清晰。

如你所见,在图下这个例子中,分支 b 中的第一行 “Freitagabend” 被替换成了 “Montagabend” 。 而在分支a 中,第一行则没有被修改。这在进行分支合并时是一个强烈信号, 它告诉我们应该采用包含 “Montagabend” 的版本。通过同样的方式,我们也可以安全地确认,对于最后一行我们应该采用包含“Git”的版本,而不是“Fit”的版本,其最终结果如图所示。

合并分支,GIT教程,git,大数据,分布式,自动化,java,开发语言
当然从事实上来说,真要想找到它们共同的祖辈提交可不是一件容易的事。为解决这个问题,Git 实现了3种不同的合并算法。其在默认情况下采用的是递归算法。但除此之外,它还实现了经典的3路算法和所谓的 “octopus” 算法。其中, “octopus” 还可以同时处理多个分支。


2️⃣ 冲突

Git 非常适合于在几个开发者对同一软件做多处修改时,被用来合并他们对程序源代码中 所做的修改。这些操作甚至常会涉及到那些受移动或重命名操作影响的文件。而不幸的是,这些文件往往会引发一些无法用 Git 自动化解决的冲突。

  • 编辑冲突:通常发生在两个开发者对同一行代码做了不同修改的时候。在这种情况下, Git 往往无法自行确定两种修改中的哪一种才是正确的。
  • 内容冲突:通常发生在两个开发者对某份代码的几个部分做出各自修改的时候。例如 这种情况就容易导致这类冲突:当一个开发者在修改某一函数的时候,另一个开发者 也在同一时间修改了同一函数。

3️⃣ 编辑冲突

当Git 遇到了自身无法解决的冲突时,就会显示以下错误消息。

> git merge one-branch
Auto-merging foo.txt
CONFLICT(content):Merge  conflict in foo.txt
Automatic merge failed; fix conflicts and then commit the result.

下面我们来看看具体发生了什么。

  1. Git 无法创建提交。Git 通常会在合并后自动创建提交。而在发生冲突的情况下,我们就必须要先解决问题,然后再手动创建提交了。
  2. .git/MERGE_HEAD 中将保存另一分支的提交散列值。
  3. 工作区中的文件代表了合并结果。
  4. 无冲突部分的修改合并将会被记录在暂存区中,以便纳入下一次提交。
  5. 将会有冲突标志被插入。
  6. 冲突所在之处将不会被注册到下一次提交中。

现在,根据 status 命令返回的信息,我们可以看到 “Changes to be committed” 这部分显示的是自动合并的文件。而 “Unmerged paths” 这部分就是用户必须进行手动编辑的文件。

> git status
#On branch master
#  (fix conflicts and run "git commit")
#
#Changes to be committed:
#
#modified:  blah.txt
#
#Unmerged  paths:
#    (use( "git add <file>..."to mark resolution)
#
#both  modified:  foo.txt
#

4️⃣ 冲突标志

冲突标志通常会描述两组修改。首先是这些被修改的行在当前分支(HEAD) 中的内容。
接下来又列出了他们在另外一个分支(即MERGE_HEAD, 在这里是 one-branch) 的内容:

In the early morning dew
<<<<<<< HEAD
to the valley
=======
for swimming
>>>>>>> one-branch
We're going.Fallera!;

出于各种历史原因,这些分支提交的共同祖辈在默认情况下是不显示的,但我们可以将 其配置成3路显示格式。

> git config merge.conflictstyle diff3

这样一来,编辑冲突就会如下所示。

In the early morning dew
<<<<<<< HEAD
to the valley
||||||| merged common ancestors
to mountains
=======
for swimming
>>>>>>> one-branch
We're going Fallera!;

5️⃣ 解决编辑冲突

解决编辑冲突最好的办法是使用像 kdiff3 这样的合并工具。在这里,我们可以从mergetool 命令启动合并工具。

> git mergetool

在这个工具中,我们可以解决冲突、保存修改以及终止这个应用程序。然后,合并之后 的修改将会出现在暂存区中,它们可以被确认为一次提交。

当然对于二进制文件来说,上面这种文本化的冲突标志是不存在的。在这种情况下,我 们就必须要去查看其原始版本。该文件的3个版本在冲突中扮演了各自的角色:即当前分(我们的)的版本、其他分支(他们的)的版本、以及这两个分支最后的共同祖先(祖辈版本)。

我们可以用 show 命令检出这些版本。

> git show :1:picture.png >ancestor.png
> git show :2:picture.png >ours.png
> git show :3:picture.png >theirs.txt

1a. 编辑受影响的文件
对于每一个冲突所在之处,我们都考虑自己想要采用的选项,然后在文本编辑器中删除冲突标志所在的剩余部分即可,但这种方法对二进制文件是不适用的,因此我们就需要用到步骤1b 了。


1b. 采用 --ours--theirs选项
或者,我们也可以用checkout 命令来完全选择只采用自己的(或者是别人的)那个版本的文件。

git checkout --theirs tests/


2. 注册修改
git add

3. 提交
git commit

另外,合并和比较工具往往也会将一些空白符方面的修改显示出来。例如,如果某个开 发者将制表符替换成了空格符,其涉及到的所有行都会被标记,尽管他没有在内容上着任何修改。这些工具通常会有相关的选项可以忽略掉空白符的修改,我们建议你使用这个选项。

当然,更好的选择是所有开发者都能用相同的工具来进行源代码的自动格式化,那我们
就等于解决了格式冲突的一个根源。

然而事情总有意外!如果我们在合并时犯了一个错误或者在解决冲突时出了错的话,就不应该再继续做下去了,相反,这时候我们应该果断地取消合并,这样我们就不会在工作区中留下合并操作的踪迹,并且 Git 中也不会在下轮提交中出现合并提交,合并操作可以通过reset 命令来取消。

> git reset --merge

6️⃣ 内容冲突

真正的麻烦是内容冲突,由于Git 无法识别这类冲突,自动化解决当然是肯定不用想了。 其真正的危险来自于当内容冲突存在时,merge 命令还是会生成有效的合并提交。
请注意! 这也就是说,即使所有的合并版本都是正确的,且 Git 也没有报告任何编辑冲
突,该合并提交也可能是坏的!

如果我们想避免内容冲突扰乱软件版本,就得要做更多事。

  • 借由自动化测试构建保护机制:如果这些测试能够定期进行,并且有一个很好的覆盖 面的话,各种内容冲突就能很快被发现。
  • 使用断言、以及前置与后置条件:基本上,我们执行越多明确的断言检查,就越能更 早地发现问题。
  • 定义清晰的接口,使其实现松耦合:以目前所讨论的点来说,显然体系结构设计得越 干净利落,其代码因不同地方被混入修改而引发意外副作用的可能性就越小。
  • 静态类型检查:只要我们的编程语言支持这一特性,那么任何签名变化所引发的问题 都将会在编译时被检测到。

顺便说一句, merge 命令在这里对于多分支的合并也是有效的,这就是 octopus 合并。


7️⃣ 快进合并

我们常常会遇到这样的情况:即若干个分支中中往往只有一个分支仍在持续工作。例如 在下图的这个项目中。开发者们一直都在 a-branch 分支下开发,而 b-branch 分支上则什么 事也没有发生。当 b-branch 与a-branch 这两个分支要进行合并时,Git 要做的工作就非常简单了:只要前移一下指针即可,不再需要产生合并提交了,我们称这种情况为快进合并。

> git checkout b-branch
> git merge a-branch
Updating 9d4caed..9332b08
Fast-forward
foo.txt | 2 +-
1 files changed,1 insertions(+),1 deletions(-)

合并分支,GIT教程,git,大数据,分布式,自动化,java,开发语言快进合并的优点是它能简化版本库的历史记录并使其保持线性发展。而缺点则是我们不能根据已经合并过的历史记录来看版本库的这一发展。正是因为它存在这样的缺点, 我们才需要在本书的一些工作流中使用 --no-ff 选项,以强制其产生一次新的提交。

> git merge --no-ff a-branch

合并分支,GIT教程,git,大数据,分布式,自动化,java,开发语言


8️⃣ 第一父级提交历史

合并提交通常都会有两个父级提交,甚至 octopus 合并中还会有两个以上的父级提交存
在。例如在下面的例子中,我们会看到两个父级提交 ed1c70e 和 fld55be。

> git log --merges
commit 7f3eae07c42df05f894fdd4754e38ab9e66a5051
Merge: ed1c70e f1d55be
Author: ...

这个例子中的第一次提交 (ed1c70e) 叫做第一父级提交,它是合并执行完后HEAD 所在的那个提交。代表的是该合并所发生的地方。如果所有的开发者都在同一分支上工作,那么它无论何时何地执行合并都不会影响结果。

在这种情况下,我们去深究哪一个是第一父级提交就显得毫无意义了。
另一方面,当我们需要将自己在某些特性分支上所开发的一个个特性集成到特定的特性 分支上时,这个集成后的结果分支 (即本例中的 master 分支) 就是一个合并提交的序列(见下图)。它的第一父级提交通常就是其上一级特性的合并提交。

合并分支,GIT教程,git,大数据,分布式,自动化,java,开发语言

如果我们沿着第一父级提交链一路追踪到根提交上,就会得到一份特性集成的概览。我 们将其称之为第一父级提交历史。你可以通过带 --first-parent 选项的log 命令来显示这份特性集成概览:

> git log --first-parent --oneline R1.0..master
7f3eae0 Merge branch 'Feature-C' Finished(M4)
ed1c70e Merge branch 'Feature-A' Finished(M3)
eeb6ec2 Merge branch 'Feature-B' Finished(M2)
8ce3213 Merge branch 'Feature-A' Partial delivery(M1)

第一父级提交历史的奇妙之处在于,它为我们提供了一份历史的总结报告。你可以从中
清楚地看到哪些已被集成的特性,无需再去侦查那些特性分支上的每一次提交。
请注意! 这只适用那些执行了快进合并的集成分支。否则,独立的特性分支提交只能被
直接放置到 master 分支的第一父级历史中。

还有一件事也需要注意! 我们不应该对集成分支(即这里的 master) 执行内部合并。相 反,我们要确保这些特性都是依次连续地被集成进来的,这样我们才能得到一份线性的特性合并历史。


9️⃣ 棘手的合并冲突

在 Git 中,大多数合并操作都可以在没有或者只有少量人工辅助的情况下自动完成。但
如果两个分支各自演变的轨迹非常的不同,也有可能会带来一些棘手的冲突。
当然,在这一节我们只讨论两个分支之间的合并。如果你是在 octopus 合并上遇到了这样的问题,建议你应该取消这次合并,试着采用逐个解决的思路来解决这个问题。

首先我们需要将重点放在信息收集上,以便了解目标分支上目前所发生的事。在这里, 在 log 命令中使用 .. 这符号可能会很有帮助。例如,a…b 可用来表示来自于分支 b, 但不属于 分支 a 的提交。它可以显示出“我们” (在当前分支上)做了哪些事,而这些事应该不会被提交到其他分支中。

> git log MERGE_HEAD..HEAD

反之亦然,我们也可以用该符号来显示“别人”所做的事情。

> git log HEAD..MERGE_HEAD

另外,分支的图形化表示也会很有用。

> git log --graph --oneline --decorate HEAD MERGE_HEAD

我们也可以在 log 命令中使用 --merge 选项,限制其只输出合并提交。

> git log --merge

除此之外,我们也可以使用一些比对原版本时会用到一些实用的分支技巧。但这需要以
合并操作为基础,即该版本必须在合并操作中是这些分支共同的祖辈提交。

> git merge-base HEAD MERGE_HEAD
ed3b1832c48b359111d00bddb071c42ba6f38324
> git diff --stat ed3b18  HEAD %Our changes
> git diff --stat ed3b18  MERGE_HEAD %Changes by others

如果想用图形化工具代替这种文本输出的话,你也可以使用 difftool 命令。
这样一来,我们就可以看到涉及冲突的是那几个开发者。这时候,我们最好能与他们每
个人都谈一谈,使得每个人都能自行确保他或她被纳入合并的修改是正确的。

如果其他人对此无能为力,那事情就更加难办了,因为我们通常对别人分支上的事情并 不精通。从技术上来说,合并原本应该是一个对称的操作。但我们在意识中往往对此会有一 个不对称的视角。即我们一般会问自己问题:“我应该怎样将别人的代码纳入到自己的代码呢?” 其实,有时将问题反过来看会更有帮助,即我们不妨以别人的版本层次为出发点,去找出可以将自己的修改整合进去的方法。这样的视角转换有时候确实会很有帮助。

或许是由于时间紧迫,我们常常倾向于直接用合并工具选取这份或那份代码变更了事。 这种贪图方便的行为是应该被抵制的。如果经过difflog工具配合“其他”版本的分析之后, 你依然无法确定解决冲突的方式,那么你就应该取消合并,然后再考虑一下以下几种可能的策略。

  • 分支重构:最干净利落的解决方案可能就是以重构的方式其中一个分支进行清理,并 执行交互式变基。但这是一个很大的工作量。
  • 分小步合并:如果两个分支中的一个分支存在细粒度的提交,我们可以采用一次一提 交的方式来处理。这种方法的优势在于,毕竟粒度越小的提交所带来的冲突往往越容易解决。但如果这种提交的数量很大,它也可能会非常耗时,无论是哪一种情况,为此创建一个本地分支都是值得推荐的做法。
  • 丢弃与捡取:在某些情况下,拒绝某个劣质分支上的某些修改是一个不错的做法,我 们可以通过 cherry-pick 命令来对其采取些改进措施。
  • 评级和测试:如果受合并影响的功能可以通过测试,那么我们自然在解决冲突时候据 此来推演,并将其结果改善到能通过所有测试为止。

🌾 总结

  • 合并:所谓合并就是对相关提交图中的分支执行合并操作。
  • 合并提交:执行 merge 命令的结果就是产生一次合并提交。
  • 3路合并:Git会在合并时利用提交图找到合并双方最后的共同祖先。然后, Git 将引自该祖先的一个分支上的修改,连同另一分支上所做的修改放在一起。只要这些修改发生在这份源代码的不同之处, Git 就能自动创建相应的合并提交。
  • 冲突:对于源代码中 Git无法自动合并(或许是由于同一行被人做了不同的修改)的那个点,我们称这里发生了冲突。
  • 内容冲突:虽然修改通常会发生在不同的位置上,但它们在内容是仍然可能会不匹配。 由于Git无法检测到这样的内容冲突。所以项目自身应该设置一些相应的预防措施, 例如自动化测试等,以保护自己免于内容冲突的破坏。
  • 快进合并:在合并过程中, 一个分支是另一个分支的祖先是很常见的。在这种情况下, Git 就只需要将分支指针前移即可,无需去创建合并提交。


温习回顾上一篇(点击跳转)
《【Git教程】(五)分支 —— 并行式开发,分支相关操作(创建、切换、删除)~》

继续阅读下一篇(点击跳转)
《【Git教程】(七)变基与拣取 —— 变基操作的概念、适用场景及其实现方式,拣取操作的实现 ~》
文章来源地址https://www.toymoban.com/news/detail-857857.html

合并分支,GIT教程,git,大数据,分布式,自动化,java,开发语言

到了这里,关于【Git教程】(六)分支合并 —— 合并过程,各类合并冲突及解决思路 ~的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Git合并多分支及冲突解决

    工作场景 工作场景中我们常常会遇到以下情况: 小明:靓仔/妹,我上线那天有事情,我的那个分支你帮我一起推一下 摸鱼崽:帮我也合一下,好哥哥 我:好(你)呀(md) 如果在这种时候你说我不会,我只会add,commit、push我本地的,你的分支我哪儿会啊,是不是有点尴尬

    2024年02月13日
    浏览(53)
  • Git 分支简介-创建-合并-解决冲突-删除

    1.在版本控制系统(如Git)中,分支(Branch)是代码库的不同线路或路径,用于同时进行不同的开发工作。分支可以将代码库的状态 ‘‘复制’’ 到一个独立的环境中,使得在这个分支上进行的更改不会影响到其他分支。 2.使用分支的好处是可以同时进行多个并行的开发任务

    2024年03月21日
    浏览(65)
  • 深入了解 Git 分支合并冲突解决步骤

    在协作开发中,当不同分支对同一文件的相同位置进行修改时,往往会出现合并冲突。这些冲突需要开发者手动介入解决,以确保代码的一致性和稳定性。以下是解决 Git 合并冲突的有效步骤,让我们深入了解这个过程。 一旦执行 git merge 分支名称 进行合并操作,Git 会尝试自

    2024年02月04日
    浏览(64)
  • 如何解决Git合并分支造成的冲突

    一、造成冲突的场景         在我们在参与项目开发的时候,通常会创建公共的文件,但是当我们编码完成,使用git进行分支合并时,往往会出现合并冲突,也就是负责不同部分的开发人员会对同一个文件的同一个部分进行修改,这个时候就需要我们解决合并造成的冲突

    2023年04月23日
    浏览(67)
  • idea解决代码冲突-git分布式合并分支-加git回滚操作

    第一次接触项目发版的工作,记录一下解决版本冲突合并问题的心得。 适用场景:分布式项目,多人使用自己分支开发,最后合并自己的代码分支给主分支。 话不多说,直接看图 1.全部拉下来(这个拉取是全部拉取,既保证自己的分支最新,同时也把远端的分支都拉到最新

    2024年02月08日
    浏览(120)
  • git的拉取、提交、合并、解决冲突详细教程

    我们在开发中使用git,经常会遇到拉代码,切换分支,提交代码,新建分支,合并代码,解决冲突这些操作,下面我跟大家分享一个好用的git工具来进行这些操作。 首先,我们下载一个git工具 点击下载GitHub Desktop 1.拉取git代码 复制git地址 打开工具,点击右上角的File,点击

    2024年02月02日
    浏览(51)
  • git的分支的使用,创建分支,合并分支,删除分支,合并冲突,分支管理策略,bug分支,强制删除分支

    查看当前本地仓库中有哪些分支 HEAD所指向的分支就是当前正在工作的分支 创建一个分支 创建好了,但是目前还是指向 master 用tree命令也可以看到已经创建分支成功了 创建出来的分支,和主分支的最新记录是一样的 切换分支就是让HEAD指向我们的dev分支 我们在dev分支上堆R

    2024年02月04日
    浏览(60)
  • 【Git】在idea中多分支开发如何——合并分支、处理冲突

    博主简介: 22级计算机科学与技术本科生一枚🌸 博主主页:是瑶瑶子啦 每日一言🌼: “人间总有一两风,填我十万八千梦” 我当前开发的分支—— hfy 我想将 subject 分支的最新代码拉取合并到 hfy 分支 点击之后会出现界面,有需要你处理的冲突( 冲突的处理的本质就是:你

    2024年04月17日
    浏览(80)
  • 多分支Git的操作简介,冲突合并,多平台对应

    在使用git管理代码时,在多人开发,或者不同功能开发以及环境测试时,需要保持master代码的稳定性,因此往往需要创建多分支的Git仓库,这里记录一些多分支仓库的操作指令 1. 分支操作 1.1 创建分支 上述输入想要创建的分支名字,即可在本地创建分支,如 即可以在本地创

    2024年01月22日
    浏览(49)
  • 使用tortoiseGit合并代码(合并分支,解决冲突)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 使用tortoiseGit + Beyond Compare 合并分支,并解决冲突 1.选择 “Settings” - “Merge Tool”-\\\"External \\\" 2.填入Beyond Compare路径和参数 X:Program FilesBeyond Compare 4BComp.exe %mine% %theirs %base %merged /title1=%yname /title2=%tname /ti

    2024年02月15日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包