分支简介
假设现在有一个工作目录,里面包含了三个将要被暂存和提交的文件。
暂存操作会为每一个文件计算校验和(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 对象索引)以及一个提交对象(包含着指向前述树对象的指针和所有提交信息)
图1 首次提交对象及其树结构
修改后再次提交,提交对象会包含一个指向上次提交对象(父对象)的指针
图2 提交对象及其父对象
Git 的分支,其实本质上仅仅是指向提交对象的可变指针
分支创建
它只是创建了一个可以移动的新指针。 比如,创建一个 testing 分支, 使用 git branch 命令:
$ git branch testing
两个指向相同提交历史的分支
名为 HEAD 的特殊指针,可以理解为当前分支的别名,git branch 只是创建一个新分支,并不会自动切换到新分支上去
HEAD 指向当前所在的分支
分支切换
$ git checkout testing
HEAD 指向当前所在的分支
查看各个分支当前所指的对象
$ git log --oneline --decorate
f30ab (HEAD, master, testing) add feature #32 - ability to add new
34ac2 fixed bug #1328 - stack overflow under certain conditions
98ca9 initial commit of my project
会输出你的提交历史、各个分支的指向以及项目的分支分叉情况
$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) made other changes
| * 87ab2 (testing) made a change
|/
* f30ab add feature #32 - ability to add new formats to the
* 34ac2 fixed bug #1328 - stack overflow under certain conditions
* 98ca9 initial commit of my project
分支新建与合并
任务:工作分支-->线上分支-->新建分支-->修改bug-->合并新分支和线上分支-->推送线上分支-->删除新建的分支-->回到工作分支
$ git checkout -b iss53
Switched to a new branch "iss53"
$ git branch iss53
$ git checkout iss53
创建一个新分支指针
开始在iss53分支修改
$ vim index.html
$ git commit -a -m 'added a new footer [issue 53]'
iss53 分支随着工作的进展向前推进
现在你接到那个电话,有个紧急问题等待你来解决。假设你已经把你的修改全部提交了,这时你可以切换回master 分支了:
$ git checkout master
Switched to branch 'master'
这个时候,你的工作目录和你在开始 #53 问题之前一模一样,现在你可以专心修复紧急问题了。
建立一个针对该紧急问题的分支(hotfix branch),在该分支上工作直到问题解决:
$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'fixed the broken email address'
[hotfix 1fb7853] fixed the broken email address
1 file changed, 2 insertions(+)
基于master 分支的紧急问题分支hotfix branch
然后将其合并回master 分支来部署到线上。 使用git merge 命令来达到上述目的:
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
master 被快进到 hotfix
删除hotfix分支,因为你已经不再需要它了, master 分支已经指向了同一个位置。 你可以使用带-d 选项的git branch 命令来删除分支:
$ git branch -d hotfix
Deleted branch hotfix (3a0874c).
切回iss53继续开发
$ git checkout iss53
Switched to branch "iss53"
$ vim index.html
$ git commit -a -m 'finished the new footer [issue 53]'
[iss53 ad82d7a] finished the new footer [issue 53]
1 file changed, 1 insertion(+)
继续iss53分支上的工作
注意:你在hotfix 分支上所做的工作并没有包含在iss53 分支中
合并iss53到master分支
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)
master
分支所在提交并不是 iss53
分支所在提交的直接祖先,Git 不得不做一些额外的工作。 出现这种情况的时候,Git 会使用两个分支的末端所指的快照(C4
和 C5
)以及这两个分支的工作祖先(C2
),做一个简单的三方合并。
一次典型合并中所用到的三个快照
git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。 这个被称作一次合并提交,它的特别之处在于他有不止一个父提交。
一个合并提交
删除iss53分支
$ git branch -d iss53
分支管理
git branch: 分支列表
git branch -v: 查看每个分支的最后提交
git branch --merged: 查看哪些分支已经合并到当前分支中
git branch --no-merged: 查看哪些分支没有合并到当前分支中
分支开发工作流
- 长期分支:比如develop, next, 用来做后续开发或测试稳定性,一旦到达稳定状态,就合并到master分支
渐进稳定分支的流水线(“silo”)视图
- 特性分支:一种短期分支,用来实现单一特性或短期工作,比如iss53和hotfix
远程分支
克隆之后的服务器与本地仓库
你在本地的 master
分支做了一些工作,同一时间,其他人推送提交到 git.ourcompany.com
并更新了它的 master
分支,那么你的提交历史将向不同的方向前进。 也许,只要你不与 origin 服务器连接,你的 origin/master
指针就不会移动
本地与远程的工作可以分叉
要同步你的工作,运行 git fetch origin
命令。 这个命令查找 “origin” 是哪一个服务器(在本例中,它是 git.ourcompany.com
),从中抓取本地没有的数据,并且更新本地数据库,移动 origin/master
指针指向新的、更新后的位置
git fetch 更新你的远程仓库引用
跟踪分支
从一个远程跟踪分支检出一个本地分支会自动创建一个叫做 “跟踪分支”(有时候也叫做 “上游分支”)。 跟踪分支是与远程分支有直接关系的本地分支
git checkout -b [branch] [remotename]/[branch]
等同于:
git checkout --track [remotename]/[branch]
比如:
git checkout -b serverfix origin/serverfix
git checkout --track origin/serverfix
想为本地分支与远程分支设定不同的名字:
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'
删除远程分支
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
- [deleted] serverfix
变基
整合分支有两种方法:merge(合并)及rebase(变基)
分叉的提交历史
通过合并操作来整合分叉了的历史
变基:提取在 C4
中引入的补丁和修改,然后在 C3
的基础上应用一次。 使用 rebase
命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
将C4 中的修改变基到C3上
回到master, 快速合并
$ git checkout master
$ git merge experiment
master 分支的快进合并
参考资料:https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E6%96%B0%E5%BB%BA%E4%B8%8E%E5%90%88%E5%B9%B6