Git使用详解(图文+代码):Git分支

news2024/9/29 21:20:10

Git分支不过如此

    • 前言
      • 什么是分支
      • 分支的新建与合并
        • 分支的新建与切换
        • 分支的合并
        • 遇到冲突时的分支合并
        • 分支的管理
        • 先写到这了,肝不动了。这几天每天都抽时间更新一点

前言

每一种版本控制都以某种形式支持分支。
使用分支的好处就是你可以从开发主线上分离开来,在不影响主线的同时继续工作。
在之前的版本控制系统中,这个是奢侈昂贵的操作,经常需要创建一个源代码目录的完整副本,对大型项目来说花费大量时间。
有了Git分支模型,将Git从版本控制系统家族区分出来,它以难以置信的轻量级,新建操作几乎可以在瞬间完成,并且在不同分支见切换起来也超快。
Git在工作流程中频繁使用分支与合并,当你理解分支的概念并熟练运用后,你才会意识到为什么Git是一个强大独特的工具,并且会改变你的开发方式。

什么是分支

我们要想理解Git分支的实现方式,需要回顾一下Git是如何储存数据的。
Git保存的不是文件的差异或者变化量,而是一系列文件快照。
在Git提交时,会保存一个提交对象,该对象包含一个指向暂存内容快照的指针,包含本次提交的作者等相关附属信息,包含0个或n个指向该提交对象的父对象指针:首次提交是没有直接祖先的,普通提交有一个祖先,2个或n个分支合并产生的提交则有多个祖先。

在这里我们举个栗子:
假设工作目录有三个文件,准备将它们暂存后提交。
在这里插入图片描述

暂存操作会对每一个文件计算校验和(SHA-1哈希字串),然后把当前版本的文件快照保存到Git仓库中(使用blob类型的对象存储这些快照),并将校验和加入暂存区域:
先执行git add README test.rb LICENSE
在这里插入图片描述

然后执行git commit -m “initial commit of my project”
在这里插入图片描述

当git commit 新建一个提交对象前,Git会先计算每一个子目录(本栗子中就是项目根目录)的校验和,然后在Git仓库中将这些目录保存为树(tree)对象。
之后Git创建的提交对象,除了包含相关提交信息以外,还包含这个树对象(项目根目录)的指针,如此它就可以在将来需要的时候,重现此次快照的内容了。

不要蒙兄弟们,我们来分析一下:
现在Git仓库中有五个对象:
三个表示快照内容的blob对象(之前聊过,文件是由blob方式储存的);
一个记录着目录树内容以及各个文件对应blob对象索引的tree对象;
一个包含指向tree对象(根目录)的索引和其他提交信息元数据的commit对象。

用个图来解释就是:
在这里插入图片描述

图(1-1)——单个提交对象在仓库中的数据结构

做些修改再次提交,那么这次提交对象包含一个指向上次提交对象的指针(下图中的parent对象)。两次提交后,仓库历史会变成下图的样子:

在这里插入图片描述
图(3-2)——多个提交对象之间的链接关系


现在来谈分支。
Git分支,本质上仅仅是指向commit对象的可变指针。GIt会使用master作为分支的默认名字。
在若干次提交后,我们其实已经有一个指向最后一次提交对象的master分支,它在每次提交的时候都会自动向前移动。
在这里插入图片描述
图(3-3)——某个提交对象往回看的历史

那么,Git又是如何创建一个新的分支的呢?答案很简单,创建一个新的分支指针。
比如新建一个testing分支,我们使用git branch命令

$ git branch testing

这会在当前commit对象上新建一个分支指针:
在这里插入图片描述
图(1-4)——多个分支指向提交数据的历史

有个问题:Git是如何知道你当前在哪个分支上工作的呢?
答:它保存着一个名为HEAD的特别指针。
在Git中,它表示一个指向你正在工作中的本地分支的指针(理解为当前分支的别名就行)
我们之前仅仅是建立一个新的分支,但不会自动切换到这个分支上去,所以我们现在易燃还在master分支里工作:
在这里插入图片描述
在这里插入图片描述
如果我们要切换到其他分支,执行git checkout命令:
在这里插入图片描述
这时候HEAD就指向了testing分支:
在这里插入图片描述
图(1-6)——HEAD转换分支时指向新的分支

可能你会问了 ,感觉有点麻烦,这样做带给我们什么好处?

我们再提交一次就可以发现里面的秘密:

$ vim test.rb
  $ git commit -a -m 'made a change'

在这里插入图片描述
展示提交后的结果:
在这里插入图片描述
图(1-7)——每次提交后HEAD随着分支一起向前移动
所以你可以看到,testing向前移动了一格,而master仍然指向原先git checkout时所在的commit对象,现在我们回到master分支看看:

$ git checkout master

在这里插入图片描述
在这里插入图片描述
图(1-8)——HEAD在一次checkout之后移动到了另一个分支
我们解读一下:这条命令做了两件事情,它把HEAD指针移动到了master分支,并且把工作目录中的文件换成了master分支所指向的快照内容。
也就是说,现在开始所做的改动,将始于本项目中较老的版本。
它的主要作用是将testing分支里作出的修改暂时取消,这样我们就可以向另一个方向进行开发。
我们作些修改后再次提交:
执行代码

$ vim test.rb
    $ git commit -a -m 'made other changes'

在这里插入图片描述
现在我们的项目提交历史产生了分叉,因为刚才我们创建了 一个分支,转换到其中做了一些工作,然后又回到原来的主分支进行了另外一些工作。
这些改变分别孤立在不同的分支里:我们可以在不同分支里反复切换,并在时机成熟时把它们合并到一起。而所有这些工作,仅仅需要branchcheckout这两条命令就可以完成。
在这里插入图片描述
图(1-9)不同流向的分支历史
由于Git分支实际上仅仅是一个包含所指对象检验和(40个字符长度SHA-1字串)的文件,所以创建和销毁一个分支就变得非常廉价了。

分支的新建与合并

我们举个例子来说:
1.开发一个网站。
2.实现某个需求,创建一个分支。
3.在这个分支上开展工作。
此时,突然接到一个电话说出了一个bug很严重需要紧急修补,那么我们可以按照下面的方式处理:
1.返回到原先已经发布到生产服务器上的分支。
2.为这次紧急修补建立一个新分支,并在其中修复问题。
3.通过测试后,回到生产服务器所在的分支,将修补分支合并起来,然后再推送到生产服务器上。
4.切换到之前实现新需求的分支,继续工作。

分支的新建与切换

首先,假设你正在项目中工作,并且已经提交了几次更新:
在这里插入图片描述
图(2-1)——一个提交历史

现在,你需要去修补问题追踪系统上#53问题。
这里我们把新建的分支取名为iss53,要新建并切换该分支,运行git checkout并加上- b参数:

$ git checkout -b iss53

相当于执行下面两条命令:

$ git branch iss53
  $ git checkout iss53

该命令执行结果:

在这里插入图片描述
图(2-2)——创建了一个新分支的指针。
接着你开始尝试修复问题,在提交了若干次更新后,iss53分支的指针也会随着向前前进,因为它就是当前分支(换句话说,当前的HEAD指针正指向iss53):

//举个修改的例子
$ vim index.html
   $ git commit -a -m 'added a new footer [issue 53]'

在这里插入图片描述
图(2-3)——iss53分支随着工作进展向前推进。

现在你接到了网站问题的紧急电话,需要马上修补。
有了Git,我们就不需要同时发布这个补丁和iss53里作出修改,也不需要再创建和发布该补丁到服务器之前大费力气来复原这些修改。
我们唯一需要做的是切换回master分支。(再次之前,留心你的暂存区或者工作目录里,那些还没有提交的修改,它会和你即将检出的分支产生冲突从而阻止Git切换分支)

切换master分支:

$ git checkout master

此时工作目录中的内容和你在解决问题#53之前一模一样,我们可以几种精力修补。
有一点需要牢记:Git会把工作目录的内容恢复为检出某分支时它所指向的那个提交对象的快照。它会自动添加,删除和修改文件以确保目录的内容和你当时提交的完全一样。

接下来,我们要紧急修补。我们创建一个紧急修补分支hotfix来搞定:

$ git checkout -b 'hotfix'
  $ vim index.html
    $ git commit -a -m 'fixed the broken email address'

在这里插入图片描述
图(2-4)——hotfix分支是从master分支所在点分化出来的。
有必要做些测试,确保修补是成功的,然后回到master分支把它合并起来,然后发布到生产服务器,用git merge命令来进行合并:

$ git checkout master
   $ git merge hotfix
   
 Updating f42c576..3a0874c
    Fast forward
    README | 1 -
    1 files changed, 0 insertions(+), 1 deletions(-)

注意,合并出现了“Fast forward”的提示。由于当前master分支所在的提交对象是要并入的hotfix分支的直接上游,Git只需把master分支指针直接右移。换句话说,如果顺着一个分支走下去可以到达另一个分支的话,那么Git在合并两者时,只会简单地把指针右移,因为这种单线的历史分支不存在任何需要解决的分歧,所以这种合并过程可以称为快进(Fast forward)。

现在最新的修改已经在当前master分支所指向的提交对象中了,可以部署到生产服务器上去了。
在这里插入图片描述
图(2-5)——合并之后,master和hotfix分支指向同一位置。

在修补发布之后,你想要回到被打扰之前的工作。
由于当前hotfix分支和master分支都指向相同的提交对象,所以hotfix已经完成了历史使命,可以删掉了。
使用git branch -d选项执行删除操作:

$ git branch -d hotfix

现在回到之前未完成#53问题修复分支上继续工作:

$ git  checkout iss53
  $ vim index.html
   $ git commit -a -m 'finished the new footer' 
      [iss53]: created ad82d7a: "finished the new footer [issue 53]"
    1 files changed, 1 insertions(+), 0 deletions(-)

在这里插入图片描述
图(2-5)——iss53分支可以不受影响继续推进
不用担心之前hotfix分支的修改内容尚未包含到iss53中来。
如果确实需要纳入此次修补,可以用git merge master把master分支合并到iss53;
或者等iss53完成之后,再将iss53分支中的更新并入到master。

分支的合并

在问题#53先关的工作完成之后,可以合并回master分支。
实际操作同前面合并hotfix分支差不多,只需回到master分支,运行git merge命令指定要合并进来的分支:

$ git checkout master
  $ git merge iss53
    Merge made by recursive.
    README | 1 +
    1 files changed, 1 insertions(+), 0 deletions(-)

注意,这次合并操作的底层实现,并不同于之前hotfix的并入方式。因为这次你的开发历史是从更早的地方开始分叉的。见(下图3-1)
由于当前master分支所 指向的对象(C4)并不是iss53的直接祖先,Git不得不进行一些额外的处理。
就此例而言,Git会用两个分支的末端(C4和C5)以及它们的共同祖先进行一次简单的三方合并计算。
在这里插入图片描述
图(3-1)——Git分支合并自动识别出最佳的同源合并点。
这次Git没有简单地把分支指针右移,而是对三方合并后的结果重新做一个新的快照,并自动创建一个指向它的提交对象(C6)。
这个提交对象比较特殊,它有着两个祖先(C4和C5)。
值得一提的是Git可以自己裁决哪个共同祖先才是最佳合并基础;
在这里插入图片描述
图(3-2)——Git自动创建一个包含了合并结果的提交对象。
之前工作成功已经合并到了master了,那么iss53也就没用了。你就可以就此删除它,并在问题追踪系统里关闭该问题。

$ git branch -d iss53

遇到冲突时的分支合并

有时候合并操作并不会如此顺利。
如果在不同的分支中都修改了同一个文件的统一部分,Git就无法干净地把两者合到一起。(逻辑上说,这种问题只能由人来裁决)
如果你在解决问题#53的过程中修改了hotfix中修改的部分,将得到类似下面的结果:

$ git merge iss53
    Auto-merging index.html
    CONFLICT (content): Merge conflict in index.html
    Automatic merge failed; fix conflicts and then commit the result.

Git做了合并,但是没有提交,它会停下来等你解决冲突。要看看哪些文件在合并时发生冲突,可以使用git status来查看:

[master*]$ git status
    index.html: needs merge
    # On branch master
    # Changes not staged for commit:
    # (use "git add <file>..." to update what will be committed)
    # (use "git checkout -- <file>..." to discard changes in working directory)
    #
    # unmerged: index.html
    #

任何包含未解决冲突的文件都会以未合并(unmergeed)的状态列出。
Git会在有冲突的文件里加入标准的冲突解决标记,可以通过手工定位并解决这些冲突。
可以看到文件包含类似下面这样的部分:

<<<<<<< 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

可以看到=======隔开的上半部分,是HEAD(即master分支,在运行merge命令时所切换到的分支)中的内容,下半部分是在iss53分支中的内容。
解决冲突的办法无非是二者选其一或者我们亲自整合到一起。比如你可以通过这段内容替换为先这样来解决:

<div id="footer">
    please contact us at email.support@github.com
    </div>

这个解决方案各采纳了两个分支的一部分,还删除了 <<<<<<<,======= 和 >>>>>>> 这些行。
在解决了所有文件里的所有冲突后,运行git add将它们标记为已解决状态。(实际上就是来一次快照保存到暂存区域)
因为一旦暂存,就表示冲突已经解决。如果你想用一个有图形界面的工具来解决这些问题,不妨运行git mergetool,它会调用一个可视化的合并工具并引导你解决所有冲突:

$ git mergetool
    merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff
    Merging the files: index.html

    Normal merge conflict for 'index.html':
    {local}: modified
    {remote}: modified
    Hit return to start merge resolution tool (opendiff):

退出合并工具后,Git会询问你合并是否成功。如果回答是,它会为你把相关文件暂存起来,以表明状态为你解决。
再运行一次git status来确认所有冲突都已解决:

$ git status
    # On branch master
    # Changes to be committed:
    # (use "git reset HEAD <file>..." to unstage)
    #
    # modified: index.html
    #

如果觉得满意了,并且所有冲突都已经解决,也就是进入了暂存区,就可以用git commit来完成这次合并提交。提交的记录差不多是这样:

Merge branch 'iss53'

    Conflicts:
    index.html
    #
    # It looks like you may be committing a MERGE.
    # If this is not correct, please remove the file
    # .git/MERGE_HEAD
    # and try again.
    #

分支的管理

我们学习了创建,合并和删除分支。除此之外,还需要学习如何管理分支,日后的常规工作中会经常用到下面介绍的管理命令。
使用git branch 命令 不仅仅能创建爱你和删除分支,如果不加任何参数,它会给出当前所有分支的清单:

$ git branch
    iss53
    *master
    testing

注意看master分支前的*字符,它表示当前所在的分支。也就是说,master分支将随着开发进度前移。
若要查看各个分支最后一个提交对象的信息,运行git branch -v

$ git branch -v
    iss53 93b412c fix javascript issue
    * master 7a98805 Merge branch 'iss53'
    testing 782fd34 add scott to the author list in the readmes

要从该清单中筛选出你已经(或尚未)与当前分支合并的分支,可以用--merge--no-merged选项。
比如git branch --merge查看哪些分支已被并入当前分支(哪些分支是当前分支的直接上游):

$ git branch --merged
    iss53
    * master

之前我们已经合并了iss53,所以这里会看到它。
一般来说,列表中没有*的分支通常可以用git branch -d来删掉。
原因很简单,既然已经把它们所包含的工作整合到了其他分支,删掉也不会损失什么。

另外可以用git branch --no-merged查看尚未合并的工作:

$ git branch --no-merged
    testing

它会显示还未合并进来的分支。由于这些分支中还包含着尚未合并进来的分支。由于这些分支还包含着尚未合并进来的工作成果,所以简单地用git branch -d删除该分支会提示错误,因为那样会丢失数据:

$ git branch -d testing
    error: The branch 'testing' is not an ancestor of your current HEAD.
    If you are sure you want to delete it, run 'git branch -D testing'.

不过如果你确实想删除该分支上的改动,可以用大写的删除选项-D强制执行,就像上面提示信息给出的那样。

先写到这了,肝不动了。这几天每天都抽时间更新一点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/174413.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Visusl Studio 2019 使用Sqlite3

1. 下载访问官网下载页面(Sqlite 官方下载)&#xff0c;从Window区下载编译好的动态库和头文件。动态库&#xff08;根据实际需要选择32或64位版本&#xff09;&#xff1a;解压得到&#xff1a;源码文件&#xff1a;解压得到&#xff08;当然我们只需要sqlite3.h&#xff09;&…

V4L2 摄像头应用

1.V4L2 是 Video for linux two 的简称&#xff0c;是 Linux 内核中视频类设备的一套驱动框架&#xff0c;为视频类设备驱动开发和应用层提供了一套统一的接口规范。2.使用 V4L2 设备驱动框架注册的设备会在 Linux 系统/dev/目录下生成对应的设备节点文件&#xff0c;设备节点的…

前端HTML5

什么是HTML&#xff1f; 超文本标记语言&#xff0c;它是用来描述网页的一种语言HTML不是一种编程语言&#xff0c;而是一种标记语言标记语言是一种标记标签 浏览器内核 浏览器内核&#xff08;渲染引擎&#xff09;&#xff1a;负责读取网页内容&#xff0c;整理讯息&#xf…

双方案-基于Mysql 与 ElasticSearch实现关键词提示搜索与全文检索

文章目录前言Mysql检索简述原理其他索引构建实例代码搜索流程搜索ElasticSearch 实现环境配置编码查询与插入前言 就喜欢搞这种不需要怎么费劲的东西&#xff0c;只需要把思路阐述清楚&#xff0c;随笔性质的博文&#xff0c;顺手啊&#xff0c;几乎不用改定就可以当博文发布出…

day19|669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移除&#xff0c;原有的父代…

生物信息【蛋白序列对比blosum】

参考学习&#xff1a;传统蛋白质序列比对算法 - 知乎 (zhihu.com) 一、蛋白序列同源、相似 同源”&#xff08;homology&#xff09;和“相似”&#xff08;similarity&#xff09;&#xff1a; 同源是指有相同的祖先&#xff0c;在这个意义上&#xff0c;无所谓同源的程度&…

MybatisPlus学习笔记(二)

分页查询 分页在网站使用十分之多1.原始的limit进行分页2.pageHelper第三方插件3.MP内置的分页插件如何使用 1.配置拦截器组件 2.使用page对象 删除操作 逻辑删除 物理删除&#xff1a;从数据库中直接移除逻辑删除&#xff1a;在数据库中没有被删除&#xff0c;而是通…

Centos 7升级系统内核版本

步骤一&#xff1a;检查内核版本 [rootmaster ~]# uname -rs Linux 3.10.0-1160.el7.x86_64 步骤二&#xff1a;升级内核 CentOS 允许使用 ELRepo&#xff0c;这是一个第三方仓库&#xff0c;可以将内核升级到最新版本 rpm --import https://www.elrepo.org/RPM-GPG-KEY-elr…

二叉树知识锦囊(二)

作者&#xff1a;爱塔居 专栏&#xff1a;数据结构 作者简介&#xff1a;大三学生&#xff0c;希望和大家一起进步&#xff01; 文章目录 文章目录 一、二叉树的存储 二、二叉树的遍历&#xff08;重点&#xff09; 2.1 前序遍历 2.2 中序遍历 2.3 后序遍历 2.4 层序遍历 2.5 小…

AX7A200教程(2): DDR3仿真平台搭建(二)

本章主要新建ddr3工程&#xff0c;然后将官方的ddr3仿真文件加入到工程里进行仿真&#xff0c;开发环境2020.1。新建ddr3_test工程新建ddr3工程顶层新建的ddr3_top顶层文件&#xff0c;目前还是空白的调用mig控制器&#xff0c;请参考我上一个章节&#xff0c;这里不在具体写调…

搜索引擎——Elasticsearch

文章目录1.ElasticSearch简介2.基本概念3.Elasticsearch概念-倒排索引4.Elasticsearch和Kibana的安装5.Elasticsearch入门操作5.1_cat5.2PUT&POST新增数据5.3PUT&POST修改数据5.4GET查询数据5.5DELETE删除数据5.7bulk批量操作5.6乐观锁字段6.Elasticsearch进阶操作6.1批…

蓝桥杯重点(C/C++)(随时更新)

目录 1 重点 1.1 取消同步&#xff08;节约时间&#xff0c;甚至能多骗点分&#xff0c;最好每个程序都写上&#xff09; 1.2 万能库&#xff08;可能会耽误编译时间&#xff0c;但是省脑子&#xff09; 1.3 蓝桥杯return 0千万别忘了写&#xff01;&#xff01; 1.4 …

【nginx】Windows下的常见问题踩坑

▒ 目录 ▒&#x1f6eb; 导读需求1️⃣ 安装2️⃣ 中文路径3️⃣ alias指定目录错误及原因正确示例&#x1f4d6; 参考资料&#x1f6eb; 导读 需求 最近写了一个前端应用&#xff0c;需要部署后&#xff0c;让别人能访问&#xff0c;想来想去&#xff0c;还是选择了目前最强…

TeeChart Pro VCL FMX 2022.36.220929 Crack

TeeChart Pro VCL FMX图表组件库提供数百种用于数据可视化的 2D 和 3D 图形样式、56 种数学、统计和财务函数供您选择&#xff0c;还有无限数量的轴和 30 个调色板组件。 快速浏览 跨平台的一个来源 针对 Windows、Web 和移动应用程序 Delphi VCL 图表组件 使用 Embarcadero 的…

elasticsearch搜索功能(二)

一、DSL查询文档&#xff08;P100&#xff09; 1. DSL查询分类 Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#xff09;来定义查询。常见的查询类型包括&#xff1a; &#xff08;1&#xff09;查询所有&#xff1a;查询出所有数据&#xff0c;一…

《Python程序设计(第3版)》[美] 约翰·策勒(John Zelle) 第 9 章 答案

《Python程序设计&#xff08;第3版&#xff09;》[美] 约翰策勒&#xff08;John Zelle&#xff09; 第 9 章 答案 答案仅供参考&#xff0c;若有错误欢迎指正 判断对错 计算机可以生成真正的随机数。Python 的 random 函数返回伪随机整数。自顶向下的设计也称为逐步求精。…

Redis优惠券秒杀 | 黑马点评

目录 一、全局唯一ID 1、全局ID生成器 二、实现秒杀下单 1、基本的下单功能 2、超卖问题 3、乐观锁解决并发问题 三、实现一人一单 1、思路分析 2、代码初步实现 3、关于锁的范围 4、关于事务失效 5、集群下线程并发问题 一、全局唯一ID 订单如果用自增长会存在…

QT动画实例代码QPropertyAnimation的应用

用QT实现动画&#xff0c;我们必定用到QPropertyAnimation&#xff0c;这里我们介绍几种情形的动画实现。如直线动画&#xff0c;曲线动画&#xff0c;路径动画。 一、基础知识 1、QPropertyAnimation的初始化 我们首先必须在包涵QPropertyAnimation的头文件或者模块&#x…

Android之WorkManager处理后台定时任务

WorkManager和Service并不相同&#xff0c;也没有直接的联系。Service是Android系统四大组件之一&#xff0c;它没有被销毁的情况下是一直保持在后台运行的。而WorkManager只是一个处理定时任务的工具&#xff0c;它可以保证即使在应用退出甚至手机重启的情况下&#xff0c;之前…

动手深度学习-pytorch数据操作

N维数组是机器学习和神经网络的主要数据结构创建数组需要形状&#xff1a;如3*4的矩阵每个元素的类型&#xff1a;例如32位浮点数每个元素的值&#xff1a;例如全是0.或者随机数数据操作首先&#xff0c;导入torch张量表示一个数值组成的数组&#xff0c;这个数组可能有多个维度…