1. 分支的应用场景
1.1 分支的必要性
几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。 在很多版本控制系统中,这是一个略微低效的过程——常常需要完全创建一个源代码目录的副本。对于大项目来说,这样的过程会耗费很多时间。
1.2 分支的类型
主分支
主分支有两种:master分支和develop分支
- master分支只负责管理发布的状态。在提交时使用标签记录发布版本号。
- develop分支是针对发布的日常开发分支。
特性分支
这个分支是针对新功能的开发,在bug修正的时候从develop分支分叉出来的。基本上不需要共享特性分支的操作,所以不需要远端控制。完成开发后,把分支合并回develop分支后发布。
release分支
release分支是为release做准备的。通常会在分支名称的最前面加上release-。release前需要在这个分支进行最后的调整,而且为了下一版release开发用develop分支的上游分支。
一般的开发是在develop分支上进行的,到了可以发布的状态时再创建release分支,为release做最后的bug修正。
到了可以release的状态时,把release分支合并到master分支,并且在合并提交里添加release版本号的标签。
要导入在release分支所作的修改,也要合并回develop分支。
hotFix分支
hotFix分支是在发布的产品需要紧急修正时,从master分支创建的分支。通常会在分支名称的最前面加上 hotfix-。
例如,在develop分支上的开发还不完整时,需要紧急修改。这个时候在develop分支创建可以发布的版本要花许多的时间,所以最好选择从master分支直接创建分支进行修改,然后合并分支。
修改时创建的hotFix分支要合并回develop分支。
这四种分支对应的切换图解
2. git分支
Git 的分支,其实本质上仅仅是指向提交对象的可变指针
要理解这句话,我们首先要理解,git的提交对象及树结构。
为了更加形象地说明,我们假设现在有一个工作目录,里面包含了三个将要被暂存和提交的文件。 暂存操作会为每一个文件计算校验和(使用我们在 起步 中提到的 SHA-1 哈希算法),然后会把当前版本的文件快照保存到 Git 仓库中(Git 使用 blob 对象来保存它们),最终将校验和加入到暂存区域等待提交:
$ git add README test.rb LICENSE
$ git commit -m ‘The initial commit of my project’
当使用 git commit 进行提交操作时,Git 会先计算每一个子目录(本例中只有项目根目录)的校验和,然后在 Git 仓库中这些校验和保存为树对象。 随后,Git 便会创建一个提交对象,它除了包含上面提到的那些信息外,还包含指向这个树对象(项目根目录)的指针。如此一来,Git 就可以在需要的时候重现此次保存的快照。
现在,Git 仓库中有五个对象:三个 blob 对象(保存着文件快照)、一个树对象(记录着目录结构和 blob 对象索引)以及一个提交对象(包含着指向前述树对象的指针和所有提交信息)。此时就产生了默认的master分支
首次提交对象及其树结构
当有改动之后再次提交,那么这次产生的提交对象会包含一个指向上次提交对象(父对象)的指针。
提交对象及其父对象
2.1 分支的curd
创建新的分支就相当于是将当前提交对象的HEAD,移动到其某个子提交对象上
- git brach a <⇒ 创建了一提交对象b,他的父提交对象是98ca9,同时将head移到该commit 上
- 查看人分支列表 git branch
2.2 分支的切换
2.2.1 准备工作
有的时候,我可能找某个分支进行开发某一功能,但未完成。这时要切换到另一个分支上, 此时就要做些准备工作。因为当前分支开发未完成,那此时 工作树,暂存区 是混乱的并且对于另一个分支是可见的,所以可能产生冲突。
- git 为我们提供了一个stash 操作,就是将当前分支的改动临时的存起来(存到 暂存栈)。
- git stash
- 查看暂存栈列表 git stash list
- 后来我们又想接着开上次未开发完的功能时,我们就需要的把上次临时存重新取到工作树
- 重新取到工作树,不删除stash记录
git statsh apply 重新取最新的那个 stash
git stash apply xxx 指定stash - 重新取到工作树和暂存区,不删除stash记录
git statsh apply --index xxx - 重新取到工作树,同时删除stash 记录
git stash pop
- 重新取到工作树,不删除stash记录
- 另外一种方式
2.2.2 切换
- 切换已存在的分支
git checkout xxx
-切换并创建新的分支
git checkout -b xxx
2.3 远程分支
2.3.1 查看
git ls-remote (remote) 来显式地获得远程引用的完整列表,或者通过
git remote show (remote) 获得远程分支的更多信息。
2.3.2 关联
git remote add 命令添加一个新的远程仓库引用到当前的项目
git fetch 更新你的远程仓库引用
git push origin serverfix
3.分支的合并
3.1 merge合并
3.1.1 快进(fast-forward)
不用进行其他的操作,直接移动HEAD
可以指定参数来进行非快进合并
3.1.2 非快进(none-fast-forward)
要进行其他的操作才能合并
如上图所示,bugfix与master 分支都有改动,要进行合并的话,就要把共同的父提交对象B, 提交对象D,提交对象Y 进行三方合并
这种合并方式会生成一个新的commit ,并且能保持原来分支的历史记录
3.2 rebase合并
rebase 操作又称为变基
将某个结点的提交 追加到目标结点的后面。
相关命令理解:
- git rebase --onto master server client
取出 client 分支,找出处于 client 分支和 server 分支的共同祖先之后的修改,然后把它们在 master 分支上重放一遍
- git rebase master server
如图 将 server 中的修改变基到 master 上 所示,server 中的代码被“续”到了 master 后面。
3.3 两种方式对比
- 两种方式的最终效果是一校的
- rebase 会修改记录
- 如果不是非常了解rebase话,建议使用 merge
- 不要对在你的仓库外有副本的分支执行变基。
4. 复制某个分支的commit
4.1 使用场景
- 我们commit 错了分支,想复制到另一个分支上
- 我们想把这个commit,复制到另一个分支上
4.2 使用命令
把修改移动到master分支后,用cherry-pick 取出「添加commit的讲解」提交,然后将其添加到master。(文档里的提交"99daed2"和下载到数据库里的提交有可能不相同。在下载的数据库里执行git log,确认是正确的提交之后再使用。)
$ git checkout master
Switched to branch ‘master’
$ git cherry-pick 99daed2
error: could not apply 99daed2… commit
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add ’ or 'git rm ’
hint: and commit the result with ‘git commit’