Git教程 · 分支
- 1️⃣ 并行式开发
- 2️⃣ 修复旧版本中的 bug
- 3️⃣ 分支
- 4️⃣ 当前活跃分支
- 5️⃣ 重置分支指针
- 6️⃣ 删除分支
- 7️⃣ 清理提交对象
- 🌾 总结
对于版本提交为什么不能依次进行,以便形成一条直线型的提交历史记录,我们认为有 以下两个重要原因。
- 有两个以上的开发者在对同一个项目进行并行式开发。
- 为修复旧版本中的 bug 而必须要创建和发布新的版本。
如果遇到以上两种情况,我们的提交历史图中就会出现分叉的情况。
1️⃣ 并行式开发
当有多个开发者用 Git 处理同一个软件开发项目时,他们就会在版本库的提交图中创建 各自的分支。下面我们来看下图, 其上半部分所显示的是两个独立的开发者在各自的本 地版本库中,基于提交B 成功创建了各自的版本(即提交C 和 D) 。 而在图的下半部分, 你将看到的是它们合并之后的版本库(关于合并的相关细节请参见后续文章)。正如你所见,它创建了一个分支,这种类型的分叉在并行式开发中是难以避免的。
2️⃣ 修复旧版本中的 bug
正如我们之前所说,分支可能会因并行式开发的需要 而创建。但除此之外,它也有可能会因修复软件旧版本中 的 bug 而创建。下面我们来看一个例子(见下图):假设 当开发者们正在为即将发布的版本(提交 C 和 D) 加班加点时,我们在该软件的当前版本(提交B) 中检测到了一个错误。由于眼下带有新功能的提交 C 和 D 都还没有 准备好交付,用于错误修复的提交 E 只能基于提交 B 来创建。
3️⃣ 分支
下面再来看看下图,在这个例子中,我们一方面在 release1 这一当前发行版上继续当前 开发分支 master 上的工作。随着各轮新的提交,该分支始终处于活跃向前的状态。而另一方面,我们会看到 release1 分支从右边岔开了,它对自身的bug 进行了修复。
分支可以看作是开发过程当中的并行线,我们可以把该提交图想象成游泳池中的泳道(见 下图)。
注意:Git并不知道某次提交是否被分配给了某个分支,划分泳道在这里某些程度上来 说算是一种比喻性的说法。
4️⃣ 当前活跃分支
在一个 Git 版本库中,总是唯一存在着一个活动分支。我们可以用 branch
命令(不带选
项)来列出当前所有的分支。其中用星号 (*
) 凸显的就是当前的当前活跃分支。
> git brancha-branch
* masterstill-a-branch
一般情况下,活动分支将会被继续用于接受所有新的提交,并将分支指针移动至最近的
那次提交。当然,我们也可以用checkout 命令来改变当前的活跃分支。
> git checkout a-branch
下面,我们来创建一个新的分支。
1a. 为当前提交创建分支git branch a-branch
1b. 为任意一批提交创建分支
我们也可以为任意一批提交创建新的分支。为此,我们必须要指定该分支上的第一次提交。git branch still-a-branch 38b7da45e
1c. 从现有分支中创建分支
git branch still-a-branch older-branch
2.切换到新分支
branch
命令只能用于创建新的分支,但并不会自动切换到该新分支上。如果我们想要
切换到新的分支上,就得使用checkout
命令。git checkout a-branch
快捷方式:创建并切换到新分支
git checkout -b a-branch
通常情况下,我们可以用 checkout 命令在分支之间来回切换。但是,如果这时候工作 区还存在着一些修改,我们就必须要先决定好如何处理这部分修改。
-
进行 Checkout
下面这个checkout 很可能会被拒绝。> git checkout a-brancherror:Your local changes to the following files would be overwritten by checkout:foo.txtPlease,commit your changes or stash them before you can switch branches.Aborting
如你所见,工作区或暂存区存在着一些修改,它们还没有被确认为一次提交。所以我们必须先决定以下何种方式来处理这些修改。
-
提交修改并切换
> git commit --all > git checkout a-branch
-
放弃这部分修改并进行切换
我们可以用 --force 选项来进行强制切换,但这样做会令这部分修改被覆盖!> git checkout --force a-branch
-
储藏修改并切换
我们可以用stash
命令先将这部分修改储藏起来,然后再进行切换。 之后再用stash pop
命令来恢复它们。> git stash > git checkout a-branch
5️⃣ 重置分支指针
分支指针主要用于指向活动分支,它会每次提交时移动到最新提交上。因此在通常情况 下,我们几乎不太需要去直接设置分支指针。但偶尔我们也会因一些偶发事件而失去对该指针的跟踪,想将其恢复到之前的状态。在这种情况下,我们可以用 reset
命令来重置分支指针。
> git reset --hard 39ea2la
这样一来,该指针就被重置到了提交39ea21a 所在的活动分支上。其中的 --hard
选项用于确保工作区和暂存区也都会被设置都提交39ea21a 的状态。
需要提醒的是,reset --hard
命令会覆盖当前工作区和暂存区中的所有修改。所以最好在 执行重置之前先用 git stash
命令存储一下这些修改。
6️⃣ 删除分支
我们可以通过branch -d
命令来删除分支。
-
删除一个已被终止的分支
> git branch -d b-branch
-
删除一个打开的分支
如果我们在试图删除一个分支时自己还未转移到不同的分支(例如 master分支)上,Git 就会给出一个警告,并拒绝该删除操作。如果你坚持要删除该分支的话,就需要在命令中使用-D
选项。error: The branch 'b-branch' is not fully merged. If you are sure you want to delete it,run 'git branch -D b-branch'. > git branch -D b-branch Deleted branch b-branch(was 742dcf6).
Git会自行负责分支的管理,所以当我们删除一个分支时,Git只是删除了指向相关提 交的指针,但该提交对象依然会留在版本库中。因此,如果我们知道删除分支时的散列信
息,就可以将某个已删除的分支恢复过来。
- (在已知提交的散列值的情况下) 恢复某个分支
1.1. 先确定相关的提交散列值> git branch a-branch 742dcf6
如果我们不知道想要恢复分支的提交散列值,可以reflog
命令将它找出来。
1.2. (通过> git reflogd765ale HEAD@{0}: checkout: moving from b-branch to master88117f6 HEADC{1}: merge b-branch:Fast-forward9332b08 HEAD@{2}: checkout: moving from a-branch to b-branch 441cdef HEAD@{3}: commit: Expanded important stuff
reflog
命令找到的散列值) 恢复该分支> git branch b-branch HEAD@{1}
7️⃣ 清理提交对象
gc
命令(gc 指的是垃圾回收) 可用于清理版本库,移除所有不属于当前分支的提交对象。 如果我们想进一步净化自己的版本库,可以先将它克隆一份,并删除其源版本库。
🌾 总结
- 提交图中的分叉:主要是因为修复旧版本 bug 以及并行式开发的需要。
- 分支:上述提交图中出现的那个分叉就叫做分支。该分支会有一个指针,指向该分支 下的最后一次提交。
- 当前活跃分支:我们平常工作所在的就是所谓的当前活跃分支。当新的提交发生时, 该分支指针就会知道被设置到该新提交上。
- 创建分支:我们可以用
branch
命令来新建分支。 - checkout: 我们可以用
checkout
命令切换到另一个分支上。 - Reflog: git 会记录我们在每次提交中对分支指针所做的所有修改。如果你想恢复某个不小心删除的分支,这是非常有用的工具。
- 垃圾处理:对于那些不属于任何分支前身的提交,我们将其视为垃圾,可以用
gc
命令将其清理掉。
《【Git教程】(四)版本库 —— 存储系统,存储目录,提交对象及其命名、移动与复制~》
1