Git应用详解第三讲:本地分支的重要操作

前言

前情提要:Git应用详解第二讲:Git删除、修改、撤销操作

分支是git最核心的操作之一,了解分支的基本操作能够大大提高项目开发的效率。这一讲就来介绍一些分支的常见操作及其基本原理。

一、分支概述

在开发当中,往往需要分工合作。比如:小红开发A功能,小明开发B功能,小刚开发C功能。如何才能做到三者并行开发呢?git为我们提供的分支功能就能实现这一需求,如下图所示:

在实际的开发过程中,master分支是用来发布项目稳定版本的。新的功能往往是在一个新建的分支上进行开发,等到新功能开发完毕并经过测试,表现稳定后,才会合并到master分支上进行版本更新。这样就可以在保持一款软件发行的同时,同步进行新功能的开发。

通常来说,远程仓库的Git分支会有如下几种:master分支、test分支、develop分支,除此之外可能还有紧急修复bughotfix分支;但是,本地的分支可以有很多;本文主要介绍Git本地分支的内容。

二、查看本地分支

1.git branch

查看当前版本库中的所有分支:

其中的 * 表示当前处于的分支,可见当前处于master分支;

使用git init初始化git仓库时,git会自动创建一个master分支。但是,如果没有在master分支上进行任何提交就切换到其他分支,那么在切换分支的时候master分支会被销毁。并且,无法查看没有提交记录的分支,如下图所示:

2.git branch -a

查看所有本地分支,包括本地分支和本地远程分支:

3.git branch -v

查看所有本地分支上最近一次的提交记录:

但是,该指令无法查看本地远程分支:

4.git branch -r

-r参数用于单独查看本地远程分支:

5.git branch -av

该指令不仅可以显示所有的本地分支,包括本地远程分支,以及对应分支上的最新提交信息:

6.git branch -vv

-vv参数表示查看所有本地分支与远程分支的关联情况。如图所示,本地master分支有本地远程分支origin/master与之关联,说明它已与远程master分支建立了关联;

至于上面提到的本地远程分支,将在下一讲中详细介绍。

三、创建本地分支

1.git branch <branch_name>

可通过上述命令创建新分支new_branch

由于是在master分支上创建的new_branch分支,所以new_branch分支master分支有着部分共同的提交历史;所以,master分支上的文件,new_branch分支上都有。但是,在new_branch分支上添加的new_branch文件,不会存在于master分支上:

此时两分支的状态为:

2.git branch -b <branch_name>

通过上述命令可创建并切换到new_branch分支:

如图所示,本来所在分支为master,并且没有new_branch分支。执行上述命令后,创建并切换到了new_branch分支上。

四、切换本地分支

1.git checkout <branch_name>

比如切换到new_branch分支:

2.git checkout -

切换回上次操作的分支:

五、重命名本地分支

1.git branch -m <oldName> <newName>

如下图所示,将本地分支master重命名为master2

六、删除本地分支

1.git branch -d new_branch

删除new_branch分支:

注意点:

  • 不能删除当前所处的分支;
  • 当需要删除的分支上有master分支没有的内容,并且删除前没有进行合并(merge)时,会报错:

此时可以通过git branch -D new_branch 使用参数D,在不合并的情况下强制删除分支

七、合并分支

注意:这里所讲的分支指的是有公共提交节点的分支,如下图中的devmaster分支所示,提交节点A为它们的公共提交节点:

当两分支没有公共提交节点,如下图所示,应采用rebase进行合并,后面会详细介绍:

1.git merge <branch_name>

  • 首先,创建并切换到新分支dev中,并为test.txt文件添加内容dev1

    注意:要将dev分支上的这一修改提交到版本库,才能进行后续合并。因为合并的是提交对象链,详情见后面讲解的合并原理:

  • 然后,切换回master分支,通过git merge dev指令,将dev分支中的内容合并到当前所处master分支中;合并后master分支与dev分支上test.txt文件的内容达到了同步:

2.分支合并的原则

git分支的合并采用的是三方合并的原则:找到两分支最新提交AB的公共父节点C,在这三个节点的基础上合并为节点D。这个节点D就包含了两个分支上的所有内容:

八、分支的本质

分支:指向一条commit对象链或一条工作记录线的指针;

快照A~D分别表示四次提交(commit),注意提交的顺序为:A -> B -> C -> D

从图中可以看到每一次提交的对象内都会保存上一次提交的commit id,由此可以从后往前把所有的提交(commit)串起来形成一条(类似单向链表),这条链就组成了一条完整的分支信息

  • 当版本库中只有一条分支:该分支的最新提交就包含了整条分支的所有内容,代表版本库的当前状态。如上图的快照D,里面包含了快照A~C中的所有内容,此时快照D中的内容就是整个版本库中的内容:

  • 当版本库中有多条分支:每条分支上的最新提交包含了所处分支的全部内容,将各个分支的最新提交进行合并。合并的节点就包含了所有分支的内容,也就是现阶段的版本库本身;如下图中的d1m2t3分别包含了devmastertest分支上的所有内容:

1.分支 == 指针

情景一:

从图中可以看到:

  • HEAD为一个指针:指向当前分支;
  • master也为一指针:指向提交;

情景二:

上图中,devmaster分支上创建的新分支,可知:

  • git在创建新分支时,文件本身不变化,只需要创建一个代表新分支,并指向当前分支的指针;如图中的devmaster指向同一个提交,文件没有发生任何变化;
  • HEAD指向dev分支,表示当前所处分支为dev,相当于执行了:git checkout -b dev 后的状态;

相信你已经发现:HEAD是一个始终指向当前分支指针

2.HEAD标识符

HEAD文件是一个指向当前所在分支的引用标识符,也可以理解为一个指针,它与分支之间的关系是这样的:

查看HEAD

HEAD文件中并不包含SHA1值(每次提交的commit ID),而是包含一个指向另外一个引用的指针。我们可以查看.git目录下的HEAD文件:

可见HEAD指向的是当前所在的master分支;

当我们通过git checkout -b dev 创建并切换到dev分支后,再次进入.git文件夹查看HEAD,会发现此时HEAD指向了dev

由此证明了HEAD始终指向当前分支;

当执行git commit命令时,git会创建一个commit对象(比如下图D)。并且将这个commit对象的parent指针指向HEAD 所指向的引用(master)指向的提交(也就是C),这样就能形成一条提交链:

我们对于HEAD修改的任何操作,都会被git reflog完整记录下来:

但是手动地修改HEAD文件,这些信息就不会被记录下来,所以十分不建议手动修改git相关的配置文件,而是应该尽量采用命令行的方式来修改。

修改HEAD

实际上,我们可以通过git的底层命令symbolic-ref来实现对HEAD文件内容的修改;

git 中的命令可分为两类:高级命令底层命令;之前介绍的git add 等都是高级命令;

读取:

写入:

要注意格式:refs/heads/develop

查看ORIG_HEAD文件:

里面是一个SHA1值,查看当前的提交信息:

可以发现,ORIG_HEAD里面的SHA1值就是最新一次提交的SHA1值。

查看FETCH_HEAD文件:

里面有两个信息,一个是最新提交的commit ID,另一个是提交信息。

所以,对于git而言commit ID是十分重要的信息,通过这个SHA1值可以回溯或查找需要的提交。

3.git merge原理

过程图解
  • 在新分支上进行提交操作

    上图表示在dev分支上进行了一次提交,此时:

    • 分支master的提交记录由:ABC组成;
    • 而分支dev的提交历史则由:ABCD组成;
  • 对两分支进行合并操作

    master分支上执行:git merge devdev分支的内容合并到了master分支上;这种合并方式叫做:Fast-forward没有冲突,改变的只是master指针的指向;

详细过程

在执行合并操作前:

  • master分支上查看该分支的提交记录:

  • dev分支上查看该分支的提交记录:

可以看到dev分支只是比master分支多进行了一次提交(dev1),两分支状态如下图所示:

执行合并操作:

先切换到master分支,然后执行git merge dev合并dev分支:

可以看到使用了Fast-forward方式进行合并,合并后两分支状态如下图所示:

合并后,HEAD同时指向了masterdev分支;并且masterdev分支的提交历史完全一致;这就说明了:使用Fast-forward(快进合并)方式进行分支合并,只会改变master分支指针的指向;

4.Fast-forward

  • 默认情况下,合并分支时git会使用Fast-forward模式;
  • 在这种模式下,删除分支会丢弃分支信息;
  • 进行分支合并操作时加上--no-ff 参数会禁止使用Fast-forward方式,这样会多出一次提交记录;

ff表示Fast-forward

具体演示如下:

使用Fast-forward

首先,查看master分支上最新的3次提交:

此时两分支的状态为:

随后在dev分支上新增一次提交:dev2。查看dev分支上最新的3次提交:

此时两个分支的状态为:

切换回master分支,通过git merge dev合并dev分支,此时默认采用Fast-forward方式:

可以看到合并后,master直接指向了dev的最新提交,并没有产生新的提交。合并后两分支的状态如下所示:

由此验证了Fast-forward方式只会改变分支指针的指向。

禁用Fast-forward

合并时可以通过:

git merge --no-of dev

禁用Fast-forward模式。

  • 继续在dev分支新增一次提交:dev3。然后查看dev分支上最新的3次提交:

  • 不修改master分支,查看其最新的3次提交:

    此时两个分支的状态为:

  • 然后,在master分支上不使用Fast-forward方式合并dev分支。合并命令采用:
    git merge --no-ff dev
    

    执行后进入如下的vim编辑器界面,要求我们填写提交注释:

这说明不使用Fast-forward方式合并分支,会触发了一次提交。填写提交注释后完成提交操作,合并完成后,查看master分支的提交记录:

可以发现禁用了Fast-forward模式的合并会比dev分支多产生一次提交:Merge branch ‘dev‘,即使合并后的内容是一样的。此时两分支的状态为:

由此验证了,禁用Fast-forward方式合并,会多出一个表示合并的提交记录。

5.合并冲突

合并的两分支只有一条分支发生了改变,并且其中一分支是基于另一分支创建的。比如上述的masterdev分支,两分支没有分岔,此时不会出现合并冲突;git会通过Fast-forward方式自动完成合并操作;

但是,当合并的两分支都发生改变时,即分支出现分岔,如下图所示。此时就需要解决冲突后手动合并分支了:

具体演示如下:

合并前

首先,分别对两分支上的test.txt文件进行修改,并分别将修改提交到各自的分支;

  • master分支上进行新的提交:mas3,然后查看文件test.txt内容和分支提交记录:

  • dev分支上进行新的提交:dev1,然后查看文件test.txt内容和分支提交记录:

可见两分支的提交记录只有最新一次提交不一样:

合并后

master分支上,通过git merge dev合并dev分支时,会在共同修改的test.txt文件中出现合并冲突,如下图所示:

出现冲突的原因为:两个分支都对同一个文件test.txt进行了修改,git合并时并不知道以哪个分支的修改为标准。所以不能采用Fast-forward方式自动合并,需要解决冲突,手动合并。

手动合并过程

手动合并操作需要分如下三步进行:

  • 第一步:选择需要保留的内容,手动解决合并冲突;

此时进入发生合并冲突的test.txt文件:

会出现典型的冲突呈现方式(此时HEAD指向的是master分支),其中:

  • <<<HEAD>>>dev之间的内容表示:两分支上test.txt文件的不同之处;
  • <<<HEAD===之间的内容表示:当前分支mastertest.txt文件的修改;
  • ===>>>dev之间的内容表示:dev分支对test.txt文件的修改;

此时只需要在test.txt中保留想要的内容即可,例如:将两分支对test.txt的修改都进行保存,删除3、5、7行多余的内容:

除此之外,还可以通过git mergetool指令,调用vimdiff工具进入vim编辑器,来解决test.txt文件的冲突:

在实际开发中,我们很少手动进行合并,而是借助于一些工具来实现。

  • 第二步:使用git add test.txt将手动解决冲突时对test.txt的修改提交到暂存区;

编辑完毕后,可以看到此时仍然处于合并过程中(MERGING)。通过git status 查看状态,发现手动解决冲突时对test.txt文件的修改操作还在工作区中,需要通过git add test.txt将这一修改纳入暂存区,继续进行合并:

  • 第三步:通过git commit -m ‘合并注释‘将手动解决冲突时对test.txt的修改进行提交,完成合并操作;

如果需要填写较多的合并注释,可以通过git commit进入vim编辑器编辑。提交后,完成整个手动合并过程。

完成手动合并分支后,查看两分支的提交历史:

  • master分支上的提交历史:

  • dev分支上的提交历史:

可以发现此时两分支转变为了可以通过Fast forward方式合并的形式了,如图所示:

  • 手动解决冲突前:

  • 手动解决冲突后:

同步两分支

若想将devmaster分支上的内容进行同步,只需要在dev分支中通过git merge master 合并master分支即可。此时就可以使用Fast-forward方式进行合并了,合并结果如下图所示:

验证:

合并后,查看dev分支的提交历史:

可以看到HEAD同时指向devmaster,即三个指针都指向了最新的一次提交,符合上述分析得出的结论;

经过上面的讨论,不难看出:合并分支的实质就是不同提交的合并,以及HEAD和分支指针的移动;

以上就是今天介绍的本地分支重要操作,相信看到这里的你已经对git本地分支的操作了如指掌了。在下一讲中将介绍git最神奇的功能:版本回退。俗话说得好:世上没有后悔药。但是在git中,就存在所谓的"后悔药"!那么我们下一节再见。

原文地址:https://www.cnblogs.com/AhuntSun-blog/p/12694197.html

时间: 2024-10-05 20:26:43

Git应用详解第三讲:本地分支的重要操作的相关文章

git 使用详解(8)-- 分支的新建与合并

分支的新建与合并 现在让我们来看一个简单的分支与合并的例子,实际工作中大体也会用到这样的工作流程: 1. 开发某个网站. 2. 为实现某个新的需求,创建一个分支. 3. 在这个分支上开展工作. 假设此时,你突然接到一个电话说有个很严重的问题需要紧急修补,那么可以按照下面的方式处理: 1. 返回到原先已经发布到生产服务器上的分支. 2. 为这次紧急修补建立一个新分支,并在其中修复问题. 3. 通过测试后,回到生产服务器所在的分支,将修补分支合并进来,然后再推送到生产服务器上. 4. 切换到之前实现

【Git使用详解】使用Egit克隆项目到本地图解

第一步:   打开Eclipse的Git视图,在视图中单击"Clone a Git repository" 如图:      第二步:在弹出的Clone Git Repository界面中输入要克隆的库地址,用户名和密码单击下一步. 如图: 第三步:选择要克隆的分支单击下一步 如图: 第四步:选择库的本地存储路径和要初始化的分支单击finish等待进度完成即可. 如图: 第五步:导入库中的项目,在Git视图界面右键库选择"import Projects",在如下界面

Git命令详解(一)-个人使用

原文  http://blog.csdn.net/magicharvey/article/details/12431867 本文暂时不会涉及到团队如何使用Git的内容,而是从个人的角度探讨如何用好Git. 约定 绿色的5位字符表示提交的ID,分别指向父节点.分支用橘色显示,分别指向特定的提交.当前分支由附在其上的标识. 这张图片里显示最后5次提交,是最新提交.分支指向此次提交,另一个分支指向祖父提交节点. git cat-file git cat-file -t,查看Git对象的类型,主要的gi

【Git使用详解】Egit的常用操作详解

常用操作 操作 说明 Fetch 从远程获取最新版本到本地,不会自动merge Merge 可以把一个分支标签或某个commit的修改合并现在的分支上 Pull 从远程获取最新版本并merge到本地相当于fetch+merge Push 将本地分支的更新,推送到远程主机 Merge tool 当你的代码产生了冲突可以通过此工具快速的对比 Switch to 将当前分支切换到其它分支或标签 Commit 将更改提交到本地库中 Rebase 可以把在一个分支里提交的改变移到另一个分支里重放一遍 Re

【Git使用详解】Egit使用过程中遇到的问题及解决办法

1.   Git错误non-fast-forward后的冲突解决 问题(Non-fast-forward)的出现原因在于:git仓库中已经有一部分代码,所以它不允许你直接把你的代码覆盖上去.于是你有2个选择方式: 1.强推,即利用强覆盖方式用你本地的代码替代git仓库内的内容 git push –f 如果你用的是Egit则可以在推送界面选择"Force Update All Specs"即可,如下图: 2.先把git的东西fetch到你本地然后merge后再push $ git fet

Git初探--笔记整理和Git命令详解

几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面clone一个项目到本地时(假设项目名为GitTest),在本地就会看到一个名为GitTest的目录,目录下有项目代码和一个名为.git的目录,什么是工作区呢,就是除了.git文件夹以外的所有东西,我们主要在工作区上阅读,修改,添加删除代码和其他内容,而这个.git目录就称为一个版本库,这个版本库中存

iOS开发——开发实战篇&amp;版本控制SVN和Git使用详解

版本控制SVN和Git使用详解 公司的实际开发中,在天朝使用较多的还是SVN,因为SVN是集中式的,在天朝上班你们都懂的! -----------------svn----------------- 一:最常用基本步骤--- 下载(完整下载,第一次),将服务器的项目下载到本地开始开发 svn checkout ip —uaerbane=? —password=?     //这里需要add 简:co 更新仓库,服务器项目有变动的时候需要更新到本地,以免错误或者冲突 svn updata    

Git应用详解第二讲:Git删除、修改、撤销操作

前言 前情提要:Git应用详解第一讲:Git分区,配置与日志 在第一讲中我们对Git进行了简单的入门介绍,相信聪明的你已经了解Git的基本使用了. 这一讲我们来进一步深入学习Git应用,着重介绍Git的一些常见操作,包括:删除文件.比较文件.撤销修改.修改注释与查看帮助文档. 一.删除文件 1.git rm <file> 该命令用于删除版本库中的文件:删除工作区和暂存区中的文件都会报错: 若用该指令删除工作区中的文件,会报找不到文件的错误: 若用该指令删除暂存区中的文件,报如下错误: 所谓版本

【Git使用详解】EGit使用详解

此系列文章写给那些打算使用Git或正在使用Git,但对Git还不是很理解的程序猿们,希望能帮助大家在学习和使用Git的过程中少走弯路,并以最少的时间和代价来熟悉Git,让Git能够辅助更多的开发者提高开发效率. Ps.使用Git已经很久了,回想当初使用Git的时候可谓是雾里看花,懵懵懂懂,没少犯错误,但我从未畏惧过错误,每一次错误的解决都是对我技术的提升和经验的积累. 下面是此系列文章的目录: [Git使用详解]Egit插件的安装图解 [Git使用详解]使用Egit克隆项目到本地图解 [Git使