几乎所有的版本控制系统都以某种形式支持分支。使用分支意味着我们可以把我们的工作从开发主线分离开来,从而影响开发主线。在很多版本控制系统中,效率稍低这个过程——通常需要完全创建一个源代码目录的副本。对于大项目来说,这样的过程会消耗很多时间。
有人把 Git 的分支模型称为它的“必杀技术特性”,也正因为这种特性,使得 Git 从队列版本控制系统中移动。为何 Git 的分支模型如此出众呢? Git 处理分支的方式就好比是速度非常轻,创建新分支这一操作几乎可以瞬间完成,并且在不同分支之间的切换操作也同样快捷。与许多其他版本控制系统不同,Git 鼓励在工作流程中间隔地使用分支与合并,这一天之内进行了许多次。理解并掌握了这一特性,我们就会意识到 Git 的强大的独特性,从而真正改变我们的开发方式。
使用git branch
可以查看现有分支或创建新的分支。
当不带任何命令参数时,输入git branch
可以帮助我们查看当前项目所拥有的全部分支。并且Git会使用*
来标明我们当前所处的分支上。
$ git branch
当我们在git branch
后面加上<branchname>
即可创建新分支:
$ git branch <branchname>
$ git branch
使用git checkout <branchname>
命令切换分支:
$ git checkout <branchname>
$ git branch
切换分支后,我们就可以进行自己的开发。分支上的文件状态是不同的。我们可以通过下面的例子有着更深入的了解。
# 切换分支
$ git checkout issue102
# 在分支上创建新的文件
$ touch issue102.md
$ git add issue102.md
$ git commit -m "update issue102.md"
$ touch issue102.html
$ git add issue102.html
$ git commit -m "update issue102.html"
在完成上述命令后,通过git log --oneline
检查下当前Git的记录。
git log --oneline
当我们在分支上完成来开发工作后,我们需要将我们在当前分支进行的工作合并到主分支上。首先我们需要切回需要合并到的分支上,此处以issue102
合并到main
上为例子进行演示:
# 切换回主分支
$ git checkout main
# 使用git merge进行合并
$ git merge issue102
# 查看所有未合并工作的分支
$ git branch --no-merged
有时候分支的合并不会一番顺利,当我们在两个分支中对同一个文件的同一个部分进行了不同的修改,Git就没有办法顺利的合并他们,会在合并的时候产生合并冲突。比如我们在issue102
分支和main
分支下对issue102.md
文件进行了修改,当我们将issue102分支融合到主分支上时就会发生冲突。如下图所示:
我们也可以通过git status
查看命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件。当出现矛盾后,合并的文件内容将会出现"<<<<<<“,”====“,”>>>>>>"等分割线来进行标记。如下图所示:
当出现矛盾时,我们需要进行手动合并
或者放弃合并
。
手动合并的方法很简单,即我们选择要保留的代码,然后把>>>>>, ====, <<<<<<这些提示行给去掉。最后重新进行add commit的操作即可。
当冲突所导致的改动量很大时,我们可以选择放弃该次的合并。使用git merge --abort
放弃此次的融合。如果我们在运行了git merge之后又进行了一些人为的改动,那么在abort之后,所进行的改动也会被回滚掉。
除了手动合并以及放弃合并之外,git官方开发了一个专门用来合并的工具,叫做git mergetool,它会将找到一份两个分支的祖先代码作为base(基准),然后再将两个分支的改动都列举出来作为对比,让我们在git编辑器当中决定要留下什么。
我们可以使用git remote -v
查看远程库的详细信息。这会显示我们可以抓取或推送的origin地址。
$ git remote -v
当我们需要推送本地分支到远程时,需要指定具体的本地分支:
# 推送本地的main分支到远程
$ git push origin main
# 推送本地的issue102分支到远程
$ git push origin issue102
当我们多人协作进行开发的时候,我们就需要使用git pull
的命令来试图合并。如果合并出现冲突时,我们需要解决冲突再提交。参考多人协作。
Git的分支删除可以分为删除本地分支
和删除远程分支
。
$ git branch -d <branchname>
# -D 表示强行删除分支
$ git branch -D <branchname>
# origin 是远程的主机名
# branchname 需要删除的远程分支名
$ git push origin --delete issue102
$ git branch -m oldBranchName newBranchName
当我们想要将改名后的分支推送到远程时,我们需要进行如下操作:
$ git branch -m oldBranchName newBranchName # 将本地的分支进行重命名
$ git push origin newBranchName # 将新的分支推送到远程
$ git push --delete origin oldBranchName # 删除远程的旧的分支
当我们已经了解了分支的操作后,我们应该考虑使用一种怎样的方式使我们最大化的使用分支操作的优点。在接下来的这部分中,将会介绍一些常见的分支开发工作流程。而正是由于分支管理的便捷,才衍生出这些典型的工作模式,我们以后可以根据项目实际情况进行使用。
因为 Git 使用简单的三方合并,所以即使在一段短暂的时机,反复把一个分支合并到另一个分支中,也不是难事。也就是说,在整个项目开发周期的不同阶段,我们可以同时拥有多个开放的分支,可以定期地把某些主题分支合并到其他分支中。
许多使用 Git 的开发者都喜欢使用这种方式来工作,比如只在main
分支上保留完全稳定的代码——有可能已经发布或即将发布的代码。他们还有一些叫做develop
或者next
的分支,被用来做后续开发或者测试稳定性——这些分支必须保持稳定,一旦达到稳定状态,它们就可以被合并入main
分支了。
一些大型项目还有一个proposed
(建议)或pu: proposed updates
(建议更新)分支,它可能因包含一些不成熟的内容而不能进入next
或者main
分支。
短期分支也叫做主题分支,它对任何规模的项目都适用。主题分支是一种短期分支,它被用来实现单一功能或者相关工作。比如bug分支
、issue分支
、develop分支
、topic分支
。
分支开发工作流程基本原则:
master分支应该是最稳定的,也就是仅用来发布新版本,平时不能直接在上面进行操作,应该保存在远程。
短期分支是我们干活的分支,短期分支可以不用上传到远程,当我们完成了bug的修复,新功能的开发时才需要合并到主分支上。
多使用分支来进行开发工作。