前面对git基础作了简单的总结,这次对git的杀手锏--分支做一总结。

Git分支简介

  几乎每个版本控制系统都以某种形式支持分支,可以使你的工作从开发主线上分离开来,以免影响开发主线。很多版本控制系统常常要创建一个源代码目录的副本,略微低效。而Git保存的不是文件的差异和变化,而是一些列不同时刻的文件快照。当进行commit操作的时候,Git会保存一个提交对象(commit object),该提交对象包含作者的姓名和邮箱,提交时输入的信息,指向父对象的指针和一个指向暂存内容快照的指针,首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象,而由多个分支合并产生的提交对象有多个父对象。

  形象的说,工作目录下有三个文件,暂存操作会为每个文件计算校验和,并把当前版本的文件快照使用blob对象保存到Git仓库中,最终将校验和添加到暂存区中等待提交,当进行commit提交时,Git先会计算每一个子目录的校验和,然后在Git仓库中将这些校验和保存为树对象,随后Git就会创建一个提交对象,除了上面提到的还会保存这个树对象的指针,就可以在需要时重现此次保存的快照。此时Git 仓库中有五个对象:三个 blob 对象(保存着文件快照)、一个树对象(记录着目录结构和 blob 对象索引)以及一个提交对象(包含着指向前述树对象的指针和所有提交信息)。

  做些修改后再次提交,那么这次产生的提交对象会包含一个指向上次提交对象(父对象)的指针。

  Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 它会在每次的提交操作中自动向前移动。

创建分支 git branch

git branch testing                         ##创建testing分支,但不会切换到testing分支

这会在当前提交对象上创建一个指针。Git有一个名为HEAD的特殊指针,指向当前所在的分支。

你可以用git log 命令查看各个分支当前所指的对象,--decorate 参数提供此命令

$ git log --oneline --decorate
472aa16 (HEAD -> testing, master) all      ## testing,master分支均指向校验和为472aa16的提交对象
24a207f add
de99f0e all

切换分支 git checkout

git checkout testing                 ## 切换到testing分支,这是HEAD就指向testing

这时,做些修改提交一次,看提交历史

$ git log --oneline --decorate
c2183f6 (HEAD -> testing) new branch       ## 这里可以看到HEAD指向testing分支,testing分支向前移动,master分支却没变化
472aa16 (master) all
24a207f add
de99f0e all

这是切换回master分支,

git checkout master                    ##切换回master

此时其实是两步操作,一是使HEAD指向master分支,二是将工作目录恢复至master分支所指向的快照内容,也就是说忽略了刚才testing分支下的修改。

再做一次提交后,运行 git log --oneline --decorate --graph --all ,它会输出你的提交历史、各个分支的指向以及项目的分支分叉情况

$ git log --oneline --decorate --graph --all
* 2b6f868 (HEAD -> master) new tt.txt       ## HEAD指向master,一次添加文件的提交
| * c2183f6 (testing) new branch          ## testing分支上次提交的校验和为c2183f6的提交对象
|/
* 472aa16 all
* 24a207f add

 分支的新建与合并

实际工作中,你可能会遇到类似的工作流。开发一个项目,为实现某个功能,创建一个分支iss,在分支iss上开展工作。此时有一个bug急需处理,你将按如下方式处理:

  1. 切换到你的线上分支(production branch)。

  2. 为这个紧急任务新建一个分支,并在其中修复它。

  3. 在测试通过之后,切换回线上分支,然后合并这个修补分支,最后将改动推送到线上分支。

  4. 切换回你最初工作的分支iss上,继续工作。

首先,你运行带参数-b的git checkout命令创建了iss分支并切换到iss分支,是git branch iss和git checkout iss两个命令的简写

git checkout -b iss                        ## 新建分支iss,参数-b表示并切换到iss分支

你已经做了一些提交,HEAD已经指向iss,此时修复bug,就需要切换到master分支,新建fix分支来处理bug,在切换分支前要要留意你的工作目录和暂存区里那些还没有被提交的修改。当切换分支的时候,Git会重置工作目录,使其看起来像回到了你在那个分支上最后一次提交的样子。

git checkout -b fix                     ## 新建并切换到fix分支,修改bug

合并分支 git merge

bug修改完成提交后,你要与master分支合并,就需要先切换到master分支,然后再合并

$git checkout master                    ## 切换回master分支
$ git merge fix                ## 合并fix分支
Updating 558d34c..0f49f4e
Fast-forward                      ## 快进
index.html | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 index.html

你会注意到Fast-forward这个词,是由于master分支是需要合并的fix分支直接上游,git只是简单的将指针移动。也就是说当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧,就叫做Fast-forward.

删除分支 git branch -d

$ git branch -d fix                     ## 删除不需要的fix分支
Deleted branch fix (was 0f49f4e).

现在切换回iss分支,由于在fix上的修改没有包含到iss中,你可以用git merge master命令将master合并到iss分支,也可以等iss完成修改后合并回master分支

$ git merge iss
Merge made by the 'recursive' strategy.    ## 合并提交
tt.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

由于master分支所在的提交不是iss分支所在提交的直接祖先,Git会把两个分支的末端所指的快照(0f49f4e和88502d9),以及这两个分支的工作祖先(558d34c),进行一个简单的三方合并,合并结果不是简单的快进(Fast-forward),而是生成了个新的快照(ce91eb7)并创建一个新的提交指向它,这个过程是一次合并提交,合并完成后就可以删除iss分支了。需要说明,Git 会自行决定选取哪一个提交作为最优的共同祖先,并以此作为合并的基础。

$ git log --oneline --decorate --graph --all
* ce91eb7 (HEAD -> master) Merge branch 'iss' ## 合并提交后生成一个新的快照,并指向新的提交
|\
| * 88502d9 (iss) iss                ## iss分支的最后一次提交
| * 8de2c03 second
| * be76065 new iss
* | 0f49f4e fix               ## master分支的最后一次提交
|/
* 558d34c all                  ## iss分支和master分支的工作祖先
* 863dcdc test

遇到冲突时的分支合并

如果在两个不同的分支中,对同一文件的同一部分进行了不同的修改,Git就无法自动合并。使用git status命令就会看到发生冲突的文件,打开冲突的文件,(=======)分割的上段为当前分支master的修改,下段为iss的修改,删除冲突标识符,手动修改保留一个分支的修改,对每个文件使用git add命令表示冲突已解决,git commit来完成合并提交

<<<<<<< HEAD
master edit.
=======
iss edit.
>>>>>>> iss

分支管理

$ git branch                         ## 列出当前所有分支的一个列表,*表示HEAD指向的分支
iss
* master
$ git branch -v                   ## 参数-v查看每个分支的最后一次提交
iss 5735ce0 iss edit
* master 3ab0a47 merge
$ git branch --merged                 ## 查看已合并到当前分支的分支
iss
* master
$ git branch --no-merged                ## 查看未合并到当前分支的分支
testing
$ git branch -d testing                 ## 未合并的分支删除时,如果你确认需要删除,参数-D强制删除
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.

分支开发工作流

长期分支:

只做简单的快进合并,反复的把一个分支合并到稳定的分支。常常会只在master分支保留完全稳定的代码(有可能仅仅是已经发布或即将发布的代码),还有一些develop或next的平行分支,被用来做后续开发或测试稳定性,这些分支不必保持稳定状态,一旦达到稳定状态就可以合并到稳定的master分支。可以用这种方法维护更多层次的分支。

特性分支:

特性分支对任何规模的项目都适合。性分支是一种短期分支,它被用来实现单一特性或其相关工作。之前的iss分支和fix分支就是这种用法。在iss和fix分支中提交一些更新,合并到主干后又删除它们,这样能使你快速并完整的切换,更容易的看出做了哪些改动。你可以在改动的特性分支中保留很久,等成熟后再合并。

请牢记:当你新建和合并分支的时候,所有这一切都只发生在你本地的 Git 版本库中 —— 没有与服务器发生交互。

远程分支

远程引用是对远程仓库的引用(指针),包括分支和标签等等。可以用git remote show获取远程分支的更多信息,但常用的做法是远程分支跟踪。远程跟踪分支是远程分支状态的引用。它们以(remote)/(branch)的形式存在。远程仓库的名字origin跟分支master,没有什么特殊的含义,master是git init时默认的分支名字,origin是git clone时远程仓库默认的名字。

git fetch origin 从远程抓取仓库origin中本地没有的数据。

推送

当需要公开分享一个分支时,将其推送到一个有写入权限的远程仓库,本地的分支不会自动的与远程的仓库同步,你必须显示的推送你想要分享的分支。这样你就可以把不愿分享的内容放到私人分支上,需要和别人协作的内容放到公开的分支上。

git push origin serverfix                ## 推送本地的 serverfix 分支来更新远程仓库上的 serverfix 分支
git push origin serverfix:serverfix     ## 推送本地的 serverfix 分支,将其作为远程仓库的 serverfix 分支
git push origin serverfix:awesomebranch      ## 推送本地的 serverfix 分支,将其作为远程仓库的 awesomebranch 分支,给远程分支改名

其他协作者从服务器上抓取数据时,就会在本地生成一个远程分支origin/serverfix,指向服务器serverfix分支的引用。但当抓取新的远程跟踪分支时,本地不会自动生成一个可编辑的副本,即不会有一个新的分支serverfix,只是一个不可修改的origin/serverfix的指针。可以运行 git merge origin/serverfix 将这些工作合并到当前所在的分支。

如果想要在自己的 serverfix 分支上工作,可以将其建立在远程跟踪分支之上:git checkout -b serverfix origin/serverfix

跟踪分支

从一个远程跟踪分支检出一个本地分支会自动创建一个叫做 “跟踪分支”。 跟踪分支是与远程分支有直接关系的本地分支。 如果在一个跟踪分支上输入git pullGit 能自动地识别去哪个服务器上抓取、合并到哪个分支。当克隆一个仓库时,它通常会自动地创建一个跟踪 origin/mastermaster 分支。如果想跟踪其他分支,就运行git checkout -b [branch] [remotename]/[branch]。因为比较常用Git提供了--track快捷方式。

git checkout --track origin/serverfix          ## 跟踪远程分支serverfix
git checkout -b sf origin/serverfix         ## 本地分支与远程分支设置不同的名字
git branch -u origin/serverfix           ## 设置已有的本地分支跟踪一个刚刚拉取下来的远程分支,或者想要修改正在跟踪的上游分支
git branch -vv                     ## 查看设置的所有跟踪分支

git branch -vv 查看每一个分支正在跟踪哪个远程分支与本地分支是否是领先、落后,这些都是与最后一次抓取的数据作比较,要想统计最新的需要在git branch -vv前先执行git fetch --all命令抓取所有的远程仓库。

拉取

当用git fetch命令从服务器抓取本地没有的数据时,不会修改工作目录中的内容,只会让你自己合并。git pull命令大多数情况下是执行git fetch后接着执行git merge。如果设置好跟踪分支,git pull都会查找当前分支所跟踪的服务器与分支,从服务器上抓取数据然后尝试合并入那个远程分支。所以通常单独显式地使用 fetchmerge 命令会更好一些。

删除远程分支

如果远程分支的工作已经完成并合并到远程仓库的master分支,就可以用带有--delete选项的git push命令删除远程分支了。

$ git push origin --delete serverfix            ##从服务器上删除 serverfix 分支

基本上这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。

变基

变基一般是为了确保在向远程分支推送时能保持提交历史的整洁,修改了提交历史。但请记住不要对在你的仓库外有副本的分支执行变基。

总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作。变基就不做说明了。

Git笔记先写到这。下次用到更高级的功能继续补充。

git学习笔记之二 -- git分支的更多相关文章

  1. Git学习笔记(二)分支管理与合并及Bug分支

    一.分支管理 1.什么是分支 分支就相当于我们看科幻片里的平行宇宙,如果两个平行宇宙互不干扰,那铁定是啥事儿没有.不过,在某个时间点,两个平行宇宙合并了呢?假如两个宇宙中都有你的影子, 合并之后相当于 ...

  2. Git学习笔记(二) · 非典型性程序猿

    远程库的使用 前面说到的都是git在本地的操作,那么实际协作开发过程中我们肯定是要有一个远程版本库作为项目的核心版本库,也就是投入生产使用的版本.这里我们以 Github为例.Github是一个开放的 ...

  3. git 学习笔记 —— 保留/丢弃当前分支修改并切换至其他分支

    笔者在本地终端进行 git 工作目录的相关处理时,遇到由于某种情况需要使用 git checkout 命令切换到其他分支的情景.此时,若已经对当前分支做了一定的修改,则直接切换分支时 git 会提示错 ...

  4. Git学习笔记(二)

    一.创建远程仓库(GitHub) 1.GitHub网站地址:https://github.com/,这个网站就是提供Git仓库托管服务的,所以,只要注册一个GitHub账号,就可以免费获得Git远程仓 ...

  5. git——学习笔记(三)分支管理

    一.创建.合并分支 每次提交,git都往后走一格,串成一跳时间线,head指向的是分支,分支指向提交.master是主分支,dev是另一条分支,分支就像指针一样,合并.删除分支时,修改的都是指针,工作 ...

  6. git——学习笔记(二)远程仓库

    GIT杀手锏之一——远程仓库 拥有远程仓库的两个办法 1:搭一个Git服务器  2:在GitHub上免费托管的Git仓库 本地仓库   远程仓库 一.在GitHub上免费托管的Git仓库 电脑: 1. ...

  7. git学习笔记(四)—— 分支管理

    一.创建与合并分支 git branch //查看分支 git branch <name> //创建分支 git checkout <name> //切换分支 git chec ...

  8. git学习笔记(二)—— 创建版本库&&版本管理

    一.创建版本库 创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录: mkdir gitHub_CXWcd gitHub_CXW git init Initialized empty G ...

  9. Git学习笔记(5)——分支管理

    本文主要记录了分支的原理.分支的创建,删除,合并.以及分支的使用策略. 分支在实际中的作用 假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不 ...

随机推荐

  1. 兔子生娃问题---函数递归应用--c语言实现

    事情是这样的:在很久很久以前....有一对兔子,从出生后第 3 个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 兔子的规律为数列:1, 1 ...

  2. Plupload上传插件简单整理

    Plupload Plupload是有TinyMCE的开发者开发的,为您的内容管理系统或是类似上传程序提供一个高度可用的上传插件.Plupload 目前分为一个核心API 和一个jQuery上传队列部 ...

  3. 常用PHP函数整理

    is_upload_file() 判断文件是不是通过HTTP POST 方式上传来的in_array() 判断变量在不在数组范围内move_uploaded_file() 将上传的临时名移到指定文件夹 ...

  4. 使用VB6写一个自定义的进度信息框窗口

    一.起因说明 之前有些项目是用Access完成的,当时为了给用户显示一些进度信息,自制了一个进度信息窗体,类似下图所示: 随着项目不断变迁,需要将进度信息按阶段及子进度进行显示,并且出于代码封装的需求 ...

  5. 提高 webpack 构建 Vue 项目的速度

    前言 最近有人给我的 Vue2 后台管理系统解决方案 提了 issue ,说执行 npm run build 构建项目的时候极其慢,然后就引起我的注意了.在项目中,引入了比较多的第三方库,导致项目大, ...

  6. robotium问答

    robotium问答   robotium集成instrumentation robotium如何定位控件? search类获取当前所有的view,然后根据类型或者文本去筛选,找到view后获取坐标, ...

  7. Dubbo配置方式详解

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是阿里巴巴 SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次 ...

  8. Java集合常见面试题集锦

    1.介绍Collection框架的结构 集合是Java中的一个非常重要的一个知识点,主要分为List.Set.Map.Queue三大数据结构.它们在Java中的结构关系如下: Collection接口 ...

  9. 自行扩展 FineUIMvc 通知对话框(多个并排显示不重叠,支持最新的显示在最上方)

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 这篇文章我们将改造 FineUIMvc 默认的通知对话框,使得同时显示多个也不会重叠.并提前出一个公共的JS文件,供大家使用. ...

  10. 4 安装MPush

    cnblogs-DOC 1.服务器环境 2.安装Redis3.安装Zookeeper4.安装MPush5.安装Alloc服务6.完整测试7.常见问题 一.Linux安装Mpush [root@loca ...