第四章、Git 分支

1. 分支简介

分支就是一个全新的提交路径。它是指在项目开发过程中,为了某个新功能,在不影响开发主线的情况下,脱离原来的开发主线独立创建一条新开发路径的方式。

通常我们把原来的开发主线叫做主分支 master。为了方便记忆和管理通常我们把新分离出来的分支取一个具有代表性的名字,如:developreleasemainfeature等。

通常在开发过程中有如下情况是比较适合建立分支:

  1. 开发新功能。
  2. 修复 Bug。
  3. 试验性开发
  4. 旧版本维护
  5. 多人协作开发

使用分支的好处如下:

  1. 并行开发互不影响。
  2. 隔离风险,试验性代码不会影响其它分支的稳定。
  3. 提高协作效率

Git 分支的基本原理和概念

Git 分支本质上是指向特定提交对象的轻量级可移动指针。你可以把分支理解成一个时间线上的标记点,代表着一个独立的提交对象链。

先来回顾一下我们常见的 my_project 工程,其中有两次提交,Git 本地仓库内部结果如下:

                 HEAD
                  |
              .--------.
              | master |
              `--------`
                  |
+-------+     +-------+
|8cb34d1| <-- |5dcccb0|
+-------+     +-------+
第一次提交      第二次提交

上图中,master 就是一个指针,它指向最后一个提交对象 5dcccb0,每个提交对象都有一个向前指向的指针,指向上一次提交,这样就形成了一个提交对象链。而每个提交对象链记录的完整的提交过程和记录。

HEAD 指针

HEAD 指针是正在操作的分支的指针。它记录了你正在操作的分支。

上图中 HEAD 指向了 master 分支对指针,也就意味着当前所有的操作都是在 master 分支上进行。如果改变正在操作的分支,只需要让 HEAD 指向其它的分支指针即可。

创建分支

现在在当前提交对象位置创建一个新的分支 test,则创建后的仓库结构如下:

                 HEAD
                  |
              .--------.
              | master |
              `--------`
                  |
+-------+     +-------+
|8cb34d1| <-- |5dcccb0|
+-------+     +-------+
                  |
              .--------.
              |  test  |
              `--------`

下载有两个分支指针,即 mastertest 这两个分支指针都指向了 5dcccb0 这个提交对象。从总体来看,这两个分支是一样的。它们都有两次提交,即提交历史 都是 8cb34d15dcccb0

现在 HEAD 指针还是指向 master 分支,因此所有的提交都会操作的是 master 指针。

切换分支

如果要操作 test 分支,此时需要切换分支,将当前分支切换到 test, Git 的做法是将 HEAD 指针指向 test 即可,如切换到 test 分支后,仓库的结构如下:

              .--------.
              | master |
              `--------`
                  |
+-------+     +-------+
|8cb34d1| <-- |5dcccb0|
+-------+     +-------+
                  |
              .--------.
              |  test  |
              `--------`
                  |
                 HEAD

提交版本

现在我们在 test 分支实现新功能1,然后提交一个新的版本。

当进行一次提交时,仓库内会新创建一个提交对象,这个提交对象会插在当前 HEAD 指向的分支的最后一个节点后,新创建的提交对象(假设是3333333)会指向之前的最后一个节点,然后分支指针指向次提交对象。最后形成这样一个结构。

              .--------.
              | master |
              `--------`
                  |
+-------+     +-------+
|8cb34d1| <-- |5dcccb0|
+-------+     +-------+
                  ^
                  |         +-------+
                  `-------- |3333333|
                            +-------+
                               |
                            .--------.
                            |  test  |
                            `--------`
                                |
                               HEAD

现在我们又需要在主分支上实现另外一个功能2,然后提交一个新的版本,此时需要切换回 master 分支(即将 HEAD 指针指向 master 指针),然后再进行一次提交,假设此次提交创建的提交对象是 4444444,则提交后的仓库结构如下:

                               HEAD
                                |
                            .--------.
                            | master |
                            `--------`
                               |
+-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |4444444|
+-------+     +-------+     +-------+
                  ^
                  |         +-------+
                  `-------- |3333333|
                            +-------+
                               |
                            .--------.
                            |  test  |
                            `--------`

经过一段时间的测试我们发现 test 分支实现的新功能稳定可靠。我们需要将其添加到 master 分支,此时需要将 test 分支合并到 master 分支(当然也可以将 master 分支合并到 test 分支),合并后会在 master 分支上有创建一个新的提交对象,假设是 555555。则合并后的结构如下:

                                             HEAD
                                              |
                                          .--------.
                                          | master |
                                          `--------`
                                             |
+-------+     +-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |4444444| <-- |5555555|
+-------+     +-------+     +-------+     +-------+
                  ^                         |
                  |         +-------+  <----+  合并版本
                  `-------- |3333333|
                            +-------+
                               |
                            .--------.
                            |  test  |
                            `--------`

合并后,master分支d的提交历史是 8cb34d15dcccb044444445555555,其中实现了所有的功能。而 test 分支的提交历史是 8cb34d15dcccb03333333

这样,功能1的开发和测试都在 test 分支上完成。待开发完成后我们将 test 分支上的某个提交合并到 master 即可。而此时 test 分支可以继续提交,当然也可以删除该分支。

使用 Git 进行版本控制时,可以创建多个分支,每个分支都可以合并到其它分支中。比较灵活和高效。Git 推荐使用分支进行版本控制。