熟悉git分支的原理是掌握了git的精髓,因为git和我们常用的源码管理系统有很大的区别和优点在分支上可以体现出来,一般我们常用的源码管理系统分支都是需要创建新目录,有全新的源码copy,一般都需要创建一个源代码目录完整的副本。对应大项目来说非常的耗费时间和空间。git正式因为其优秀的分支模式可以从源码管理系统中脱颖而出。因为git的分支非常的轻量级,他的操作机会瞬间完成,在不同的分支切换也非常快速。与其他版本相比,git更加推崇使用分支管理。分支是一个git非常强大和高效的工具。熟悉使用可以大大的提高工作效率和开发效率。
1、分支
git分支是如果存储数据,我们通过git数据存储的方式可以知道,存储一些列文件快照的方式。而一般常用的源码管理软件保存的基于文件版本差异的变化保存数据。
在git提交中,会保存一个提交(commit)对象,该对象包含一个指向暂存内容快照的指针,包括本次提交的作业的相关附属信息,包含零个或多个指向该提交对象的父对象指针,首次提交时没有直接的祖先,普通提交有一个祖先,由两个或多个分支合并产生的提交有多个祖先。
假如我们的工作目录有三个文件,准备将他们暂存后提交,暂存操作会对每一个文件计算校验和(Sha1哈希字符串)。然后把当前版本文件快照保存到git仓库中。git使用blob类型对象存储这些快照。并将校验和加入暂存区。
当使用git commit 新建一个提交对象前,git会计算每一个子目录或者项目的根目录的校验和,然后在git仓库中将这些目录保存为(tree)树对象。之后git创建的提交对象,除了包含相关提交信息之外,还包含指向这个树对象(项目根目录)的指针。如此他就可以在将来需要的时候,重现此次快照的内容。
$ git add test1.txt test2.txt test3.txt
$ git commit -m " this is the firt commit"
[master (root-commit) 680e70a] this is the firt commit
3 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 test1.txt
create mode 100644 test2.txt
create mode 100644 test3.txt
$ find .git/objects/ -type f
.git/objects/15/f2ed7f3d000ee95bf0e343f40eb892f622174d
.git/objects/30/758feb48e8bdba6ace1ecadf7bf2f89b94c115
.git/objects/5b/3c0c1c42386a00a8f81854b84628305f7082c7
.git/objects/68/0e70ac4e4376992c7d90905b8351badd233850
.git/objects/97/22bcfd0dcf84bbc82ce6095055010c011f91e6
以上是我刚刚创建的一个空的仓库,添加test1.txt test2.txt test3.txt 三个文件。添加到暂存区后,在。git/objects/ 对象中会新增加三个文件快照blog 对象。暂存.git/index 会指向对应的对象。首次提交到仓库后,仓库中在.git/objecs/目录中有5个对象。比在暂存区中增加了两个对象,是因为一个是根目录树(tree)对象。和一个提交commit 的对象。根目录tree对象指向三个文件blob的索引对象和保存文件内容的名称。而commit 对象会指向树对象,同时保存对象说明及相关的附属信息。仓库对象之间的关系图可以如下图。
当连续多次提及后,每次创建一个提交commit 对象会指向上一个提交的父对象。已经提交了三个对象,可以参照如下图:
$ git log --oneline
4d38d40 the third commit
66a1a2e the secomd commit
680e70a this is the firt commit
2、 创建分支
git bran branchname 这个命令会在当前活动分支的基础上创建一个新的分支。其实是在当前活动分支对象commit 新添加一个指向该对象的分支指针,如我们在现master 分支的基础上创建一个testing 分支。git branch testing 创建分支如下关系图:
git 当前活动分支,即工作分支是是哪个呢,可以通过命令git branch 查看,*号标示的就是当前活动分支。有一个head 特别指针保存着当前活动分支。具体物理地址是保存在.git/head 文件中,他指向的是一个分支名称,分支明确refs/heads/master 指向的是当前分支指向的commit 对象。他是指向当前工作本地活动分支的指针。看如下命令,我么可以通过git checkout branchname 转换分支。如git checkout testing 后就指向了testing 分支。看如下图转变过程。
$ git branch
* master
testing
$ ls .git/refs/heads
master testing
$ cat .git/refs/heads/master
4d38d402b3873d95c03cb3e1d2c65bf9aa3b5894
$ cat .git/refs/heads/testing
4d38d402b3873d95c03cb3e1d2c65bf9aa3b5894
$ cat .git/head
ref: refs/heads/master
$ git checkout testing
Switched to branch 'testing'
$ cat .git/head
ref: refs/heads/testing
当前活动分支是在testing 分支,我们在testing 分支做修改后提交。这是testing 分支指向最近一个提交。master 分支是指向当前提交的父提交commit 对象。
现在我们切换到master 分支,并把工作目录文件换成master分支指向的快照内容,现在所做的修改时在老的版本上做修改,在master 分支上做修改。修改不同余testing 分支另一条分支提交。如下图结果。
$ git commit -a -m "testing branch change"
[testing 0c8f2de] testing branch change
1 files changed, 1 insertions(+), 0 deletions(-)
$ git checkout master
Switched to branch 'master'
$ git commit -a -m "the master branch commit "
[master 1d37642] the master branch commit
1 files changed, 2 insertions(+), 0 deletions(-)
如现在我们需要把testing 分支和 master 分支合并。合并操作命令git merge branch name ,查看分支日志。
$ git merge testing
Merge made by the 'recursive' strategy.
test2.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
$ git log --oneline --graph
* ac631f6 Merge branch 'testing'
|\
| * 0c8f2de testing branch change
* | 1d37642 the master branch commit
|/
* 4d38d40 the third commit
* 66a1a2e the secomd commit
* 680e70a this is the firt commit
由于分支实际上仅仅是一个包含所指对象校验和(40个字符串长度的sha1字符串)文件。所以创建和销毁一个分支会非常的容易和廉价。实际上新建一个分支就是向一个文件写入41个字节(一个换行符)。指向一某个提交点。
正式由于这个特性和其它版本形成了特别鲜明的对比。原始的源码管理系统管理分支一般都采用备份所有项目文件到特定的目录,所以根据项目文件数量和大小不同,消耗的时间随着项目的大小时间也不同。而gti 无论项目大小不同,他的特性与项目的复杂度无关,永远可以在几毫秒内创建分支和切换分支。同时每次回记录和指向父对象。这位将来要合并对象对参照标准基础。
3、分支合并创建实例模型
分支创建和合并的例子,实际工作中工作流程
1、开发一个项目
2、为显示某个新的需求,创建一个新的分支。
3、在这个分支的开发
4、如果此时项目有bug需要立即修复需要在原先发布到生产环境的版本的分支。
5、为这次紧急bugfix 创建一个新的分支,并在其中修复问题。
6、bug修复没问题后,会到开发服务器生产分支,和修补分支合并,然后推送到生产服务器上。
7、所有一切都完成后,切换到之前新需求分支,继续工作。
接着刚刚写的范例,我们在主分支发布到生产环境后,已经推送到中心服务器,当前的状态如下图:
1、现在有新的需求需要开发,所以在当地master 分支上创建一个新的开发分支。然后再开发分支上做开发。用到的命令式git checkout -b dev ,相当于git branch dev ,git checkout dev 两条命令。当前工作活动分支是指向dev开发分支,我们在新的开发分支上做修改提交后。如下图:
$ git checkout -b dev
Switched to a new branch 'dev'
$ git commit -a -m "dev branch revise"
[dev 46324fb] dev branch revise
1 files changed, 1 insertions(+), 0 deletions(-)
现在正式的生产环境发现有bug 需要修复,现在我们不需要在创建和发布到修复服务器上花大力气做修改,现在需要做的只需要切回到master分支,然后再master 的分支上创建bugfix分支。在分支切回过程有一点需要注意的是。在暂存区和工作目录是否还没有提交的修改,如果他和你即将检出的分支产生冲突从而阻止切回分支。在切换分支前需要保持一个干净的工作区域。
$ git checkout master
Switched to branch 'master'
$ git checkout -b bugfix
Switched to a new branch 'bugfix'
$ git commit -a -m "bug fix branch commit"
[bugfix 7599941] bug fix branch commit
1 files changed, 2 insertions(+), 0 deletions(-)
在bugfix 分支上测试成功后,发现已经ok了,需要把master分支合并进来,然后推送到中心仓库服务器。先切换成到master 分支,然后git merge 合并bugfix 分支做合并,你会发现fast-forfward 合并,git只需要把master分支指针直接右移,如果顺着一个分支走下去可以到达另一个分支,那么在git 合并的时候,只会简单的把指针右移,因为这种单线历史分支不存在解决冲突和分歧。所以这种合并过程成为快进(fast forward). 当master 分支和bugfix 分支合并后,见下图,当前的bugfix 分支和master 分支会指向一个相同的提交对象。如果bugfix 分支已经没有存在的必要了,可以使用git branch -d branch 进行删除。
$ git merge bugfix
Updating ac631f6..7599941
Fast-forward
test1.txt | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
$ git log --graph --oneline
* 7599941 bug fix branch commit
* ac631f6 Merge branch 'testing'
|\
| * 0c8f2de testing branch change
* | 1d37642 the master branch commit
|/
* 4d38d40 the third commit
* 66a1a2e the secomd commit
* 680e70a this is the firt commit
$ git branch -d bugfix
Deleted branch bugfix (was 7599941).
以上bug修复完成后,可以切换到dev 分支,继续需求开发,可以将master 分支合并到dev 分支,或者等dev 版本开发完成后,再将dev分支更新到并入master.现在分支不同于hotfix 合并的方式,因为这次从历史ac631 处有分支同父对象,dev 和master 分支在进行合并的时候,会找到相同的祖先分支。ac631 和最新分支末端 46324fb 和 22ef87 进行一个三方合并运算,合并提交三个对象,git没有简单的把分支指正右移,而是三方合并结果做一个新的快照创建一个提交commit 对象1421fd5 。这个提交对象有两个祖先,有一点需要注意的是,git 可以决定哪个祖先是最佳合并的基础,这和CVS 和 SVN 不同,他们需要开发者手工合并基础,所以此特性合并操作会让git操作会比其它系统要简单许多。
$ git merge dev
Merge made by the 'recursive' strategy.
$ git log --oneline --graph
* 1421fd5 Merge branch 'dev'
|\
| * 46324fb dev branch revise
* | 22ef787 before dev merege commit
* | 7599941 bug fix branch commit
|/
* ac631f6 Merge branch 'testing'
|\
| * 0c8f2de testing branch change
* | 1d37642 the master branch commit
|/
* 4d38d40 the third commit
- 码云git使用四(分支的创建,使用和合并)
我们在使用git的时候,一般都不是直接在主代码中开发, 通常我们做的操作是创建一个分支,我们在分支上开发,开发完毕,在提交到主代码中. 我们现在学习创建分支,合并分支. 1.首先我们下载到本地都是在主 ...
- Git 初始化项目、创建合并分支、回滚等常用方法总结
就在刚才查看资料时候, 看见一句话, 写的特别好: 当我的才华撑不起我的梦想的时候, 应该安静下来学习 配上我最喜欢动漫的一个角色: 红莲 1. Git 初始化项目 1). 创建新的知识库 echo ...
- git 入门教程之冲突合并
如果足够幸运的话,团队成员互不影响,彼此相安无事,大家各自基于 master 分支的某个 commit 创建自己的分支,平时在分支上独立工作,等到一段时间后再合并 merge 到 master 分支, ...
- 前端项目中使用git来做分支和合并分支,管理生产版本
最近由于公司前端团队扩招,虽然小小的三四团队开发,但是也出现了好多问题.最让人揪心的是代码的管理问题:公司最近把版本控制工具从svn升级为git.前端H5组目前对git的使用还不是很熟悉,出现额多次覆 ...
- Git历险记(五)——Git里的分支&合并
分支与合并 在Git里面我们可以创建不同的分支,来进行调试.发布.维护等不同工作,而互不干扰.下面我们还是来创建一个试验仓库,看一下Git分支运作的台前幕后: $rm -rf test_branch_ ...
- git 基于某个分支创建分支
1.拷贝源代码 git clone git@git地址 cd 项目目录 2.根据已有分支创建新的分支 git checkout -b yourbranchname origin/oldbranchna ...
- git基于某个分支创建分支
1.git checkout -b 新分支名 老分支名 git checkout -b dev_20150909 master git ls -tree 分支名字
- Git——入门操作加创建账号【三】
创建账号 GitHub https://github.com/ 码云 https://gitee.com/ 无论是github还是码云,创建账号都是非常简单快捷的,大家可以自行选择创建下,不过建议最好 ...
- Git入门--创建版本库,关联远程库,从远程库下载
1.(先进入项目文件夹)通过命令 git init 把这个目录变成git可以管理的仓库 git init 2.把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点 ...
随机推荐
- NHibernate官方文档——第八章 继承映射(Inheritance Mapping)
本文翻译自NHibernate官方文档NHibernate Reference Documentation 4.1. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他 ...
- Python学习笔记——对象
Python 的对象定义方式如下: class Person: def __init__(self, name): self.name = name ...
- sql server 性能调优 资源等待之网络I/O
原文:sql server 性能调优 资源等待之网络I/O 一.概述 与网络I/O相关的等待的主要是ASYNC_NETWORK_IO,是指当sql server返回数据结果集给客户端的时候,会先将结果 ...
- vi中使用“/”查找字符
在vi 文件中使用"/"查找字符串 命令模式下,输入 /word 后回车,即查找word,按 n 查找下一个匹配单词,按 N 查找上一个匹配单词.
- CentOS6.5安装ganglia3.6
参考来源: 1.http://yhz.me/blog/Install-Ganglia-On-CentOS.html 2.http://blog.csdn.net/sdlyjzh/article/det ...
- JAVA_Exception starting filter struts2怎么办
1 请确保你的项目里面有这两个文件,没有则导入 2 如果还不行,并且你设置了Struts的开发模式,并且你的Tomcat的路径有空格,大部分情况是Program File的原因,此时你需要重新安装 ...
- ecplise内存配置
-server -Xms256m -Xmx512m -XX:PermSize=128M -XX:MaxPermSize=256m -XX:+UseG1GC
- react-native 中使用 mobx
1. 介绍 1.1. 原理 React的render是 状态 转化为树状结构的渲染组件的方法而MobX提供了一种存储,更新 状态 的方法React 和 MobX都在优化着软件开发中相同的问题.Reac ...
- xUtils介绍 -- DbUtils、ViewUtils、HttpUtils、BitmapUtils
转载注明出处:https://github.com/wyouflf/xUtils xUtils简单介绍 xUtils 包括了非常多有用的android工具. xUtils 支持大文件上传,更全面的ht ...
- Android下Fragment使用(全集)
1 http://blog.csdn.net/niu_gao/article/details/7163263 思路清晰,讲解详细,代码偏少,推荐高手阅读 2 http://blog.csdn.net ...