git 中分支的概念及使用

news2025/1/31 8:02:36

git 中分支的概念及使用

分支模型是 Git 中的 “必杀技特性”, Git 处理分支的方式非常轻量,创建新分支这一操作几乎能在瞬间完成,并且在不同分支之间的切换操作也是一样便捷。 理解和精通这一特性,我们便会意识到 Git 是如此的强大而又独特,并且从此真正改变我们的开发方式。

在版本控制中使用「分支」,最主要的目的就是用来解决开发过程中版本冲突的问题。

概念

在 Git 中保存的不是文件的变化或者差异,而是一系列不同时刻的快照。Git 的分支就是某个「commit 对象」的 hash 值(也就是一个指针)。

在这里插入图片描述

我们可以在 .git/refs/heads 文件夹中看到存在两个 master 、newBranch 两个文件:

在这里插入图片描述

这些文件里面的内容就是分支对应的最新「commit 对象」的 hash 值:

在这里插入图片描述
在这里插入图片描述

HEAD

HEAD 也是一个指针,指向当前我们「工作目录」分支最新「commit 对象」的 hash 值。

在这里插入图片描述

我们在执行 git log 命令时也会显示这个 HEAD:

在这里插入图片描述
在这里提示了当前处于 master 分支,且最新的「commit 对象」的 hash 值是d49f35…。

HEAD 指针保存在 .git/HEAD 文件中,我们可以直接打开该文件查看内容:
在这里插入图片描述
可以看到文件内容是 refs/heads/master,根据前面讲解的可以知道 master 文件里的内容是最新的「commit 对象」的 hash 值,所以我们现在应该清楚为什么 HEAD 能指向当前「工作目录」分支最新「commit 对象」的 hash 值了吧。

当我们执行 git checkout newBranch 命令时 HEAD 文件里的内容就会更改成对应的 newBranch 分支映射:

在这里插入图片描述

同时 git log 命令里显示的内容也不一样,HEAD 指向了 newBranch:

在这里插入图片描述

日志记录

当我们创建了新分支后,在 .git/logs/refs/heads 文件中就会生成对应的分支记录文件,里面包含了分支创建时的「commit 对象」hash 值,这样我们就能知道创建分支的源头:

在这里插入图片描述

在 newBranch 这个分支文件里面可以看到 newBranch 是在 a71e31… 这个「commit 对象」中创建的。之后的一些 commit 操作也会记录上去。

分支创建

我们在初始化 Git 仓库时,默认就创建了一个名叫 master 分支(在 github 中叫 main,只是名称不同,并非存在特别的设计)。

在这里插入图片描述

分支名称前面的 * 代表处于当前分支。

我们在 master 分支上添加一个 file.txt 文件并提交用于后续的使用。

在这里插入图片描述

创建分支有三种方法,分別是:

  1. git branch <branchName>:这个命令可以创建一个分支

    在这里插入图片描述

    在上图可以看到通过 git branch 可以查询到当前仓库多了一个 newBranch1 的分支,但是此时「工作目录」还处于 master 分支上,如果我们需要在 newBranch1 分支上开发,需要切换分支(请看 分支切换 部分)。

    此时我们 master 分支上再次新增一个 file2.txt 文件并提交用于后续的使用。

  2. git checkout -b <branchName>:这个命令不但会建立一个新分支,还会将目前「工作目录」切换到新建的分支上。
    在这里插入图片描述

    从上图可以看到执行命令后不仅多了一个 newBranch2 分支,当前的「工作目录」也处于 newBranch2 分支下( * newBranch2 )

    在这里插入图片描述

    根据 git log 命令我们可以看到 newBranch1、newBranch2 的历史提交记录不同,这是因为分支会自动继承来源分支的完整历史(在 newBranch2 分支创建之前 master 又新增了一个 file2.txt 文件)。

  3. git switch -c <branchName>:跟第二种方法一样,不但会建立一个新分支,还会将目前「工作目录」切换到新建的分支上。
    在这里插入图片描述

分支切换

使用 checkout

如果我们想将「工作目录」切换到其他分支,可以输入以下指令:

git checkout [branchName]

与创建分支的第二种方法非常类似(只是不含 -b 参数)。

切换到 newBranch1

在这里插入图片描述

可以看到提交历史里只有一条记录。

在切换分支前,需要确保我们的「工作目录」是干净的(不能有任何文件异动中的状态),否则分支切换会失败,比如我们修改了file.txt文件但是并未提交:

在这里插入图片描述

使用switch

git switch [branchName]

与创建分支的第三种方法非常类似(只是不含 -c 参数)。

在这里插入图片描述

使用 -f 参数可以强制切换分支,不过这会导致当前分支上未提交的修改被删除掉,最好慎用。

在这里插入图片描述

分支删除

如果我们想删除某个分支,可以输入以下指令:

git branch -d [branchName]

与创建分支的第一种方法非常类似(只是多了个 -d 参数)。

我们不能删除当前「工作目录」所处的分支,必须先切换到其他分支后,再删除我们目前这个分支。

举个例子,如果我们想删除当下这个 newBranch1 分支,那么我们必须先切换到其他分支(例如 master 分支),然后再执行 git branch -d newBranch1 命令,即可删除 newBranch1 分支。

删除当前分支会提示失败:

在这里插入图片描述

切换成 master 分支后删除 newBranch1:

在这里插入图片描述

如果我们在分支上提交了,之后在删除该分支时 Git 也会提示错误:

在这里插入图片描述
这是因为 Git 检测到了当前分支的提交并没有合并到 master 分支上,我们可以先合并之后再删除,或者使用 -D 参数来强制删除:
在这里插入图片描述

查看当前分支

直接用 git branch 命令查看所有的分支,分支名称前面存在 * 字符代表处于当前分支。

分支合并

由于 Git 是一种分布式版本控制系统,过程中会不断的进行分支与合并,无论是有意的合并 ( git merge ) 或无意的合并 ( git pull ),总之在使用 Git 时「合并」的动作会经常发生。

如果我们想将当前分支的「工作目录」合并到其他分支,需要先切换到需要合并的那个分支上,然后执行 git merge 命令。

继续我们上面的例子,我们现在在 newBranch2 上新建一个 file3.txt 文件后提交。此时 newBranch2 领先 master 分支一个 commit,之后切换成 master 分支,执行 git merge newBranch2 命令即可合并。

在这里插入图片描述

此时我们可以看到合并成功后在 master 分支上的「工作目录」也存在了 file3.txt 文件。

通常来说,在执行完合并操作后,分支的任务已经完成了,此时就可以把该分支删除了。

遇到冲突时合并

很多时候我们的合并操作并不会像上面的例子一样这么简单,对于多人协同开发,免不了会对同一个文件进行不同的修改,此时合并通常都会产生冲突:

在这里插入图片描述

虽然冲突了,但是文件其实已经合并成功,不过冲突文件上会包含一些特殊区段:

在这里插入图片描述

从 <<<<<<< HEAD 到 ======= 的内容,代表 file.txt 的内容。HEAD 代表当前 master 分支的最新版

从 ======= 到 >>>>>>> newBranch2 的内容,代表 newBranch2 分支里 file.txt 的内容。

我们通过 git status 查看状态也会有提示:

在这里插入图片描述

为了解决冲突,我们必须选择使用由 ======= 分割的两部分中的一个,或者也可以自行合并这些内容(如果我们遇到冲突什么都不改,直接执行 git add . 再加上 git commit 的话,确实也可以解决冲突,但是提交上去的文件仍旧会存在这些特殊区段)。

在这里我们直接合并两个分支的内容,手动把特殊区段去掉:

在这里插入图片描述

或者通过 vscode 提供的简便方式直接合并:

在这里插入图片描述

也可以通过 git mergetool 命令启动一个可视化合并工具:

在这里插入图片描述
在这里插入图片描述

解决完冲突后,对每个文件使用 git add 命令来将其标记为冲突已解决。 一旦暂存这些原本有冲突的文件,Git 就会将它们标记为冲突已解决。

合并重置

如果我们合并时出错了,这时只需要通过 git reset --hard ORIG_HEAD 命令就可以回复到上一版,然后再重新合并一次引发相同的冲突重新合并。

在这里插入图片描述

在执行 merge 命令时,会在 .git 文件下生成一个 ORIG_HEAD 文件,里面便记录了当前分支在合并前的最新「commit 对象」的 hash 值。

分支管理

–merged 与 --no-merged 这两个的选项可以过滤这个列表中已经合并或尚未合并到当前分支的分支。

如果要查看哪些分支已经合并到当前分支,可以运行 git branch --merged:

在这个列表中分支名字前没有 * 号的分支通常可以使用 git branch -d 删除掉;我们已经将它们的工作整合到了另一个分支,所以并不会失去任何东西。

查看所有包含未合并工作的分支,可以运行 git branch --no-merged:

在这里插入图片描述

这里显示了其他分支。 因为它包含了还未合并的工作,尝试使用 git branch -d 命令删除它时就会提示失败。

暂存「工作目录」

有时,当我们在项目的一部分上已经工作一段时间后,所有东西都进入了混乱的状态,而这时我们想要切换到另一个分支做一点别的事情或者是拉取远程仓库中的最新代码。但是这时候我们并不想为当前未完成的工作创建一次提交,此时就可以通过 git stash 命令来把「工作目录」暂存起来,使仓库回归到上一次 commit 的版本。

当前在 master 分支上开发着新功能:

在这里插入图片描述

执行 git stash 或者 git stash push 保存未完成功能:

在这里插入图片描述

现在可以看到当前的「工作目录」是干净的,我们就可以切换到其他分支或者拉取最新的代码了。

可以使用 git stash list 来查看暂存的东西。

在这里插入图片描述

使用 git stash apply 便可以重新应用之前的工作,默认是恢复最新(索引为 0 那个)的暂存内容,也可以通过 git stash apply stash@{-n} 来指定恢复某个暂存。

在这里插入图片描述

使用 git stash apply 命令只是恢复暂存的内容,但是在暂存堆栈上仍旧存在它,我们可以使用 git stash drop 加上将要移除的暂存的名字来移除它。

在这里插入图片描述

当然也可以直接通过 git stash pop 直接恢复暂存内容同时从暂存堆栈上删除掉。

checkout 命令

我们在切换分支的时候,分支本身其实并没有任何变化,变动的只是 HEAD 这个指针。

前面我们说到,.git/HEAD 这个文件的内容是指向当前分支的(例如,refs/heads/master ),而当前分支文件里储存是最新「commit 对象」的 hash 值,那么本质上 HEAD 其实指向的就是一个「commit 对象」的 hash 值,因此我们也可以直接使用 git checkout <hashName> 命令直接取出来一个具体的 commit 版本。

在这里插入图片描述

可以看到我们在执行了 git checkout 2e77 后出现了一大堆提示,在 git log 命令也可以看到 HEAD 指向了具体的「commit 对象」的 hash 值而非某个分支,这种现象就成为 detached HEAD(分离头指针)。

.git/HEAD 文件里的内容也变成了具体的 hash 值:
在这里插入图片描述

在这种情况下,我们执行 add、commit 的操作并不会记录在任何分支上(垃圾对象),如果我们想把这些操作记录起来就需要执行前面提示里的 git switch 命令:

在这里插入图片描述

在执行了 git switch -c detachedBranch 命令后可以看到,HEAD 此时指向了 detachedBranch 这个分支:

.git/HEAD 文件里的内容也随之更改成功了分支映射:

在这里插入图片描述

git checkout <hashName>这个用法我们基本会很少用到,不过存在一种使用场景:当我们误删了某个分支的时候。

前面多次提到了分支只是一个指向了某个「commit 对象」的 hash 值映射,如果我们误删了分支,其实并不重要,.git/objects 里仍储存着对应的「commit 对象」,我们只需要找到误删分支对应的那个「commit 对象」,使用 checkout 取出来并重新创建一个分支即可。

比如说我们误删了一个叫 dev 的分支,我们可以通过 git reflog 查看日志来找到被删的 dev 分支对应的「commit 对象」的 hash 值:

在这里插入图片描述

从上图可以看到左边黄色字体的就是 hash 值,右边就是删除 dev 分支的日志。

之后通过 git checkout f173a5a 取出版本,然后重新创建 dev 分支:

在这里插入图片描述

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

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

相关文章

使用mamba替换conda和anaconda配置环境安装软件

使用mamba替换miniconda和anaconda&#xff0c;原因是速度更快&#xff0c;无论是创建新环境还是激活环境 conda、mamba、anaconda都是蟒蛇的意思… 下载mambaforge wget https://github.com/conda-forge/miniforge/releases/latest/download/Mambaforge-Linux-x86_64.sh ba…

浅谈项目周报的核心要点

相信很多朋友都写过周报&#xff0c;无论什么岗位&#xff0c;而其中项目周报对于项目管理人员极其重要&#xff0c;项目周报是一种重要的沟通工具&#xff0c;用于向相关人员汇报项目的进展情况、存在的问题和下一周的工作计划。以下是一些关于如何编写项目周报的核心要点&…

SpringBoot 入门 SpringBoot 与其他项目整合 集成 Druid 数据库连接池 集成 Log 日志 配置修改

目录 1.SpringBoot简介 1.1.什么是SpringBoot 1.2.特点 2.SpringBoot快速入门 2.1.创建SpringBoot项目 2.2.项目目录介绍 2.3.配置修改 2.4.启动SpringBoot 3.SpringBoot与其他项目整合 3.1.整合JDBC 3.2.整合Druid数据库连接池 3.3.整合MyBatis 3.4.整合Log日志 …

【Kafka-3.x-教程】-【六】Kafka 外部系统集成 【Flume、Flink、SpringBoot、Spark】

【Kafka-3.x-教程】专栏&#xff1a; 【Kafka-3.x-教程】-【一】Kafka 概述、Kafka 快速入门 【Kafka-3.x-教程】-【二】Kafka-生产者-Producer 【Kafka-3.x-教程】-【三】Kafka-Broker、Kafka-Kraft 【Kafka-3.x-教程】-【四】Kafka-消费者-Consumer 【Kafka-3.x-教程】-【五…

TLC Nand Flash 存储单元的读取原理

我们知道Nand Flash使用浮栅晶体管作为存储单元&#xff08;memory cell&#xff09;来存储数据&#xff0c;浮栅晶体管物理结构如图1所示&#xff1a; 图1 浮栅晶体管 对于普通的晶体管&#xff08;去掉浮栅晶体管中的浮栅层&#xff0c;floating gate&#xff09;&#xff0…

Redis数据缓存

缓存 一 缓存基础 1 缓存的概念和作用 缓存就是数据交换的缓冲区&#xff08;称作Cache&#xff09;&#xff0c;是存贮数据的临时地方&#xff0c;一般读写性能较高 2 缓存的使用 之前没有使用缓存是的模型 3 项目说明 当我们查询商家信息的时候&#xff0c;直接从mysql中…

FFmpeg 的使用与Docker安装流媒体服务器

本文阐述的均为命令行的使用方式&#xff0c;并不牵扯FFmpeg 的 C音视频开发内容&#xff0c;补充一句&#xff0c;C的资料真的少&#xff0c;能把C学好的人&#xff0c;我真的是觉得巨佬。 我主要是使用FFmpeg 推流方面的知识&#xff0c;案例大都是靠近这方面。 一、FFmpeg…

寻找最富裕的小家庭 - 华为OD统一考试

OD统一考试(C卷) 分值: 100分 题解: Java / Python / C++ 题目描述 在一棵树中,每个节点代表一个家庭成员,节点的数字表示其个人的财富值,一个节点及其直接相连的子节点被定义为一个小家庭现给你一棵树,请计算出最富裕的小家庭的财富和。 输入描述 第一行为一个数N,…

系列十、Spring Security登录接口添加验证码

一、Spring Security登录接口添加验证码 1.1、概述 一般企业开发中&#xff0c;登录时都会有一个验证码&#xff0c;基于Spring Security的登录接口默认是没有验证码的&#xff1f;那么如何把验证码功能集成到Spring Security的登录接口呢&#xff1f;请看下文&#xff01; 1.…

SpringBoot视图渲染技术:整合Freemarker,常见指令和数据类型

目录 1.Freemarker 1.1.什么是Freemarker 1.2.Freemarker模板组成部分 1.3.优点 2.SpringBoot整合Freemarker 2.1.配置 2.2.数据类型 2.2.1.字符串 2.2.2.数值 2.2.3.布尔值 2.2.4.日期 2.3.常见指令 2.3.1.处理不存在的值 2.3.2.assign 2.3.3.if/elseif/else …

物联网中的通信技术

阅读引言&#xff1a; 本文主要大致为大家带来物联网中的常见的通信方式的知识梳理。 目录 一、概述 二、无线通信技术 1.物联网电子标签 RFID 1.1 RFID 概念 1.2 RFID 系统组成 2.WI-FI技术 3.UWB技术 4.ZigBee技术 5.NFC技术 6.蓝牙技术 7.EnOcean技术 一、概述 物…

ssm基于VUE.js的在线教育系统论文

摘 要 随着学习压力越来越大&#xff0c;课外参加补习班的学生越来越多。现在大多数学生采用请家教、自学、报名补习班的方式进行课外的额外学习。请家教费用昂贵&#xff0c;自学效率低&#xff0c;碰到自己不会的知识不能及时得到解达&#xff0c;报名补习班需要时间、地点的…

VBA技术资料MF106:检查单元格是否在表对象中

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

Java中的包机制、final和super关键字

一、包机制 关于java语言当中的包机制&#xff1a; 1.包又被称为package,java中引入package这种语法机制主要是为了方便程序的管理。 不同功能的类被分门别类放到不同的软件包当中&#xff0c;查找比较方便&#xff0c;管理比较方便&#xff0c;易维护。 2.怎么定义package呢…

第 4 课 创建工作空间与功能包

文章目录 第 4 课 创建工作空间与功能包1.工作环境的创建2.ROS功能包的创建 第 4 课 创建工作空间与功能包 消息和服务的创建、发布器和订阅器的编写、服务端和客户端的编写都是基于Ros功能包进行操作的&#xff0c;因此在进行上述操作前&#xff0c;需要先创建工作空间及功能包…

基于Springboot的网上点餐系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的网上点餐系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&am…

【Java学习】Java环境变量——配置jdk

本文我主要是介绍jdk的下载方式和在Windows系统下安装配置jdk11&#xff08;压缩包格式&#xff09;&#xff0c;其他格式的jdk以及Linux操作系统上的jdk安装我后续视情况进行更新… JDK的下载 大家可以去官网Java|Oracle下载对应的资源&#xff0c;也可以下载文末我上传的jd…

8 - MySQL数据读写分离|MySQL多实例

MySQL数据读写分离&#xff5c;MySQL多实例 MySQL数据读写分离数据读写分离如何实现数据的读写分离提供数据读写分离服务的软件&#xff08;中间件&#xff09;maxscale 软件提供的读写分离服务的工作过程配置数据读写分离结构 提供数据存储服务 MySQL多实例 MySQL数据读写分离…

最新国内可用GPT4、Midjourney绘画、DALL-E3文生图模型教程

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

Zabbix监控系统及部署

目录 前言 一个完整的项目 业务架构 运维架构 优秀监控软件的好处 1.zabbix概述 zabbix是什么 zabbix监控原理 Zabbix6.0新特性 1.Zabbix server高可用防止硬件故障或计划维护期的停机 2.Zabbix6.0 LTS新增Kubernetes监控功能&#xff0c;可以在Kubernetes系统从多个…