分支是在软件项目中启动一条单独的开发现的基本方法。分支是从一种统一的,原始的状态分离出来的,使开发能够在多个方向上同时进行,并可能产生项目的不同版本。通常情况下,分支会被用来与其他分支合并,来重聚不同的力量。
1,为什么要使用分支?
在项目功能人多较多的情况下,可以利用分支进行功能点的切分;在团队协作中,如果Git只有一条版本演进的轨迹,那么轨迹中的代码可能会非常混乱,许多成员会实时的提交自己的代码,而自身的代码页在与轨迹中的代码经常不一致,使用分支则能降低这种混乱,成员只有在自己已开发完成的功能代码后,才会将代码合并到主分支。
2,分支名
分支的取名尽管有一定的限制,但是基本上是任意的。
版本库中的默认分支命名为 master,这并没有什么神奇的地方,如果愿意,可以重命名甚至删除 master 分支,但是建议不要这么干。
建议创建一个带有层次的分支名,类似于 UNIX/Linux 的路径名。例如,开发团队正在修正大量的bug。在bug分支下建立不同的分支,例如 bug/fix-1234 和 bug/2345。使用层次分支命名的其中一个愿意是Git是支持通配符的,可以一次性选择所有bug分支:
git show-branch 'bug/*'
分支名的一些规范:
2-1,可以使用斜杠(/)创建一个分层的分支名。但是,该分支名不能以斜杠(/)结尾;
2-2,分支名不能以减号(-)开头;
2-3,以斜杠分隔的分层不能以点(.)开头。如 bug/.fix-1111 这样的分支名是无效的;
2-4,分支名的任何地方都不能包含两个连续的点(..);
2-5,分支名不能包含任何空格或空白字符,在Git中具有特殊含义的字符也不能包括。包括波浪号(~),插入府(^),冒号(:),问号(!),星号(*),左方括号([)。
这些分支的命名规则是由 git check-ref-format 底层命令强制检测的,它保证分支的名字不仅容易输入,而且在 .git 目录中作为一个文件名是可用的。
3,使用分支
在Git版本库中可能会存在许多不同的分支,但是有且最多只有一个活动分支(当前分支)。活动分支决定在工作区中检出哪些文件。
默认情况下,master 分支是活动分支,但是可以把任何分支设置成活动分支。
分支允许版本库中的每一个分支的内容向许多不同的方向发散,当一个版本库中分出至少一个分支时,把每次提交到某个分支,取决于哪个分支是活动的。
每个分支在特定的Git版本库中必须有唯一的名称,这个名字始终指向该分支上最新提交的版本。一个分支的最新提交称为该分支的头部(tip或head)。
一个分支包括足以重建整个项目历史记录的提交,沿着分支来自的路径,可以通过所有路径回到项目最开始的地方:
4,创建分支
新的分支是基于版本库中现有的提交的。完全由我们自己来决定并指定哪次提交作为新分支的开始。
一个分支的生命周期同样是由我们来决定的。一个分支可能稍纵即逝,也可能长久留存。
一旦确定了从哪一个提交开始一个分支,就只需要使用 git branch 命令了:
git branch <branchname> [starting-commit]
如果没有指定的 starting-commit,就默认为当前分支上的最新提交。
注意:git branch 命令只是把 分支名 引进Git版本库而已。并没有改变工作目录去使用新的分支。说白点就是 git branch 命令只是在给定的提交上创建一个命名的分支。
例如:接到一个修复 BUG#1234 的任务,我们可以创建一个分支来进行:
看见没,只是创建了一个名为 bug/fix-1234 的分支,当前分支还是 master 。
5,列出分支名
git branch 命令就可以列出版本库中的分支名;
如果没有额外的参数,则只列出版本库中的本地分支;
可以用 -r 选项列出有哪些远程分支;
也可以用 -a 选项把本地分支和远程分支都罗列出来;
6,查看分支
git show-branch 命令提供了比 git branch 更为详细的输出,按照时间降序排列。与 git branch 一样,没有选项择列出本地分支,-r 显示远程分支,-a 显示所有分支。
git show-branch 的输出被一排破折号(--)分为两个部分。
分隔符上部分列出 分支名,并用方括号([])括起来,每行一个。最前面用感叹号或星号(如果是当前分支)标记。
分隔符下部分是一个表示每个分支中提交的矩阵:
如果有加号(+),星号(*)或减号(-)在分支名之前,对应的提交就会在该分支中显示:
加号表示提交在一个分支中;
星号突出显示存在于活动分支的提交;
减号表示一个合并提交;
7,检出分支
本节前面提到,工作区一次只能反应一个分支。要在不同的分支上开始工作,就要执行 git checkout 命令。
给定一个分支名,git checkout 会使用该分支名切换变成新的当前分支。
git checkout 命令会改变工作树文件和目录结构,以此来匹配给定分支的状态:
7-1,检出分支的一个简单示例
假设工作区是干净的,现在来修复bug#1234:
ok,现在模拟修复bug#1234,添加一个bug@1234.txt的文件,内容随意:
至此,在bug/fix-1234下的工作已经提交到版本库了。
7-2,有未提交的更改时进行检出
在执行 git chekout 的时候,工作区中的未被Git跟踪的文件和目录始终会置之不管。
但是,如果一个文件的本地修改不同于新分支上的变更,在 git checkout 时,Git会发出如下错误消息,并拒绝检出目标分支:
这是什么原因呢?可以检查文件 hello.txt 在工作目录和目标分支中的内容:
可以看出 hello.txt 在两个分支中的不同,而且前面已经介绍过 git checkout 命令是会重写工作区的。默认情况下,Git检测到检测到这种潜在的损失,并防止它发生。
如果真的不在乎对工作区的丢失,可以通过 -f 选项进行强制覆盖(git checkout -f <branch>),但是建议少这样做。
后面会介绍一阵更为优雅的解决方式来面对这种问题。
7-3,合并变更到不同分支
当工作区当前状态与想切换到的分支相冲突时,可能需要的是一个合并工作:工作目录中的改变必须和被检出的文件合并。
使用 git checkout 命令的 -m 选项,Git通过在你的本地修改和目标分支之间进行一次合并操作,尝试将你的本地修改加入到新的工作区中。
这个操作有点类似 svn update 命令:本次修改与目标分支合并,并保留在工作去中。
然后,在这些情况下,一定要小心,虽然 git chekout -m <branch> 看起来合并得很 干净并且一切没有问题,但是Git已经简单地修改了文件并留下了其中的合并冲突指示,我们还必须手动解决存在的冲突:
后面会有一个章节专门介绍合并和解决合并冲突的有用技巧。
7-4,创建并检出新分支
有一种比较常见的情况:当想创建一个新的分支并且同时切换到该分支。
Git提供了一个更为快捷的方式来处理这种情况,git checkout -b <new-branch>
该命令等价于下面的两条命令:
git branch <new-branch> [starting-commit]
git checkout <branch>
8,删除分支
命令 git branch -d <branch> 会从版本库中删除一个分支,但是Git会阻止删除当前分支,因为删除当前分支会导致Git无法确定工作区目录树(tree)。
但是删除一个非当前分支会有一个小问题:Git不会让你删除一个包含不存在于当前分支中的提交的分支。
这是什么意思呢?就是如果一个非当前分支包含一个独有的文件,其他分支都没有,那么这个非当前分支是不能删除的,因为删除该分之后,其中包含的独有文件就没有访问入口了。
看下面的图片:
在 bug/fix-2345 分支下创建文件"bug#2345.txt",提交到版本库,切换到 master 分支,删除 bug/fix-2345 分支,Git阻止掉,并提示我们 bug/fix-2345 没有进行合并,如果依然像删除分支,则使用 git branch -D bug/fix-2345(大小写敏感哟)。
Git并不强制要求所有分支在可以删除之前必须合并到 master 分支。反而,Git会防止你在不合并到当前分支的分支被删除时,不小心而导致的内容丢失,所以我们现在要做的就是合并 bug/fix-2345 分支到当前分支,然后就可以安心删除它了
ok,分支管理就到这,关于合并和解决冲突后面会有一个章节具体来介绍。