适宜人群
这是一篇关于 git 冲突入门级的介绍,以及简略介绍 git 分支的应用,大佬请绕行//手动龇牙
另外还有一篇非常好的最最基础的git使用命令请参考这篇写得很好的博客:Git操作详解
背景
最近在做一个微信小程序,因为不再是自己一个人独自开发,而是和两个组员一起开发小程序前端页面
那么不能再像在 GitHub 中托管辣鸡 demo 一样,一直一条分支
直接 git pull origin master
然后git push origin master
然后看着 GitHub 又变绿了一点,发出一声感叹:“虽然今天的代码一个都调不通,但是还是好累呢!”
刚开始其实三个人也是用的一个分支,即 master 分支,后来页面数量多起来,愈发地混乱,而且小程序页面注册,还有全局变量的设置,都在根目录下的app.js
,app.json
...中进行配置,(我重新整理后的)小程序目录大概如下:
所以项目 git 上传就一直冲突不断,基本上传一次就冲突一次
入坑
当项目中的两个成员同时修改一个文件(不是文件夹),然后分别上传到远程 git 仓库就会产生冲突,一般 git 会整合的时候在发生冲突的文件中自动生成三方合并标记线(<<<<<<<、=======、>>>>>>>)来标识各个成员的不同修改
Fine,For example
- 在 GitHub 上创建了一个测试项目来模拟远程 git 仓库
- 在电脑本地新建并使用两个空文件夹
file1
,file2
模拟真实开发中的两个项目成员- 在
file1
,file2
中分别clone下这个测试项目- 在
file1
,file2
先后修改clone到本地的测试项目中的同一个文件test.text
中的内容- 将修改后的
file1
,file2
先后push到GitHub,你会发现冲突
具体过程:
在 test.text
文件中, zb
是模拟的公共配置项代码
成员 file1
在公共代码下面配置了自己的代码: 甲的修改
成员 file2
在公共代码下面配置了自己的代码: 乙的修改
于是他们两个在互不知情的情况下修改了同一个文件,分别 push 到远程 git 仓库
file1
先 pull,然后 push,这时候远程的 git 仓库中的 test.text
中的内容变成了 file1
修改后的内容
这时候 file2
在 pull 的时候就会产生冲突,因为远程的 git 仓库 test.text
中的第二行和 file2
本地
git 仓库 test.text
中的第二行内容不一样,git 本身无法判断到底保留哪个
所以就会自动处理冲突,全部保留下来,下面图片就是 git 自动处理冲突后的打印出的信息:
git 并使用标记线标明代码冲突来源和冲突的内容,下图就是
file2
的 test.text
在 git 自动处理冲突后打开时候的内容(顿时感觉自己的代码被下了毒)稍稍解释一哈这个里面的意思:
<<<<<<<HEAD 乙的修改
表示 git 提示这部分产生冲突的来源是HEAD,冲突的内容是
乙的修改
,这个 HEAD 是一个指针,指向的是file2
的最新提交记录
=======
分隔符,将冲突的内容以及来源的不同信息隔开
甲的修改 >>>>>>>a35d5e7617aeb98bf382fa1a1af7579e976f9f4a
表示 git 提示这部分产生冲突来源是哈希值为
a35d5e7617aeb98bf382fa1a1af7579e976f9f4a
的提交记录(每一个提交 commit 都会有一个独有的哈希值,通过哈希值可以找到这个提交的所有信息),冲突的内容是甲的修改
,这个提交记录正是file1
的提交
这时候你就要自己手动处理,看看到底保留哪一份代码,或者还是都保留,然后删掉这些 git 自己增加的字符,解决冲突后,继续 push 到远程 git 仓库
那么这时候问题来了,如果是一个两个文件冲突还好,像我自己目前这个小程序包含了大量的项目页面,配置等文件,每上传一次,来一次冲突,冲突还是一大片的,这谁顶得住?
我的微信小程序项目的冲突就是这样,许多文件许多代码段出现大量的<<<<<<<、=======、>>>>>>>标记符:
填坑
解决这个坑的思路是这样的:
- 三个人分别建立自己的分支,每个人在自己的分支上提交记录,互不干扰
- 将公共的要配置的代码放在gitignore中不传到远程git仓库中,最后合并分支再统一处理
分支思想
如果是单独开发,开发者可以选择一条分支进行代码托管
但是项目协作者一多,单分支就会出现问题:
上图就是我之前的项目的问题,大家都在同一条分支上进行修改提交,不知不觉就会修改同一个文件,然后产生冲突的问题
所以就将每个人写的项目独立成一条分支,然后就在自己的分支上尽情修改,最后再合并成一条,这样在开发的时候各个功能开发一起进行,互不影响,等各自完成后再合并部署,加快了进度和主分支的完整性和可用性
如图,在
master
分支上第二次提交的节点上新建branch2
分支,甲在 master
上继续提交,乙在 branch2
上提交,互不干扰合并分支:
当分支上的功能完成,我们可以将
branch2
分支合并到 master
分支上,如上图所示,最后又合并成一条主分支,然后就可以进行完整功能测试和部署至服务器了那么问题来了,分支解决了冲突了么?
其实分支的目的就是避免冲突,互不影响,提高效率,如果两位开发者在两条不同的分支修改同一份文件,最后合并的时候还是会有冲突的,git 还是搞不清楚到底保留哪一份代码,于是又会它自己解决冲突,又会出现那些三方合并标记线
所以项目的模块划分,低耦合性很重要,我这个项目的解决方式是将这些公共的经常修改的配置文件等都在 .gitignore 中配置好,不传到远程 git 仓库中,最后统一分支的时候手动选择
相关命令
git branch
列出本地已经存在的分支,并且在当前分支的前面加 * 号标记
- git branch -r 列出远程分支
- git branch -a 列出本地分支和远程分支
- git branch branch2 创建一个新的叫
branch2
的本地分支,但只是创建分支,没有进行分支切换
git chekout
切换分支
- git checkout master 切换到
master
分支 - git checkout -b branch2 新建并且切换到一条名为
branch2
的新分支
即这条命令包含了两个过程:
1.git branch branch2 新建branch2
分支
2.git checkout branch2 指针 HEAD 指向切换到branch2
分支(也就是目前你都是在branch2
分支上修改)
git pull origin master
git push origin master
将本地 git 仓库的 master 分支 push 到远程的test分支中,照例还是要先 pull,后push
git log
打印git的提交记录,后面可以跟参数
1.git log --oneline 可以使每条日志以简短的形式一行输出
2.git log --graph 可以使日志以图的形式打印
参数可以连用,即:git log --oneline --graph 功能叠加
举个例子:创建,合并分支过程
- git init
在空文件下初始化git - 在初始化 git 后的文件夹中创建并编辑相关代码文件
- git add .
将自己修改好的代码添加到暂存区(add后面有个空格和 . ) -
git commit -m "master第一次提交"
将暂存区的代码提交到本地 git 仓库中
此时的本地 git 仓库:
- git checkout -b branch2
新建并且切换到branch2
新分支
这时候一个节点就包含了两个指针,一个master
,一个branch2
:
- 两次 git commit
因为两个指针都包含在一个节点,所以要分离开两个指针,使之成为两条独立的分支
当前 HEAD 指向branch2
,所以直接输入git commit
然后切换至master
分支:git checkout master
,继续输入:git commit
- 这时候不同开发者就可以在各个分支上进行修改
假设master
分支上提交了一次,branch2
分支上也提交了一次 - git checkout master
如果在其他分支,这时候切换至master
分支,准备合并 - git merge branch2
如果在其他分支,先使用git checkout master
命令切换至master
分支
再使用git merge branch2
将branch2
合并至master
分支 - git commit
再使用commit
,使 git 分支树彻底合并:
10.git log --oneline --graph
之前的图示都是我自己绘的,如果使用控制台查看 git 的历史提交记录,就是这样:
如果你也是一步步按照我的步骤,这就是最后打印出来的图示!
坑外话
其实 git 博大精深,林纳斯作为 git 的创造者,毕竟是影响世界 IT 进程的程序员,牛皮不是没有道理的,我这里也只是小叙一波,有什么错误的不清晰的地方请大佬们指教,以后有什么更深入的理解也会持续更新(撒花)