分支(Branch)是Git中的一项重要功能,它允许你从主线分支(通常被称为master
)开发的历史记录中创建新的开发路径。分支操作可以帮助你同时进行多个功能的开发,而代码不会互相干扰。这篇笔记我们介绍Git本地仓库中分支的使用。
我们可以使用以下命令查看当前版本库中有哪些分支。
git branch
如下图所示,我们可以看到我们的仓库中有master
和dev
两个分支,其中*
表示当前所在的分支。
创建一个分支需要基于一个已有的分支,假如我们当前位于master
分支,下面命令基于当前分支创建一个新分支。
git branch test
如果我们想要切换到新创建的分支,可以使用以下命令。
git checkout test
分支切换完成后,我们可以看到以下提示。
如果我们不再需要某个分支,可以使用以下命令删除它。
git branch -d test
有时,我们删除分支时可能看到类似如下的提示。
出现这个提示是因为要删除的分支包含了未合并到当前分支的提交,Git提示我们是否要强制删除这个分支。一般来说,如果我们确认所有需要的提交已合并,此时可以使用-D
参数来强制删除。
假设我们现在位于dev
分支,我们对仓库内容进行了修改并提交,此时我们想要将dev
分支合并到master
分支,可以使用以下命令。
git checkout master && git merge dev
合并需要我们首先切换到目标分支,然后再执行合并操作。合并完成后,我们可以看到以下提示。
如果两个分支同时对一个文件做了有冲突修改(改动了同一行),则合并分支后,我们需要手动将冲突解决。下面是一个合并分支时发生冲突的例子。
此时使用git status
命令查看工作区状态,我们可以看到Git提示我们手动对冲突进行处理。
我们可以使用Vim等编辑器查看文件的内容,Git帮我们将文件内容修改为了如下状态,其中<<<<<<< HEAD
和=======
之间的部分是当前分支修改的内容,而=======
和>>>>>>> dev
之间是dev
分支修改的内容,这两次修改位于不同分支,它们改动了同一行,是冲突的,当合并分支时,我们必须手动解决冲突。
HiHiHi~
<<<<<<< HEAD
HoHoHo!
=======
HoHoHo?
>>>>>>> dev
Hi, Tom.
Hello, world!
我们编辑文件,并将其修改为我们想要的形式,例如下面。
HiHiHi~
HoHoHo!?
Hi, Tom.
Hello, world!
修改完成后,我们可以再次提交,这样冲突就顺利解决了。
git add --all && git commit -m "合并dev分支解决README.md文件的冲突"
此外,我们可以发现,Git处理冲突时会在冲突行添加一些标记,这可能无意间破坏了我们的代码。实际开发中,我们通常不直接使用命令行和Vim处理冲突,大多数集成开发环境(IDE)都提供了图形化的冲突解决工具,直接使用这些工具更加方便,不过我们还是要了解这些图形化工具底层究竟做了什么。
注意:同一个文件添加了不同的行,通常并不会引起冲突,Git能够自动处理这种情况。
变基其实也是一种“分支合并”操作,但它和传统的分支合并不同,它是基于指定的分支基础将一组提交“移动”过去,简单来说就是将一个分支的提交应用到另一个分支上而不会创建新的提交,这和后面介绍的摘樱桃操作类似。由于变基本质上是提交的搬运而不是分支的合并,因此不会产生分支的合并记录,也不会在版本历史中体现出分叉的分支,变基合并后的分支仍是线性的。
下面例子中,我们从dev
分支通过变基“合并”到master
分支。
git rebase dev
如果没有冲突,输出例子如下。
如果存在冲突,冲突处理的方式和分支合并类似,只是提交冲突解决的方式和分支合并稍有不同。假设我们的冲突文件为README.md
,我们需要将变更添加到暂存区,然后执行git rebase --continue
命令。
git add README.md && git rebase --continue
当然,我们可以看到rebase其实就是起到类似于“美化”提交历史、提升提交历史可读性的作用,实际开发中如果你没有强迫症这种优化也不是特别必要,我们一般采用merge合并即可。
对于单人开发的小型项目,单分支模型其实已经足够应付了,但企业级的大型软件项目通常需要更复杂的分支管理策略,GitFlow就是其中一种。GitFlow是一种Git分支管理的参考模型,它基于Git的分支功能来组织和管理代码,并为不同的开发活动定义了清晰的分支策略。
GitFlow中,包含以下几种分支类型:
生产分支(master):仓库的主分支,只包含稳定的生产环境代码,对应于当前生产环境线上运行的软件版本。master分支通常只允许合并,不允许直接提交修改。
开发分支(dev):各种功能开发完成后都首先合并到dev分支进行集成测试,因此也叫集成分支。
发布分支(release):当软件发布新版本时,版本内上线的feature分支会逐一合并到release分支,然后统一将release分支合并到master分支。
功能分支(feature):feature分支通常对应于一个研发任务或一个程序员,feature开发完成后合并到dev分支进行测试,上线前合并到release分支。
热修复分支(hotfix):如果生产环境出现严重Bug需要紧急修复,此时需要基于master分支创建一个hotfix分支进行修复,修复完成后将hotfix分支合并到master分支和dev分支。
当然,这里并不是说我们的项目必须严格按照GitFlow工作流程来开发,GitFlow只是提供了一种参考,我们实际开发中,还是需要根据实际情况灵活调整,以满足我们的管理需要。
下面我们以例子形式介绍GitFlow工作流程。
假设某互联网公司开发了一个网络商城项目,程序员汤姆刚刚加入项目组,现在他将负责开发新功能“优惠券”。
feature_tom_coupon
。feature_tom_coupon
分支上,最终功能基本开发完成。feature_tom_coupon
分支到dev
分支上,持续集成系统被触发,并自动部署dev
分支的代码到测试服务器上,汤姆通知测试人员进行测试。feature_tom_coupon
分支上修改,修改完成后合并到dev
分支,并再次部署。feature_tom_coupon
分支合并到release_201801
分支,201801版本上线的其它功能代码也从其他同事的功能分支上陆续合并上来。release_201801
分支合并到master
分支,并通知实施人员201801版本代码已准备好。master
分支代码并部署到生产环境服务器,测试人员进行生产环境测试。master
分支创建了一个hotfix_tom_coupon
分支,并迅速编写代码。hotfix_tom_coupon
分支合并到dev
分支,并通知测试人员对开发环境进行测试。hotfix_tom_coupon
分支合并到master
分支,并通知实施人员部署生产环境代码,以及通知测试人员继续连夜测试生产环境。