11.团队协作_冲突解决

在上一节,通过执行 git pull 成功合并后再推送来解决非快进式推送的问题。但在真实的项目环境中,不总是会一帆风顺的,只要有合并就可能出现冲突,这一节重点介绍冲突解决方式。

上节已经说过: git pull = git fetch + git merge

  • git fetch :可暂时理解为将远程的版本库的对象(提交、里程碑、分支等)复制到本地。在本地版本库有专门的远程仓库映射引用,如:.git\refs\remotes\origin\master

  • git merge :会被隐式地执行,将其他版本库的提交和本地版本库的提交进行合并。该命令还可以对本版本库的其他分支进行显示的合并操作。默认情况下,合并后的结果会自动提交,如果提供 --no-commit 选项,则合并后的结果会放入暂存区,用户可以对合并结果进行检查、更改,然后手动提交。

合并操作并非总会成功,因为合并的不同提交可能同时修改了同一文件相同区域的内容,这会导致冲突。冲突会造成合并操作的中断,冲突的文件会被标识,用户可以对标识为冲突的文件进行冲突解决操作,然后更新暂存区,再提交,最终完成合并操作。

场景一、成功自动合并

大多数情况下,Git 都能非常智能地进行自动合并,下面演示一下成功自动合并的三种情况。

情况一:修改不同的文件

还是用上一节的例子进行演示,为了确保版本库状态的一致性,分别在 user1user2 的本地版本库中执行下面的操作:

git fetch
git reset --hard origin/master

现在两个用户的本地版本都为远程版本库的最新版本,状态一致。都有 team 目录和 user1.txtuser2.txt 文件。

  1. 用户 user1 修改 user1.txt 文件,提交并推送到远程。
local19.png
  1. 用户 user2 修改 user2.txt 文件,提交并推送(推送会失败,遇到非快进式推送的错误)。
local20.png
  1. 用户 user2 执行 git fetch 操作,获取提交并更新到本地用于跟踪远程版本库 master 分支的本地引用 origin/master 中。再执行 git merge 操作,成功自动合并,最后推送合并后的本地版本库到远程版本库。
local21.png
  1. 查看提交关系图。
local22.png

情况二:修改相同文件的不同区域

当用户 user1user2 在本地提交中修改相同的文件,但修改的是文件的不同位置时,仍可成功自动合并,具体操作如下:

  1. 为了确保版本库状态的一致性,分别在 user1user2 的本地版本库中执行 git pull 操作。

  2. 用户 user1 修改 README 文件,在第一行插入内容,更改后内容如下:

    User1 hacked.
    Hello.

  3. 用户 user1 本地提交并推送:

local23.png
  1. 用户 user2 也在自己的工作区中修改 README 文件,在文件的最后插入内容,更改后的文件内容如下:

    Hello.
    User2 hacked.

  2. 用户 user2 对修改进行本地提交,并执行 git fetch 操作:

local24.png
  1. 用户 user2 进行合并操作,完成自动合并并进行推送。这里合并的时候写的是 refs/remotes/origin/master ,其简写就是: origin/master
local25.png
  1. 追溯一下 README 文件每一行的来源,可以看到 user1user2 更改的位置:
local26.png

情况三:同时更改文件名和文件内容

如果用户将文件移动到其他目录(或修改文件名),另外一个用户使用旧的文件进行了修改,Git 还是可以成功自动合并,具体操作如下:

  1. 为了确保版本库状态的一致性,分别在 user1user2 的本地版本库中执行 git pull 操作。

  2. 用户 user1README 移动到 doc 目录下,进行本地提交并推送:

local27.png
  1. 用户 user2 在本地修改 REAMD 文件,在文件的最后插入内容,并本地提交。
local28.png
  1. 用户 user2 执行git fetch 操作,并执行 git merge 合并操作,最后进行推送。
local29.png
  1. 查看日志,并使用 -m 参数查看合并操作所做出的修改。
local30.png

可以看到,上面的提交是 user1 的,进行了文件的移动。下面的提交是 user2 的,doc/README | 2 +- 表示这个文件从第二行开始,添加了一行并删除了一行 。原来的第三行内容是:User2 hacked. ,而现在的第三行内容是:User2 hacked.User2 hacked again.。Git` 理解为删除了原来的行,新增了一行。

场景二、自动合并失败,手动冲突解决

如果不同用户修改了同一文件的同一区域,则在合并时会遇到冲突而中断,因为 Git 无法替用户做出决定(是要 user1 的提交内容还是 user2 的提交内容 ,还是两者提交的所有内容),会把决定权交给用户,用户再根据 Git 标识出的冲突位置来进行手动处理。

演示这个场景很简单,两个用户都修改 doc/READE 文件,都在第二行 Hello. 的后面加上自己的名字,具体操作过程如下:

  1. 老规则,为了确保版本库状态的一致性,分别在 user1user2 的本地版本库中执行 git pull 操作。

  2. 用户 user1 在第二行 Hello. 的后面加上自己的名字,内容如下:

    User1 hacked.
    Hello. user1.
    User2 hacked.User2 hacked again.

  3. 用户 user1 进行本地提交并推送:

    git add -u
    git commit -m "say hello to user1."
    git push

  4. 用户 user2 在第二行Hello. 的后面加上自己的名字,内容如下:

    User1 hacked.
    Hello. user2.
    User2 hacked.User2 hacked again.

  5. 用户 user2 对修改进行本地提交:

    git add -u
    git commit -m "say hello to user2."

  6. 用户 user2 执行 git pull 操作(相当于git fetchgit merge):

local31.png

自动合并失败了,需要手动修复冲突然后再对结果进行提交。

  1. 通过 git status 命令,可以从状态输出中看到文件 doc/README.txt 处于冲突状态,这个文件在两个不同的提交中都做了修改:
local32.png

输出提示可以使用 git merge --abort 终止合并操作,或者手动修复冲突然后再对结果进行 commit

实际上,合并过程是通过 .git 目录下的几个文件进行记录的,当合并成功时,文件会自动被删除,现在合并失败,所以本地还存在这些文件:

  • .git/MERGE_HEAD :记录所合并的提交 ID(就是合并成功后的新提交节点)。

  • .git/MERGE_MSG :记录合并失败的信息。

  • .git/MERGE_MODE:标识合并状态。

local33.png

而且暂存区中还会记录冲突文件的多个不同版本,可以使用 git ls-files -s 命令查看:

local34.png

输出中的每一行有四个字段,第一个是文件的属性,第二个是哈希值,第三个是暂存区编号,当合并冲突发生时,会用到 0 以上的暂存区编号。

  • 编号 1 的暂存区用于保存冲突文件修改之前的副本,也就是冲突双方共同的祖先版本。

  • 编号 2 的暂存区用于保存当前冲突文件修改的副本。

  • 编号 3 的暂存区用于保存合并分支的修改的副本。

可通过 :n:{filename} 语法来访问对应副本的内容,也可以用我们之前学过的 git cat-file -p {commit} 来查看副本的内容:

local35.png

通过 :n:{filename} 的方式是这样的:git show :1:doc/README 。对暂存区中冲突文件的上述三个副本无须了解太多,这三个副本实际上是提供给冲突解决工具,用于实现三向文件合并的。

工作区的版本则可能同时包含了成功的合并及冲突的合并,其中冲突的合并会用特殊的标记(<<<<<<<=======>>>>>>>)进行标识。当前冲突的文件内容如下:

local36.png

特殊标记 <<<<<<<======= 之间的内容是当前分支所更改的内容 。 ========>>>>>>> 之间的内容是所合并的分支修改的内容。

冲突解决的本质:就是通过编辑操作,将冲突标识符所标识的冲突内容替换为合适的内容,并去掉冲突标识符。编辑完毕后执行 add add 命令将文件添加到暂存区(编号0),然后再提交,就完成了冲突解决。

现在,工作区处于合并冲突状态,是无法再执行提交操作的。此时有两个选择:放弃合并操作或者解决冲突。放弃合并很简单,可以使用 git merge --abort 终止合并或执行 git reset 将暂存区重置即可。下面重点介绍如何进行冲突解决,也有两个方法:一个是对少量冲突非常适合的手工编辑操作,另一个是使用图形化冲突解决工具。

冲突解决方式一:手工编辑完成冲突解决

很简单,直接将 README 文件的标识符去掉,并修改为想要的提交内容,再进行提交。

修改后的文件内容如下:

User1 hacked.
Hello. user1. and user2.
User2 hacked.User2 hacked again.

添加到暂存区并提交:

git add -u
git commit -m "Merge completed:say hello to all users."

查看最近三次的提交日志,会看到最新的提交就是一个合并提交。提交完成后,会看到 .git 目录下与合并相关的文件 .git/MERGE_HEAD.git/MERGE_MSG.git/MERGE_MODE 文件都自动删除了,而且暂存区中的三个副本也都清除了(实际在对编辑完的冲突文件执行 git add 后就已经被清除了)。

local37.png

冲突解决方式二:图形工具完成冲突解决

  1. 由于已经手动完成了冲突解决,只能先回滚提交,再执行合并重新进入冲突状态。
local38.png
  1. 再次合并操作,进入冲突状态:git merge origin/master

  2. 开始使用图形工具,根据不同的冲突解决软件来做具体操作,最终结果跟手动处理的一致。

  3. 最后进行 git push 操作。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359

推荐阅读更多精彩内容