前言
前面的一些概念的东西写的好像过于详细,下面的介绍将从简出发。这篇文章来说一下重要的分支。
分支
分支是软件项目中启动一条单独的开发线的基本方法。分支是从一种统一的、原始的状态分离出来的,使开发功能在多个方向上同时进行,并可能产生项目的不同版本。通常情况下分支会被调解与其它分支合并,来重聚不同的力量。
Git允许很多分支,因此同一个版本库中可以有许多不同的开发现。这也是处于不同地方的工作者可以对同一个项目进行开发的方法,每个单独修复的bug或者功能都可以是一个新的分支,这样的处理可以让庞大的项目显得更加清晰,回溯历史版本的时候也可以更容易找出问题的所在。
创建分支
新的分支基于版本库中现有的提交,由你来决定哪次提交作为分支的开始。Git支持任意复杂的分支结构,包括分支的分支和从同一个提交分叉出的多个给定的分支名可以在其版本库的整个生命周期里多次添加或删除。
一旦确定了从哪个提交开始分支,只需要使用git branch
命令,例如为了解决报告问题#1,要从当前分支的HEAD创建一个新的分支点,可以使用
$ git branch prs/prs-1
这条命令的基本形式是:
$ git branch branch [starting-commit]
如果没有指定的starting-commit,就默认在当前分支上的最近提交。也就是说,默认是在你现在的工作的地方启动一个新的分支。
需要注意的是,git branch命令指示把分支名引进版本库,并没有去改变工作目录去使用新的分支,没有工作目录文件发生变化。直到你切换到它。
列出分支名
git branch命令列出版本库中的分支名。
$ git branch
* master
prs/prs-1
prs/prs-2
这里显示了三个分支,当前已检出到你的工作目录的分支用星号标记。如果没有额外的参数,则只列出版本库中的特性分支,可以用-r选项列出那些远程追踪分支,也可以用-a选项把特性分支和远程分支都列出来。
查看分支
git show-branch命令提供比git branch 更详细的删除,按时间以递序的形式列出对一个或多个分支的有贡献的提交。
$ git show-branch
* [master] add line4 and line5
! [prs/prs-1] fixed prs-1
! [prs/prs-2] add line2 and line3
-----
* ++ [master] add line4 and line5
+ [prs/prs-2] add line2 and line3
*++++ [prs/prs-1] fixed prs-1
git show-branch的输出被一排破折号分为两部分。分隔符上方的部分列出分支名,并且用方括号括起来,每行一个。
输出的下半部分是一个表示每个分支中提交的矩阵。每个提交后面跟着该提交中日志消息的第一行。如果有一个加号(+)、星号(*)或减号(-)在分支的列中,对应的田炯就会在该分支中显示。加号表示提交在一个分支中,星号突出显示存在于活动分支的提交,减号表示合并一个分支。
检出分支
工作目录一次只能反映一个分支。要在不同的分支上开始工作,要发出git checkout命令。给定一个分支名,git checkout会使该分支成为当前工作分支。它改变了工作树文件和目录结构来匹配给定的分支状态。但是Git会采取措施来使你避免丢失未提交的工作数据。
Git会让你访问版本库的所有状态,从分支的最前端到项目的最开始。这是因为每次提交会捕获在一个给定时刻版本库完整状态的快照。
$ git branch
* master
prs/prs-1
prs/prs-2
$ git checkout prs/prs-1
Switched to branch ‘prs/prs-1’
$ git branch
master
* prs/prs-1
prs/prs-2
工作树中的文件和目录结构已更新来反应新的分支的状态和内容。工作目录中的文件已经发生了变化以符合该分支顶端的状态。
选择一个新的当前分支可能会对工作树文件和目录结构产生巨大影响,改变的程度取决于当前分支和你检出分支之间的差异。改变分支的影响有:
- 在要被检出的分支哄但不在当前分支中的文件和目录,会从树对象库中检
出并放置到工作树上。 - 在当前分支中但不在要被检出的分之中的文件和目录,会从工作树中删除
- 这两个分支都有的文件会被修改为要被检出的分支的内容。
有未提交的更改是进行检出
毫无疑问,这样是不能检出成功的,如果数据没有被提交,一但检出覆盖,那么未提交的数据会丢失。Git会发出如下错误消息,并拒绝检出目标分支。
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
hello.txt
Please commit your changes or stash them before you switch branches.
Aborting
此时你需要提交然后才可以检出为新的分支,或者合并变更到不同分支。
工作目录的当前状态与你想切换到的分支相冲突,我们需要的是一个合并:工作目录中的改变必须要被检出的文件合并。
检出时使用-m参数,git通过在你的本地修改和对目录分支之间进行一个合并操作,尝试将你的本地修改加入到新的工作目录中。
$ git checkout -m master
Switched to branch 'master'
M hello.txt
在这里,Git已经修改了hello.txt文件,并成功检出master分支。
$ cat hello.txt
hello world
<<<<<<< master
<<<<<<< HEAD
add line4
add line5
=======
add line2
add line3
add line2
add line3
>>>>>>> prs/prs-2
=======
test uncommit checkout
>>>>>>> local
进行这种合并时一定要小心,虽然它看起来合并的很干净并且一切都没有问题。这个命令有时候也十分有用,当你在一个分支上耗费了大量的时间之后,发现这不是你想要提交的分支,可能你会陷入抓狂,这个命令可以替你解决问题,不过工作的时候一定要注意分支。
创建并检出新的分支
另一种比较常见的情况是当你想创建一个分支并同时切换到它,Git提供了一个快捷方式-b new-branch来处理这种情况。
$ git checkout -b prs/prs-4
Switched to a new branch 'prs/prs-4'
$ git show-branch
! [master] fixed commit
! [prs/prs-1] fixed prs-1
! [prs/prs-2] add line2 and line3
! [prs/prs-3] add line4 and line5
* [prs/prs-4] fixed commit
! [rel-2.3] add line4 and line5
------
+ * [master] fixed commit
- - [master^] fixed conflit
+ + * [prs/prs-2] add line2 and line3
+ +*+ [prs/prs-3] add line4 and line5
++++*+ [prs/prs-1] fixed prs-1
以下这个命令
$ git checkout -b new-branch start-point
与两个命令序列是等价的:
$ git branch new-branch start-point
$ git checkout new-branch
删除分支
Git阻止你删除当前工作分支,删除当前分支将导致Git无法确定工作目录树应该是什么样的。必须始终选择一个非当前分支。还有一个问题,Git不会让你删除一个包含不存在于当前分之中的提交的分支。也就是说,如果分支被删除则开发的提交部分就会丢失,Git会阻止你意外删除提交中的开发。
$ git branch -d prs/prs-3
Deleted branch prs/prs-3 (was 03b66ff).
Git不会保持任何形式的关于分支名创建,移动,操纵,合并或者删除的历史记录,一旦某个分支删除了,它就没了。但是,该分支的提交历史记录是一个独立的问题。Git最终会删除那些不再被引用的提交和不能从某些命名(如分支和标签名)的引用的可达的提交。如果你想保留那些提交,必须将它们合并到不同的分支,为它们创建一个分支,或者用标签指向它们,否则,如果没有对他们的引用或者提交,blob是不可以达的,最终将被 git gc工具当成垃圾回收。
注:意外删除分支或其他引用后,可以使用git reflog命令恢复。
总结
这篇大概讲解了分支的使用方法和切换,理解分支的工作原理很重要,下一篇是关于分支之间的合并问题,产生冲突时的解决方法。Git鼓励的就是小规模频繁的提交,这就有利于将问题细致化,一个分支解决一个问题,虽然有点杀鸡用牛刀的意思。所以这个模式有时候会不可避免地产生一些冲突,怎么正确的解决冲突也相当重要。