什么是Git引用和分支?

一. 引言

什么是Git引用和分支?比如我在 Github 上一个项目的 .git/refs目录下:

├─heads
│      dev
│      master
│
├─remotes
│  └─origin
│          master
│
└─tags

refs 目录下包含了 heads、remote、tags 三个子目录,每个子目录下都有对应的文件
打开 heads/master 文件,查看其内容:

$ cat heads/master
1b41db435c03fe80fa965dc77442261708deb16d

上述这段编码,其实就是 SHA-1 值,再来看看其类型和内容:

$ git cat-file -p 1b41d
tree 03073e441d5360400b758257647c2a0250ee38c7
parent 90157be126d9204779c63aaadf3a95f5fa207fc4
author haohuin <huins...@gmil.com> 1623935829 +0800
committer haohuin <huins...@gmil.com> 1623935829 +0800
系统介绍Readme

这个 SHA-1 值就指向 Git 仓库中的某个提交对象 ID。既然能用 SHA-1 值来区分不同的提交对象,为何要创建一个存放 SHA-1 值的文件呢?因为 SHA-1 值过于长,而且没有规律,如果利用简单的文件名来引用对原来的提交对象,就不用记住复杂且无规律的 SHA-1 值了。
因此在 Git 中,像这种只含有 SHA-1 值的文件,就是 Git 的引用(Reference)。而分支,就是一个指向某一系列提交之首的指针或引用。如下图所示:
 

image.png


下面就讲解一下 Git 中的引用和分支的具体内容

二. Git引用

在引言中提到过,Git 引用内部存储着 SHA-1 值,来跟踪和引用不同的 Git 对象,从类型上讲,可以分成 HEAD 引用,分支引用(branch),标签引用(tag)和远程引用(remote):

2.1. HEAD引用

在 .git根目录中,有一个 HEAD 文件,我们先来查看一下 HEAD 文件中的内容:

$ cat .git/HEAD
ref: refs/heads/master

发现 HEAD 中的内容指向了一个引用 refs.heads/master,当执行 git checkout dev,将当前版本切换至 dev 分支后,HEAD 文件内容会变成如下引用值:

$ git checkout dev
Switched to branch 'dev'

$ cat .git/HEAD
ref: refs/heads/dev

此时 HEAD 指向的分支成了 dev,说明 HEAD 的内容就是指向当前 Git 仓库所在的分支。HEAD 文件通常是一个符号引用(symbolic reference),指向目前所在的分支或提交。 所谓符号引用,表示它是一个指向其他引用的指针。让我们首先来看看指向分支的 HEAD:

2.1.1 指向分支

如下图所示,是 HEAD 指向某个分支:
 

image.png


我们可 通过 git checkout <分支名>来使得 HEAD 在不同分支中进行切换。
此外有一种特殊情况,会导致 HEAD 中的内容直接为某个提交对象的 SHA-1 ID 值:

2.1.2 指向某个提交对象

当使用 git checkout检出某个非分支引用指向下的提交对象时:

//先查看所有的提交对象
 $ git log
commit 1b41db435c03fe80fa965dc77442261708deb16d (HEAD -> dev, origin/master, master)
Author: haohuin <huins...@gmil.com> 
Date:   Thu Jun 17 21:17:09 2021 +0800

    系统介绍Readme

commit 90157be126d9204779c63aaadf3a95f5fa207fc4
Author: haohuin <huins...@gmil.com>
Date:   Thu Jun 17 21:08:07 2021 +0800

    基本功能完成

commit f7d98432d5bc8c1a67e4c4f75795544cb8a7f4d0
Author: haohuin <huins...@gmil.com>
Date:   Thu Jan 21 21:26:48 2021 +0800

    init repository

//将HEAD指向最早的提交-init repository
$ git checkout f7d98432d5bc
Note: switching to 'f7d98432d5bc'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at f7d9843 init repository

而后出现了一大段的描述,其实现在就处于"detached HEAD"(分离头指针)状态,我们再来看看此时 HEAD 中的内容:

$ cat .git/HEAD
f7d98432d5bc8c1a67e4c4f75795544cb8a7f4d0

此时 HEAD 指向了一个具体的提交 ID,而不是一个分支引用。
在这种情况下,如果再次进行提交操作,创建了一个新的提交,但是此时的 master 和 dev 分支引用都不会向前移动。HEAD 也不会指向这个新提交,那么因为没有引用指向该提交,Git 的垃圾回收机制可能最后会清理掉这个提交:
 

image.png


但是分离头指针的这个特性,也有助于创建临时分支的情景。
总结来说,HEAD 引用有以下作用:

  • 当 HEAD 指向当前所处的分支或提交,它表示正在工作的位置。当再执行 Git 操作时,比如提交,检出分支等时,Git 根据 HEAD 的位置确定在哪个分支上进行操作。
  • 当 HEAD 指向某一个具体的提交时,会进入分离头指针状态。在这种状态下,可以在历史提交上工作,创建新的提交,但不会更新任何分支。这在实验性工作、查看旧版本代码或创建临时分支时很有用。
  • 当 HEAD 执行分支时,可以使用 ^ 符号用于引用上一次提交。例如,HEAD^ 表示 HEAD 的父提交,HEAD^^ 表示 HEAD 的父提交的父提交,以此类推。这在查看提交历史、比较版本之间的差异等操作中很有用。
  • 当存在合并冲突时,HEAD 在解决冲突时起到重要作用。HEAD 指向当前分支的最新提交,同时也是合并操作的目标分支。可以通过编辑冲突文件并执行合适的操作,来解决冲突后进行提交。

2.2. 分支引用

在Git中,分支引用是指向特定提交(commit)的可变指针。它们用于跟踪各个分支在代码库中的位置,以便在不同的提交之间进行切换和管理。

2.2.1 本地分支

分支引用存储在 .git/refs/heads 目录下,每个分支引用对应该目录下的一个文件。比如在当前仓库下的 .git/refs/heads目录下有两个分支 dev 和 master,其内部存储的值如下:

$ cat .git/refs/heads/master
1b41db435c03fe80fa965dc77442261708deb16d
$ cat .git/refs/heads/dev
1b41db435c03fe80fa965dc77442261708deb16d
$ git cat-file -p 1b41db4
tree 03073e441d5360400b758257647c2a0250ee38c7
parent 90157be126d9204779c63aaadf3a95f5fa207fc4
author haohuin <huins...@gmil.com> 1623935829 +0800
committer haohuin <huins...@gmil.com> 1623935829 +0800

系统介绍Readme

两个分支文件内部的内容就是指向某个提交对象,此处两个分支指向的提交对象一致。
分支引用通常是指向最新提交的指针。当在分支上进行提交时,分支引用会自动更新以指向新的提交。这样,Git就能够跟踪分支的进展和历史记录。
除了本地分支引用,还有远程分支引用。

2.2.2 远程分支

远程分支引用跟踪远程仓库中的分支。这些引用存储在 .git/refs/remotes/ 目录下。
如果你添加了一个远程版本库并对其执行过推送操作,Git 会记录下最近一次推送操作时每一个分支所对应的值,并保存 refs/remotes 目录下。在我的项目中有远程提交的仓库 orgin,可以通过 git remote showw 来看看当前远程仓库:

$ git remote show
origin
$ cat .git/refs/remotes/origin/master
1b41db435c03fe80fa965dc77442261708deb16d

此时远程仓库 origin中的分支 master对应的 SHA-1 值就是本地仓库中最新的提交对象。

远程引用和分支(位于 refs/heads 目录下的引用)之间最主要的区别在于,远程引用是只读的。 虽然可以 git checkout 到某个远程引用,但是 Git 并不会将 HEAD 引用指向该远程引用。因此,你永远不能通过 commit 命令来更新远程引用。 Git 将这些远程引用作为记录远程服务器上各分支最后已知位置状态的书签来管理。

在远程引用中,可能会涉及到引用规范的内容,具体可以看这篇文章Git - 引用规范

2.3. 标签引用

除了 HEAD 引用和分支引用,在 Git 对象中还有标签对象,从前面的深入剖析Git对象底层原理我们知道,标签对象有两种:

  • 轻量标签:只有一个固定的指向提交对象的引用值,类似于分支引用
  • 附注标签:会创建一个标签对象,其中记录一个引用来指向该标签对象

标签对象类似于分支引用,但与分支引用不同的是,标签对象是不可变的,一旦创建就不能更改。
标签对象通常用于指定软件版本、发布快照或重要里程碑。它们提供了一个有意义的名称来标识特定的提交或代码状态。
标签对象存储在 .git/refs/tags/ 目录下,每个标签对应该目录下的一个文件。例如,如果有一个名为 firstTag 的标签,对应的标签对象文件就是 .git/refs/tags/firstTag
在我的仓库中分别存储了两种标签,可以看到其对应的标签,以及其引用的对象:

$ find .git/refs/tags/
.git/refs/tags/
.git/refs/tags/firstTag
.git/refs/tags/secondTag

//1.查看轻量标签,其内部引用值指向提交对象
$ cat .git/refs/tags/firstTag
2b2af66549827bd6a466fe43081f406c2a12900b

$ git cat-file -p firstTag
tree 2503e9e0c4f774fc5ce298f4972f0e6d3a800d6f
parent 7b34a1e750918570ed610ee1f228e83b43a1192e
author haohuin <huins...@gmil.com> 1705458723 +0800
committer haohuin <huins...@gmil.com> 1705458723 +0800

second commit

//2.查看附注标签,其内部引用值指向标签对象
$ cat .git/refs/tags/secondTag
9cb2c0bd900b37a05f7c531fdd07cece35097045

$ git cat-file -p secondTag
object 8a4678fae181c16c6f4ff0e6a618991128d86da2
type commit
tag secondTag
tagger haohuin <huins...@gmil.com> 1705480524 +0800

secondTag

三. 总结

总体来说,引用机制让Git可以通过简单但唯一的ID来识别和追踪对象,管理项目版本以及支持分布式协作开发模式。Git中的引用主要包括

  1. HEAD引用,指向当前检出的分支或提交对象。HEAD管理 Git 当前操作所在的分支或提交状态。
  2. 分支引用,存储在.git/refs/heads目录下,每个分支对应一个引用文件。指向某个提交对象,跟踪分支历史记录和进度。本地分支和远程分支分别保存在不同目录下。
  3. 标签引用,存储在.git/refs/tags目录下,每个标签对应一个文件或对象。用于标记特定版本,不可变更。分支和标签都是引用的一种,但功能不同。分支指导开发顺序,标签标记具体版本。

技术前沿拓展

前端开发,你的认知不能仅局限于技术内,需要发散思维了解技术圈的前沿知识。细心的人会发现,开发内部工具的过程中,大量的页面、场景、组件等在不断重复,这种重复造轮子的工作,浪费工程师的大量时间。

介绍一款程序员都应该知道的软件JNPF快速开发平台,很多人都尝试用过它,它是功能的集大成者,任何信息化系统都可以基于它开发出来。

这是一个基于 Java Boot/.Net Core 构建的简单、跨平台快速开发框架。前后端封装了上千个常用类,方便扩展;集成了代码生成器,支持前后端业务代码生成,实现快速开发,提升工作效率;框架集成了表单、报表、图表、大屏等各种常用的 Demo 方便直接使用;后端框架支持 Vue2、Vue3。如果你有闲暇时间,可以做个知识拓展。

看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

300分钟吃透分布式缓存-22讲:怎么认识和应用Redis内部数据结构?

Redis 内部数据结构 RdeisDb Redis 中所有数据都保存在 DB 中&#xff0c;一个 Redis 默认最多支持 16 个 DB。Redis 中的每个 DB 都对应一个 redisDb 结构&#xff0c;即每个 Redis 实例&#xff0c;默认有 16 个 redisDb。用户访问时&#xff0c;默认使用的是 0 号 DB&…

【CSS】简单的抽屉面板展开收起自然过渡效果的css

目录 效果展示css固定梯形按钮至抽屉面板中间梯形按钮css过渡动画 效果展示 1.收起时点击蓝色梯形按钮展开 2. 展开时点击蓝色按钮收起 3.展开收起时需要过渡自然&#xff0c;有抽屉推拉效果 css 固定梯形按钮至抽屉面板中间 .toggle{ position: absolute;left:-21px;top…

【CSP】2022-03-3 计算资源调度器 stl大模拟使用map优化索引 完整思路+完整的写代码过程(遇到的问题)+完整代码

2022-03-3 计算资源调度器 stl大模拟使用map优化索引 2022-03-3 计算资源调度器 stl大模拟使用map优化索引思路写代码的过程&#xff08;遇到的问题&#xff09;完整代码 2022-03-3 计算资源调度器 stl大模拟使用map优化索引 在联系了之前那么多道stl大模拟题后&#xff0c;终…

Flutter does not exist

Flutter does not exist 原因&#xff1a;Generated.config 配置文件内路径缺失 原因&#xff1a;Flutter SDK缺失 通过配置文件查到Flutter SDK在本地的存放位置FLUTTER_FRAMEWORK_DIR/Users/haijunyan/Documents/flutter/bin/cache/artifacts/engine/ios 真机所需&#xf…

day06、07-MySQL

文章目录 一、MySQL概述1.1 安装1.2 数据模型1.3 SQL简介1.3.1 SQL通用语法1.3.2 分类 二. 数据库设计-DDL2.1 项目开发流程2.2 数据库操作2.2.1 查询数据库2.2.2 创建数据库2.2.3 使用数据库2.2.4 删除数据库 2.3 图形化工具2.3.1 介绍2.3.2 安装2.3.3 使用2.2.3.1 连接数据库…

【数据结构与算法】贪心算法题解(一)

这里写目录标题 一、455. 分发饼干二、56. 合并区间三、53. 最大子数组和 一、455. 分发饼干 简单 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这…

五种常见户外LED显示屏模组故障维修方法

在户外LED显示屏的使用过程中&#xff0c;可能会出现各种故障&#xff0c;例如连续不亮、坏点等问题&#xff0c;这通常是由LED显示屏模组上出现问题所导致的。以下是针对五种常见户外LED显示屏模组故障的解决办法&#xff1a; 连续不亮或有异常&#xff1a; 这种情况通常导致L…

matlab去除图片上的噪声

本问题来自CSDN-问答板块,题主提问。 如何利用matlab去除图片上的噪声? 一、运行效果图 左边是原图,右边是去掉噪音后的图片。 二、中文说明 中值滤波是一种常见的图像处理技术,用于去除图像中的噪声。其原理如下: 1. 滤波器移动:中值滤波器是一个小的窗口,在图像上移…

包装类 --java学习笔记

包装类 包装类就是把基本类型的数据包装成对象 基本数据类型与其包装类&#xff1a; 将整型数据包装成对象&#xff1a; 自动装箱&#xff1a;可以自动把基本类型的数据转换成对象 例&#xff1a;Interger a3 12&#xff1b; 自动拆箱&#xff1a;可以自动把包装类型的对象…

地理数据可视化:使用echarts实现地图可视化功能

前言 地图是一种直观而强大的数据可视化工具&#xff0c;能够帮助我们更好地理解地理分布和区域间的差异。在本文中&#xff0c;我们将探讨如何使用 echarts 实现地图功能&#xff0c;展示各个区域的数据分布和趋势。 一、基础使用 <template><div class"chartB…

.net core框架

ASP.NET Core 入门 跨平台开源框架 B/S 类与方法 Console 部分称为“类”。 类“拥有”方法&#xff1b;或者可以说方法存在于类中。 WriteLine() 部分称为“方法”。 想要使用方法就要知道方法在哪里 —————————— 执行流 一次执行一段 ASP.NET Core 是什么东西…

多场成像,快速提高机器视觉检测能力--51camera

多阵列CMOS传感器与芯片级涂层二向色滤光片相结合&#xff0c;可在单次扫描中同时捕获明场、暗场和背光图像。 多场成像是一种新的成像技术&#xff0c;它可以在不同的光照条件下同时捕获多幅图像。再加上时间延迟积分(TDI)&#xff0c;这种新兴的成像技术可以克服许多限制的传…

编译Linux内核并修改版本号后缀为学号-Ubuntu22.04中编译安装Linux内核6.7.8

前言&#xff1a;实验课要求下载最新版本Linux内核并修改版本号&#xff0c;本人在Vmware中Ubuntu22.04中实现&#xff0c;花三天时间查阅大量网站资料。记录一下误打误撞成功的过程&#xff0c;希望对你们有帮助。 目录 一、常规安装步骤&猜想Ubuntu与gcc版本过低 二、安…

【c++】string类的使用及模拟实现

1.我们为什么要学习string类&#xff1f; 1.1 c语言中的字符串 我们先了解一下什么是OOP思想 OOP思想&#xff0c;即面向对象编程&#xff08;Object-Oriented Programming&#xff09;的核心思想&#xff0c;主要包括“抽象”、“封装”、“继承”和“多态”四个方面。 抽象…

2020-2021年江苏省社区行政村边界数据

开展村&#xff08;社区&#xff09;规模优化调整&#xff0c;一是落实中央和省委部署要求的需要。党的十九大作出了实施乡村振兴战略的重大部署。乡村要振兴&#xff0c;合理确定行政村规模是前提、也是基础。2017年以来&#xff0c;国务院和省委省政府相继出台文件&#xff0…

pc端vue2项目使用uniapp组件

项目示例下载 运行实例&#xff1a; 这是我在pc端做移动端底代码时的需求&#xff0c;只能在vue2使用&#xff0c;vue3暂时不知道怎么兼容。 安装依赖包时可能会报&#xff1a;npm install Failed to set up Chromium r756035! Set “PUPPETEER_SKIP_DOWNLOAD” env variable …

羊大师分析羊奶的喝法,都有什么讲究?

羊大师分析羊奶的喝法,都有什么讲究&#xff1f; 羊奶的喝法确实有一些讲究&#xff0c;以下是一些主要的注意事项&#xff1a; 温度控制&#xff1a;羊奶不宜煮沸喝&#xff0c;加热时最好保持在50℃&#xff0d;60℃之间&#xff0c;以避免破坏其营养成分。 饮用时间&…

CleanMyMac X4.15具有哪些功能和特点?

CleanMyMac X具有许多其他功能和特点&#xff0c;以下是一些主要亮点&#xff1a; 系统清理&#xff1a;它能够深入扫描macOS系统&#xff0c;识别并清除各种垃圾文件&#xff0c;如缓存、日志、无用的语言文件等。这不仅有助于释放硬盘空间&#xff0c;还可以提高系统的整体性…

SIGMATEK西格玛泰克CPU模块控制器维修CCP531 12-104-531

Sigmatek的“解决方案”有两方面含义&#xff1a;一方面是指Sigmatek从控制系统、人机界面、伺服驱动系统直到开发平台&#xff0c;都能够提供解决方案&#xff1b;另一方面是指从方案的一开始&#xff0c;Sigmatek便能够位客户提供独特的、量身定做的产品实施方案。 Sigmatek产…

【C++】关键字:auto

文章目录 1. 介绍2. 如何使用 1. 介绍 从C11开始&#xff0c;auto变成了类型指示符&#xff08;之前auto并不是这个作用&#xff09;。使用auto定义变量时必须对其进行初始化&#xff0c;在编译阶段编译器自动推导auto变量的实际类型。因此auto并非是一种“类型”的声明&#…