Git多人协作¶
约 4728 个字 48 行代码 6 张图片 预计阅读时间 16 分钟
多人协作实例1¶
要求:以当前master
分支的最新提交为基础,现在需要有两个人在同一个分支上同时进行开发,开发完成后,需要将各自的代码合并到master
分支上
首先准备两个分支,本次考虑直接在远程仓库上创建一个分支dev
,结果如下:
现在,使用下面的命令可以查看本地和远程的所有分支:
Bash | |
---|---|
1 |
|
可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 |
|
其中remotes/origin/
表示的就是远程仓库中的分支
可以看到,尽管远程创建了一个dev
分支,但是本地新创建的dev
分支,所以需要使用下面的命令将远程的dev
分支拉取到本地:
Bash | |
---|---|
1 |
|
此时会看到类似下面的结果:
Text Only | |
---|---|
1 2 3 |
|
再查看当前所有分支就可以得到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 |
|
另外,再另外一个系统下克隆当前仓库,模拟第二个开发者,克隆完成后查看当前所有分支:
Text Only | |
---|---|
1 2 3 4 |
|
现在本地仓库中可以看到远程的dev
分支,但是不可以直接在这个dev
分支上进行开发,考虑下面的思路:
- 在本地创建一个
dev
分支 - 关联本地的
dev
分支与远程的dev
分支
首先执行第一步:在本地创建一个dev
分支
Bash | |
---|---|
1 |
|
接着执行第二步:关联本地的dev
分支与远程的dev
分支
在执行关联操作之前,首先解释一下何为关联?在前面介绍过,不论是使用git pull
还是使用git push
都需要指定一个远程分支,这样做的目的就是为了让Git知道当前是从哪个分支下拉取或者向哪一个分支推送,而在之后的过程中也会涉及到远程仓库的指定分支和本地仓库的指定分支建立连接,但是注意当前这种做法不会建立连接(具体如何建立分支,后面会具体提及),而一旦明确了分支,就可以简写git pull
和git push
命令如下:
Bash | |
---|---|
1 2 3 4 |
|
那么如何查看本地分支与远程分支的连接呢?可以使用下面的命令:
Bash | |
---|---|
1 |
|
可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 |
|
可以看到,当前只有master
分支与远程的master
分支建立了连接,而dev
分支并没有与远程的dev
分支建立连接,现在先不建立连接,直接切换到dev
分支进行开发看看会发生什么:
首先切换到dev
分支:
Bash | |
---|---|
1 |
|
接着,在dev
分支上进行开发:
Bash | |
---|---|
1 |
|
接着,执行下面的命令完成提交和推送:
Bash | |
---|---|
1 2 3 |
|
可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 |
|
可以看到,因为当前dev
分支并没有与远程的dev
分支建立连接,所以提交时Git无法知道当前要提交到哪一个远程分支,所以需要使用下面的命令建立连接:
Bash | |
---|---|
1 |
|
例如当前情况下执行下面的命令:
Bash | |
---|---|
1 |
|
执行完成后,就可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 |
|
接着,再使用查看已经连接的分支命令:
Bash | |
---|---|
1 |
|
可以看到类似下面的结果:
Text Only | |
---|---|
1 2 |
|
此时,远程仓库和本地仓库的dev
分支已经建立了连接,并且远程仓库的内容也与本地仓库保持一致,而远程仓库下的master
分支并没有更新到最新版本,至此第一个开发者已经完成
接着,第二个开发者此时也执行上面的步骤进行开发,这里介绍另外一种方式:在创建分支的同时建立与远程分支的连接:
Bash | |
---|---|
1 |
|
例如当前情况下执行下面的命令:
Bash | |
---|---|
1 |
|
此时会看到类似下面的结果:
Text Only | |
---|---|
1 2 |
|
现在假设第二个开发者并不知道第一个开发者已经对test.txt
文件进行了修改,所以如果第二个开发者直接将开发结果推送给远程仓库,就会出现冲突出现下面类似的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 |
|
出现上面结果的原因就在于当前远程仓库的dev
分支和当前本地的dev
分支之间存在冲突,所以解决方案如下:
- 将远程仓库的
dev
分支拉取到本地 - 在本地的
dev
分支上进行冲突处理 - 将处理后的结果推送到远程仓库
首先执行第一步可以得到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
此时在当前本地dev
分支中的test.txt
文件中就会出现类似下面的内容:
Text Only | |
---|---|
1 2 3 4 5 6 7 |
|
接着手动处理冲突,处理完成后,再提交到远程仓库:
Bash | |
---|---|
1 2 3 |
|
执行完成后,就可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
那么,为了尽可能避免上面的冲突,在进行多人位于同一个分支上进行开发,执行前先进行拉取保证当前本地与远程保持同步,回到第一个开发者,因为当前远程仓库的dev
分支中的内容和本地dev
分支中的内容还没有同步,所以先执行git pull
确保一致
现在两个开发者都完成了开发,在实际开发中,一旦测试发现开发结果没有问题就可以考虑合并代码了,根据前面的介绍,现在有两种合并方式:
dev
分支提出Pull Request
请求合并到master
分支- 在本地合并再提交到远程分支
本次考虑第二个方式,首先为了确保本地master
分支和远程master
分支保持一致,先执行git pull
拉取远程master
分支的内容,接着执行下面的命令:
Bash | |
---|---|
1 2 3 4 |
|
之所以要在dev
分支上合并master
分支是为了确保如果存在冲突,能够在dev
分支上解决,而不是在master
分支上解决
执行完成后没有问题再将dev
合并到master
分支:
Bash | |
---|---|
1 2 3 4 |
|
合并完成后,再将结果推送到远程仓库:
Bash | |
---|---|
1 |
|
执行完成后,就可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 |
|
回到远程仓库即可看到master
分支已经更新到最新版本
开发完成后,如果需要将dev
分支删除,执行下面的命令:
Bash | |
---|---|
1 |
|
但是上面的命令只是删除了本地的dev
分支,而远程的dev
分支并没有删除,可以考虑在远程仓库的界面上直接删除,删除后再查看所有的分支如下:
Text Only | |
---|---|
1 2 3 4 |
|
可以看到,远程的dev
分支依然存在,此时查看远程分支的状态可以使用下面的命令:
Bash | |
---|---|
1 |
|
可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 |
|
可以看到,远程的dev
分支已经标记为stale
,表示已经过时,可以使用下面的命令删除:
Bash | |
---|---|
1 |
|
执行完成后,再查看远程分支的状态,就可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 |
|
再次查看即可看到远程的dev
分支已经被删除
多人协作实例2¶
要求:以当前master
分支的最新提交为基础,现在需要有两个人在两个不同的分支上同时进行开发,开发完成后,需要将各自的代码合并到master
分支上
同样,现在需要两个开发者有两个分支,但是本次不考虑在远程仓库上创建分支,而是让两个开发者在本地创建分支,首先让第一个开发者创建一个dev1
分支:
Bash | |
---|---|
1 |
|
接着,在该分支上创建一个dev1.txt
文件并写入以下内容:
Text Only | |
---|---|
1 |
|
接着,执行下面的命令完成提交:
Bash | |
---|---|
1 2 |
|
但是,现在有个问题,dev1
分支已经完成了本地开发,需要将结果提交到远程仓库的dev1
分支,但是远程并不存在dev1
分支,所以现在需要先创建一个远程分支dev1
,之后再建立连接,此时就需要执行完整版本的git push
命令:
Bash | |
---|---|
1 |
|
执行完成后,就可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
可以看到使用了上面的命令不仅会在远程仓库创建一个dev1
分支,还会将修改的内容推送到远程仓库的dev1
分支
接着让第二个开发者也执行上面的操作,写入内容为this is dev2
执行完上面的操作后,现在远程仓库就存在着三个分支:
master
分支:不存在任何一个开发者的修改dev1
分支:第一个开发者的修改dev2
分支:第二个开发者的修改
现在,假设第二个开发者需要拜托第一个开发者在其分支下继续开发,那么对于dev1
分支来说,目前能看到的分支只有两个dev1
和master
,即如下:
Text Only | |
---|---|
1 2 3 4 5 |
|
那么要使dev1
分支可以看到dev2
分支并且修改其中的内容,就需要先拿到dev2
分支,所以可以使用下面的命令:
Bash | |
---|---|
1 |
|
执行之后可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
可以看到,尽管dev1
分支没有和远程仓库中的dev1
分支进行连接,但是依旧可以拉取到远程仓库中的dev2
分支,这是因为在使用git pull
时有两种情况:
- 拉取远程仓库中指定分支的内容:需要建立连接
- 拉取远程仓库中指定分支:不需要建立连接
现在,第一个开发者再在master
分支下创建一个dev2
本地分支并与远程仓库的dev2
建立连接即可,这里考虑另外一种建立连接的方式,首先创建一个dev2
本地分支,再使用下面的命令进行:
Bash | |
---|---|
1 |
|
例如当前情况下执行下面的命令:
Bash | |
---|---|
1 |
|
此时就可以看到类似下面的结果:
Text Only | |
---|---|
1 |
|
这就说明远程仓库的dev2
分支与本地的dev2
分支已经建立了连接
接着进入到本地dev2
分支中,先进行git pull
再继续写入内容,例如:
Text Only | |
---|---|
1 |
|
接着,执行下面的命令完成提交:
Bash | |
---|---|
1 2 |
|
再使用git push
将修改推送到远程仓库:
Bash | |
---|---|
1 |
|
执行完成后,就可以看到类似下面的结果:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
此时,远程仓库的dev2
分支下的dev2.txt
内容已经更新到最新版本,但是对于第二个开发者来说,他的dev2
分支并没有更新到最新版本,所以需要先执行git pull
拉取最新版本,才能进行修改。拉取后依旧需要保证远程仓库的dev2
和本地仓库的dev2
是已经建立连接的
现在,第二个开发者在dev2
分支下继续修改dev2.txt
的内容,例如:
Text Only | |
---|---|
1 |
|
接着,执行下面的命令完成提交:
Bash | |
---|---|
1 2 |
|
再使用git push
将修改推送到远程仓库:
Bash | |
---|---|
1 |
|
可以看到整个过程中不需要处理任何冲突问题,同时也不影响到dev1
分支中的内容
最后,全部开发完毕需要将两个分支的内容全部合并到master
分支中,这里为了简便,首先将dev2
分支的内容使用提交Pull Request
的方式合并到master
分支中,再使用另外一种方式合并master
和dev1
分支的内容
首先,准备Pull Request
提交的申请:
接着,点击下面的内容准备进行审核:
再点击“提交”即可:
最后合并分支即可:
现在再看远程仓库的master
分支下的内容就可以看到dev2
分支的内容已经合并到master
分支中了
Info
在实际开发中,审核Pull Request
并不是由程序员来进行的,而是由专门的人员负责
接着就是合并dev1
分支下的内容,首先第一个开发者切换到master
分支:
Bash | |
---|---|
1 |
|
接着先进行git pull
拉取最新版本,再切换到dev1
分支下执行下面的命令:
Bash | |
---|---|
1 |
|
执行完成后,如果没有冲突就可以切换到master
分支进行合并,最后再将结果推送到远程仓库即可
至此,整个多人协作的过程就完成了,最后删除不需要的分支即可
企业开发模型¶
系统开发环境¶
- 开发环境:开发环境是程序猿们专门用于日常开发的服务器。为了开发调试方便,一般打开全部错误报告和测试工具,是最基础的环境
- 测试环境:一个程序在测试环境工作不正常,那么肯定不能把它发布到生产机上。该环境是开发环境到生产环境的过渡环境
- 预发布环境:该环境是为避免因测试环境和线上环境的差异等带来的缺陷漏测而设立的一套环境。其配置等基本和生产环境一致,目的是能让发正式环境时更有把握!所以预发布环境是产品质量最后一道防线,因为下一步项目就要上线了
- 生产环境:是指正式提供对外服务的线上环境,例如目前在移动端或PC端能访问到的APP都是生产环境
关系如下图所示:
Git分支设计规范与Git Flow模型¶
在实际开发中,一般会使用Git Flow
模型,该模型主要包含以下几个分支:
分支 | 名称 | 适用环境 |
---|---|---|
master | 主分支 | 生产环境 |
release | 预发布分支 | 预发布/测试环境 |
develop | 开发分支 | 开发环境 |
feature | 需求开发分支 | 本地 |
hotfix | 紧急修复分支 | 本地 |
下面是每一个分支的介绍:
master 分支
- master为主分支,该分支为只读且唯一分支。用于部署到正式发布环境,一般由合并
release
分支得到 - 主分支作为稳定的唯一代码库,任何情况下不允许直接在
master
分支上修改代码 - 产品的功能全部实现后,最终在
master
分支对外发布,另外所有在master
分支的推送应该打标签(tag)做记录,方便追溯 master
分支不可删除
release分支
- release为预发布分支,基于本次上线所有的
feature
分支合并到develop
分支之后,基于develop
分支创建。可以部署到测试或预发布集群 - 命名以
release/
开头,建议的命名规则:release/version_publishtime
release
分支主要用于提交给测试人员进行功能测试。发布提测阶段,会以release
分支代码为基准进行提测- 如果在
release
分支测试出问题,需要回归验证develop
分支看是否存在此问题 release
分支属于临时分支,产品上线后可选删除
develop分支
- develop 为开发分支,基于
master
分支创建的只读且唯一分支,始终保持最新完成以及bug修复后的代码。可部署到开发环境对应集群 - 可根据需求大小程度确定是由
feature
分支合并,还是直接在上面开发(非常不建议)
feature分支
- feature分支通常为新功能或新特性开发分支,以
develop
分支为基础创建feature
分支 - 命名以
feature/
开头,建议的命名规则:feature/user_createtime_feature
- 新特性或新功能开发完成后,开发人员需合到
develop
分支 - 一旦该需求发布上线,便将其删除
hotfix分支
- hotfix 分支为线上bug修复分支或叫补丁分支,主要用于对线上的版本进行 bug 修复。当线上出现紧急问题需要马上修复时,需要基于
master
分支创建hotfix
分支 - 命名以
hotfix/
开头,建议的命名规则:hotfix/user_createtime_hotfix
- 当问题修复完成后,需要合并到
master
分支和develop
分支并推送远程。一旦修复上线,便将其删除
下面是一个Git Flow
模型的示例:
gitGraph
commit id: "初始提交"
branch develop
checkout develop
commit id: "开发环境搭建"
branch "feature/功能1"
checkout "feature/功能1"
commit id: "功能1开发"
commit id: "功能1完善"
checkout develop
merge "feature/功能1" id: "合并功能1"
branch "feature/功能2"
checkout "feature/功能2"
commit id: "功能2开发"
checkout develop
merge "feature/功能2" id: "合并功能2"
branch "release/v1.0"
checkout "release/v1.0"
commit id: "提测修复"
commit id: "预发布准备"
checkout develop
merge "release/v1.0" id: "合并到开发分支"
checkout main
merge "release/v1.0" id: "v1.0发布" tag: "v1.0"
checkout main
branch "hotfix/bug修复"
checkout "hotfix/bug修复"
commit id: "紧急bug修复"
checkout main
merge "hotfix/bug修复" id: "修复上线" tag: "v1.0.1"
checkout develop
merge "hotfix/bug修复" id: "同步修复到开发分支"
checkout develop
commit id: "继续开发新功能"