git pull拉回操作中的合并
在前面一个博客,我们将到了非快进式推送的非强制性的另一种解决办法,那就是先拉回在提交,这里的拉回其实包含了两个操作:获取远程仓库的数据,将本地数据进行合并。可以这样写:git pull = git fetch + git merge
git merge命令用于合并分支,它的命令行格式为:git merge [options...]
默认情况下,合并后的结果会自动提交,我们可以通过设置选项来指定手动提交,通过命令:git merge --no-commit
合并操作并非总会成功,下面将详细介绍
合并一:自动合并
这一类合并不会报错,不需要用户来处理相应的错误,主要分为三种
修改不同的文件
如果两个(或者多个,这里只介绍两个)用户user1/user2各自的本地提交中修改的是不同的文件,那么第二次进行合并推送的提交将能正确合并并提交,不会遇到任何麻烦
修改相同文件的不同区域
首先需要说明的是,文件的修改是分区域的,可以具体到修改哪一行,通过命令cat > fileName.suffix进行逐行修改
当user1用户修改了index.txt文件的第一行第二行并进行提交与上游推送,然后user2用户同样修改了index.txt文件,不过修改的是第三行和第四行,然后在进行git pull命令,同样能正常合并,不会遇到任何麻烦
同时更改文件名和文件内容
如果user1用户将index.txt文件移动到了index2.txt文件并删除index.txt(重命名的操作),并且进行了提交与上游推送,此时user2用户使用命令git pull获取并合并信息之后,会发现它同样也能正常合并,然后我们进行推送:git push origin master然后成功推送,接着我们查看一下远程仓库的内容,会发现git对这种情况的处理方式是:user2用户最终修改的是user1用户对应重命名后的文件
这种情况下的自动合并其实是有逻辑冲突的,就C语言编程我们来举一个例子:我们在main.c文件中调用了一个头文件head.h文件,然后另一个用户将该文件该名成head2.h文件,最终我们使用main.c文件将会编译错误:找不到head.h头文件。所以在这种情况下,我们要慎重合并,或者在本次提交操作上添加一些重要的注释
合并二:冲突解决
当两个用户同时修改同一个文件的相同区域的内容时,就会发生冲突事件了。看如下例子:
首先为了保证两个用户的本地版本库和远程版本库一直,分别进行命令:git pull
然后先将user1用户修改文件hello.txt成如下内容并进行提交:
然后user2用户进行同样的修改操作如下:
接下来我们进行user2用户的非快进式合并推送,会发现合并失败:
这就是因为两个用户同时修改了相同文件的相同区域造成的冲突,通过命令查看当前状态,会发现输出的日志告诉我们同时修改了一个文件hello.txt
接下来我们通过一个命令来查看到底是哪些文件发生了合并冲突,这个命令是:git ls-files -s,该命令输出的第二列的值如果为0表示对应的文件没有冲突,合并成功,如果不为0,则表示产生了合并的冲突,其中具体的值对应的意义是:1表示两个用户之前一个共同版本的对应文件内容;2表示当前用户对应的文件版本;3表示合并后的文件对应的远程版本
通过命令:git show :n:filename查看对应文件的对应版本的内容
在知道了三个版本的文件内容之后,我们就可以手动的对冲突的文件进行手动修改操作了。这里需要注意的是,对应的冲突文件的内容已经发生了改变,里面对应的冲突区域的内容将会同时存在当前分支的内容和远程版本的内容,如下图。我们可以手动对该文件进行修改操作,然后在手动add、commit、push就可以了
然后我们通过之前的查看版本区别的命令就可以看到对应的冲突文件已经没有冲突了
对于上面的文件冲突,除了通过使用命令git ls-files -s // git show :n:filename来解决之外,还可以通过git内置的图形化界面工具来操作,通过命令:git mergetool打开工具,默认git提供的是kdiff3,其中上方的三个界面从左到右依次为:两个版本的前一个共同版本的文件版本、当前本地版本的文件版本、合并后的文件版本
合并三:树冲突
如果一个用户将某个文件进行改名,而另一个用户也对该文件进行改名,当这两个用户的提交进行合并操作时,就会发生树冲突,因为git无法替用户做选择。下面将对树冲突进行测试并给出解决办法
同样为了确保两个用户的当前版本信息和远程版本一直,分别对两个用户执行命令:git pull
首先user1用户将hello.txt文件改名成user1.txt
然后进行提交
接下来user2用户对相同的hello.txt文件进行改名成user2.txt
然后进行user2用户推送后提交
然后发现合并出现了冲突,这是因为多个用户修改了相同的文件的文件名,查看当前分支的状态
我们可以通过命令:git ls-files -s查看当前版本的冲突文件对应的状态,其中1表示当前合并前的版本的文件对应的文件名,2表示当前分支的文件名,3表示合并的版本的文件名
同样我们知道了这些信息之后就可以进行手动修改操作了。首先,删除需要改名的对应的文件,这里就是删除文件hello.txt,然后删除user1.txt文件或者删除user2.txt文件即可进行提交和上游注册了
合并策略概述
git合并操作可以指定使用的合并策略,默认会选择最适合的合并策略。例如:两个分支的合并默认使用recursive合并策略、两个以上分支的合并默认使用octpus合并策略。我们也可以通过传递参数来指定使用的合并策略,命令行模式为:gig merge -s 合并策略 -x 合并策略参数
resolve策略:只能用于两个分支的合并,这个合并策略被认为是最安全、最快的合并策略
recursive策略:只能用于两个分支的合并,两个分支的合并默认使用该策略。该策略可以使用选项:
ours:在遇到冲突的时候,选择当前分支的版本,而忽略远程合并过来的版本。
theirs:和ours选项相反
subtree[=path]:使用子树合并策略
octpus策略:用于合并两个以上分支的策略,该策略拒绝执行需要手动解决的复杂合并。
ours:可以用于任意多个分支的合并策略,合并的结果总是使用当前分支的内容而丢弃远程合并过来的版本内容
subtree:这是一个经过调整后的recursive策略,子树合并策略相关内容可以去百度,这里就不详解了(主要是博主也不会~~)
合并相关的设置
可以通过命令git config来设置与合并相关的配置变量,对合并进行配置。
merge.conflictstyle:该配置变量定义冲突文件中冲突内容的标记风格,有两个可用的风格:默认的merge和diff3
默认的merge风格使用标准的冲突分界符<<<<<<<=======>>>>>>>读冲突内容进行标识,两个文字块分别是本地的修改和他人的修改
diff3风格会在冲突文件中出现三个文字块,<<<<<<< ||||||| ======= >>>>>>>,分别表示本地更改版本、共同的原始版本、他人更改的版本
merge.tool:设置执行命令git mergetool进行冲突解决时调用的图形化工具
merge..path:设置对应的图形化工具的安装位置
参考文献
git权威指南一书