Git分支操作
Git分支操作

什么是分支
在版本控制过程中,同时推进多个任务,为每个任务,我们就可以创建每个任务的单独分支。使用分支意味着程序员可以把自己的工作从开发主线上分离开来,开发自己分支的时候,不会影响主线分支的运行。对于初学者而言,分支可以简单理解为副本,一个分支就是一个单独的副本(分支底层其实也是指针的引用)

分支的好处
同时并行推进多个功能开发,提高开发效率
各个分支在开发过程中,如果某一个分支开发失败,不会对其他分支有任何影响。失败的分支删除重新开始即可
分支的操作
| 命令 | 作用 |
|---|---|
git branch 分支名 | 创建分支 |
git branch -v | 查看分支 |
git checkout 分支名 | 切换分支 |
git merge 分支名 | 把指定的分支合并到当前分支 |
创建分支、查看分支
1)基本语法
git branch 分支名
git branch -v2)案例实操

切换分支
1)基本语法
git checkout 分支名2)案例实操

合并分支
1)基本语法
git merge 分支名2)案例实操
正常合并

冲突合并
冲突产生的原因:合并分支时,两个分支在同一个文件的同一个位置有两套完全不同的修改。Git无法替我们决定使用哪一个。必须人为决定新代码内容

解决冲突



提示
新版本git中新增了merge默认选项strategy="ort",对于相同文件的不同行的修改已经可以实现自动合并了。
只有在相同行都做了修改时,才会出现合并冲突。
实际案例
工作流程说明
- 开发某个网站。
- 为实现某个新的需求,创建一个分支。
- 在这个分支上开展工作。
正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补。 你将按照如下方式来处理:
- 切换到你的线上分支(production branch)。
- 为这个紧急任务新建一个分支,并在其中修复它。
- 在测试通过之后,切换回线上分支,然后合并这个修补分支,最后将改动推送到线上分支。
- 切换回你最初工作的分支上,继续工作。
Git 流
首先,我们假设你正在你的项目上工作,并且已经有一些提交

现在,你已经决定要解决你的公司使用的问题追踪系统中的 #53 问题。想要新建一个分支并同时切换到那个分支上
git checkout -b iss53
你继续在 #53 问题上工作,并且做了一些提交。 在此过程中,iss53 分支在不断的向前推进,因为你已经检出到该分支

!!!现在你接到那个电话,有个紧急问题等待你来解决
有了 Git 的帮助,你不必把这个紧急问题和 iss53 的修改混在一起,你也不需要花大力气来还原关于 #53 问题的修改,然后再添加关于这个紧急问题的修改,最后将这个修改提交到线上分支。你所要做的仅仅是切换回 master 分支
但是,在你这么做之前,要留意你的工作目录和暂存区里那些还没有被提交的修改,它可能会和你即将检出的分支产生冲突从而阻止 Git 切换到该分支。 最好的方法是,在你切换分支之前,保持好一个干净的状态。(提交你的所有修改)
git checkout master这个时候,你的工作目录和你在开始 #53 问题之前一模一样,现在你可以专心修复紧急问题了。 请牢记:当你切换分支的时候,Git 会重置你的工作目录,使其看起来像回到了你在那个分支上最后一次提交的样子。 Git 会自动添加、删除、修改文件以确保此时你的工作目录和这个分支最后一次提交时的样子一模一样
!!!接下来,你要修复这个紧急问题。让我们建立一个针对该紧急问题的分支(hotfix branch),在该分支上工作直到问题解决
git checkout -b hotfix
# 做出修改...
git commit -a -m 'fixed the broken email address'
!!!你可以运行你的测试,确保你的修改是正确的,然后将其合并回你的 master 分支来部署到线上。你可以使用git merge命令来达到上述目的
git checkout master
git merge hotfix快进合并
在合并的时候,有时候会出现"快进(fast-forward)"这个词

由于当前 master 分支所指向的提交是你当前提交的直接上游,所以 Git 只是简单的将指针向前移动。 换句话说,当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进合并”

!!!关于这个紧急问题的解决方案发布之后,你准备回到被打断之前时的工作中。 然而,你应该先删除 hotfix 分支,因为你已经不再需要它了—— master 分支已经指向了同一个位置。 你可以使用带-d选项的git branch命令来删除分支。现在你可以切换回你正在工作的分支继续你的工作,也就是针对 #53 问题的那个分支
git branch -d hotfix
git checkout iss53
你在 hotfix 分支上所做的工作并没有包含到 iss53 分支中。 如果你需要拉取 hotfix 所做的修改 ,你可以使用git merge master命令将master 分支合并入 iss53 分支,或者你也可以等到 iss53 分支完成其使命,再将其合并回 master 分支
git checkout master
git merge iss53典型合并
当前的合并和你之前合并 hotfix 分支的时候看起来有一点不一样。在这种情况下,你的开发历史从一个更早的地方开始分叉开来(diverged)。因为,master 分支所在提交并不是 iss53 分支所在提交的直接祖先,Git 不得不做一些额外的工作。出现这种情况的时候,Git 会使用两个分支的末端所指的快照(C4 和 C5)以及这两个分支的工作祖先(C2),做一个简单的三方合并

和之前将分支指针向前推进所不同的是,Git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。这个被称作一次 合并提交,它的特别之处在于他有不止一个父提交

需要指出的是,Git 会自行决定选取哪一个提交作为最优的共同祖先,并以此作为合并的基础;这和更加古老的 CVS 系统或者 Subversion(1.5 版本之前)不同,在这些古老的版本管理系统中,用户需要自己选择最佳的合并基础。Git 的这个优势使其在合并操作上比其他系统要简单很多
最终删除 iss53 号分支
git branch -d iss53冲突
有时候合并操作不会如此顺利。如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。如果你对 #53 问题的修改和有关 hotfix 的修改都涉及到同一个文件的同一处,在合并它们的时候就会产生合并冲突
此时 Git 做了合并,但是没有自动地创建一个新的合并提交。Git 会暂停下来,等待你去解决合并产生的冲突。你可以在合并冲突后的任意时刻使用git status命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件
任何因包含合并冲突而有待解决的文件,都会以未合并状态标识出来
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html在你解决了所有文件里的冲突之后,对每个文件使用git add命令来将其标记为冲突已解决。 一旦暂存这些原本有冲突的文件,Git 就会将它们标记为冲突已解决
分支的知识拓展
创建分支和切换分支图解


master、hot-fix 其实都是指向具体版本记录的指针。
当前所在的分支,其实是由 HEAD 决定的。所以创建分支的本质就是多创建一个指针
- HEAD 如果指向 master,那么我们现在就在 master 分支上
- HEAD 如果指向 hotfix,那么我们现在就在 hotfix 分支上
所以切换分支的本质就是移动HEAD指针
分支模式
长期分支(master)

许多使用 Git 的开发者都喜欢使用这种方式来工作,比如只在 master 分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。他们还有一些名为 develop 或者 next 的平行分支,被用来做后续开发或者测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入 master 分支了,等待下一次的发布。随着你的提交而不断右移的指针。稳定分支的指针总是在提交历史中落后一大截,而前沿分支的指针往往比较靠前

特性分支(topic)
特性分支对任何规模的项目都适用。特性分支是一种短期分支,它被用来实现单一特性或其相关工作。也许你从来没有在其他的版本控制系统(VCS)上这么做过,因为在那些版本控制系统中创建和合并分支通常很费劲。然而,在 Git 中一天之内多次创建、使用、合并、删除分支都很常见
分支本质
Git 分支,其实本质上仅仅是指向提交对象的可变指针。Git 的默认分支名字是 master。在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。它会在每次的提交操作中自动向前移动
注意: Git 的 “master” 分支并不是一个特殊分支。它就跟其它分支完全没有区别。之所以几乎每一个仓库都有 master 分支,是因为git init命令默认创建它,并且大多数人都懒得去改动它

分支原理
.git/refs 目录
这个目录中保存了分支及其对应的提交对象
HEAD 引用
当运行类似于git branch (branchname)这样的命令时,Git 会取得当前所在分支最新提交对应的 SHA-1 值,并将其加入你想要创建的任何新分支中。当你执行git branch (branchname)时,Git 如何知道最新提交的 SHA-1 值呢?答案是 HEAD 文件。HEAD 文件是一个符号引用(symbolic reference),指向目前所在的分支。所谓符号引用,意味着它并不像普通引用那样包含一个 SHA-1 值。它是一个指向其他引用的指针
