DevOps系列文章之 Git知识大全

news2024/11/29 6:28:20

refs和reflog

Git的所有操作都基于提交:你会暂存提交,创建提交,查看过去的提交记录,或者使用很多很多Git命令在不同的仓库之间转移提交内容。这些命令中的很大一部分都会以某种形式来操作提交,其中很多还会以提交ID作为参数。比如git checkout命令,你可以传入一个提交ID用来查看那次的提交内容,或者传入一个分支名称用于切换分支。

 

如果更加理解提交的引用,你会让这些Git命令更加强大。在本文中,我们将会通过精雕细琢提交的引用,让其在git checkoutgit branch或者git push等普通命令的使用中大放光彩。

我们也会学习如何通过Git的reflog机制来找回那些看上去已经丢失的提交记录。

Hashes

对于提交的最直接的引用方式是使用SHA-1哈希串。这个哈希串用来表示每一次提交的唯一ID。通过执行git log命令的输出可以查找到每一次提交的哈希串。

commit 0c708fdec272bc4446c6cabea4f0022c2b616eba Author: Mary Johnson  Date: Wed Jul 9 16:37:42 2014 -0500 Some commit message

想要将此哈希串作为参数传递给其他Git命令,只需要提供足够长度的字符串就可以了。比如说,你可以通过下面的命令来传入上面的哈希串,以便使用git show命令查看那次提交的具体内容。

git show 0c708f

有些时候需要解析分支,tag,或者其他对于提交的间接引用。对于这种情况,你可以使用git rev-parse命令。下面的命令返回指向main分支的提交哈希串。

 git rev-parse main

这对于编写只接受提交ID作为参数的自定义脚本非常有用。你可以使用git rev-parse命令来标准化脚本的输入,进而进入对于提交的统一处理。这就避免了脚本用户需要手动解析提交的引用。

引用

引用是一种对于提交的间接引用方式。你可以认为这是一种用户友好的哈希串别名。这其实也是Git表示分支和tag的内部机制。

引用的描述会以普通文件的形式存储在.git/refs目录下。为了更加详细的了解引用描述,可以进入.git/refs目录。你大概会看到一个类似下面结构的文件夹结构,当然由于你项目的仓库、分支、tag以及远程仓库不同,具体输出也会与下面不一样。

 .git/refs/ 
  heads/ 
    main 
    some-feature 
  remotes/ 
  origin/ 
    main 
  tags/ 
    v0.9

heads文件夹中定义了你当前仓库中的所有本地分支。文件夹下的每一个文件名都与你本地的分支名对应,并且在每一个文件内你会找到一个表示提交的哈希串。这个哈希串表示这个分支的顶端提交ID。为了验证这个表示,可以在Git项目的根目录下执行下面的两行命令

 # Output the contents of `refs/heads/main` file: 
 cat .git/refs/heads/main 
 # Inspect the commit at the tip of the `main` branch: 
 git log -1 main

cat命令输出的提交哈希串应该与git log命令输出的提交哈希串一致。

如果需要改变main分支的引用,Git只需要修改refs/heads/main文件的内容就可以了。类似的,创建一个新的分支也不过是创建一个新的文件,并在其中写入新的提交哈希串。这也是Git处理分支快于SVN的原因之一。

tags目录的作用与此一致,只不过其中含有的是tag而不是分支。remotes目录中是所有使用git remote命令添加的远程仓库,每一个远程仓库都以一个独立的子目录代表。在每一个子目录中,你都会找到通过git fetch命令下载到本地的对应远程仓库分支。

指定引用

向Git命令传递引用时,即可以通过引用的全名进行引用,也可以使用简称进行引用,然后让Git根据简称去比对和搜索对应的引用。其实对于引用的简称你已经很熟悉了,因为这正是你使用分支名时实际发生的事情。

git show some-feature

实际上some-feature这个参数其实是一个分支的简称。Git会将它解析为refs/heads/some-feature然后再使用。当然你也可以直接使用分支的全名传递给Git命令:

git show refs/heads/some-feature

使用全名表示引用也可以避免歧义。有时候这还挺有必要的,比如说如果你同时给某个分支和tag都命名为some-feature。这时候使用全名来表示引用就可以避免混淆分支和tag。

在关于refspecs的部分,我们还会看到更多关于ref的全名引用。

打包的引用

对于大型的仓库,Git会周期性的执行垃圾回收机制用来删除不必要的Git对象,以及把引用打包压缩到一个单独的文件,以便提高性能。你可以使用如下命令手动执行这个压缩动作:

git gc

此命令会把refs文件夹下所有表示单独分支和tag的文件移动到.git根目录下一个叫做packed-refs文件中。如果打开文件查看,内容是像下面这样关于哈希串和ref的映射关系:

 00f54250cf4e549fdfcafe2cf9a2c90bc3800285 refs/heads/feature 
 0e25143693cfe9d5c2e83944bbaf6d3c4505eb17 refs/heads/main 
 bb883e4c91c870b5fed88fd36696e752fb6cf8e6 refs/tags/v0.9

而对于外部来说,正常的Git功能不会受到影响。所以如果你想知道.git/refs文件夹为什么变空了,这就是原因。

特殊引用

refs目录之外,还有一些用来表示特殊引用的文件放置在.git目录的根目录下:

  • HEAD – The currently checked-out commit/branch.
  • HEAD – 当前检出的提交/分支
  • FETCH_HEAD – The most recently fetched branch from a remote repo.
  • FETCH_HEAD – 最近一次检出的远程仓库分支
  • ORIG_HEAD – A backup reference to HEAD before drastic changes to it.
  • ORIG_HEAD – 备份的HEAD引用,以放置其发生剧烈变动
  • MERGE_HEAD – The commit(s) that you’re merging into the current branch with git merge.
  • MERGE_HEAD – 使用git merge命令合并到当前分支的其他分支引用
  • CHERRY_PICK_HEAD – The commit that you’re cherry-picking.
  • CHERRY_PICK_HEAD – 正在cherry-pick的提交

这些引用都是由Git在必须时自行创建及更新。比如执行git pull命令时先执行git fetch,这一系列动作会更新FETCH_HEAD引用。之后Git会自动执行git merge FETCH_HEAD以便完成将远程分支合并到目标分支的操作。当然你可以像使用其他普通引用一样使用这些特殊引用,比如我相信你一定使用过HEAD

这些文件的内容依他们本身的类型和当前本地仓库状态而不同。HEAD引用的内容可以是一个符号引用,所谓符号引用并不是一个提交哈希串,而不是一个对于其他引用的引用,或者其内容也可以就是一个提交哈希串。比如当你正在main分支时查看下HEAD引用的内容:

 git checkout main 
 cat .git/HEAD

以上命令会输出ref: refs/heads/main,就是说HEAD指向了refs/heads/main引用。通过这种方式Git就能知道当前被检出的分支就是main分支。如果切换到其他分支,那么HEAD引用的文件内容就会更新为那个新分支的引用。但是,如果你检出的不是一个分支,而是具体的一次提交,此时HEAD引用内容就不是符号引用,而是一个具体的提交哈希串。通过这种方式Git就能知道当前处于游离的HEAD状态。

大多数情况下,HEAD是唯一一个你会直接使用的引用。而其他的那些只会在编写操作Git内部机制的脚本时才会用到。

Refspecs

一个refspec用来表示一个本地分支和与之对应的远程仓库的分支之间的映射。利用这种映射关系我们可以使用本地Git命令来管理和操作远程分支,甚至也可以利用它们配置一些高级的git pushgit fetch行为。

一个refspec通常表示为[+]``<src>``:``<dst>的形式。<src>参数表示本地仓库的源分支,<dst>参数则表示处于远程仓库中的目标分支。可选的加号符号是用来强制远程仓库执行不可快进的更新。

refspecs可以用于git push命令,此时可以为远程分支指定一个分支名称。比如下面的命令会将本地的main分支推送到名为origin的远程仓库,此时与普通推送的行为是一致的。但是它却使用了qa-main分支作为远程仓库的目标分支。对于QA团队想把最新的main分支推送到他们专属的远程分支这一场景来说,这确实会比较方便。

 git push origin main:refs/heads/qa-main

也可以使用refspec来删除远程分支。在功能分支工作流程中,向远程仓库推送功能分支是很常见的操作。但问题是当你在本地删除了某个功能分支之后(比如这个功能分支已经被合并),远程仓库中却还保留着这个功能分支。长此以往,当你的项目不断开发,远程仓库中会聚集起大量的死亡分支。这时候你可以使用空源分支的refspec,传递给git push命令,用于删除远程分支。

git push origin :some-feature

注意Git v1.7.0以上的版本已经支持--delete选项以替代上面的方法。使用如下所示:

git push origin --delete some-feature

通过对Git进行简单的配置,可以利用refspecs的特性改变git fetch的默认行为。git fetch操作默认拉取远程仓库的所有分支。底层原因在于.git/config文件中的如下配置:

[remote "origin"]
url = https://git@github.com:mary/example-repo.git
fetch = +refs/heads/*:refs/remotes/origin/*

fetch那一行的配置指定git fetchorigin远程仓库中下载所有分支。但是,一些工作流根本用不着所有分支。比如说,很多持续集成工作流只关心main分支。为了仅fetch main分支,可以将fetch那行的配置改成如下内容:

 [remote "origin"]
 url = https://git@github.com:mary/example-repo.git
 fetch = +refs/heads/main:refs/remotes/origin/main

同样的,你也可以通过改变配置修改git push的默认行为。比如如果你想要推送main分支到origin远程仓库时,总是将其推送到远程仓库的qa-main分支(就像我们之前提到过的那样),你可以如下修改配置文件:

[remote "origin"]
url = https://git@github.com:mary/example-repo.git 
fetch = +refs/heads/main:refs/remotes/origin/main 
push = refs/heads/main:refs/heads/qa-main

利用refspec特性,可以让你完全控制Git命令如何在不同仓库之间转移分支。比如:

  • 对于本地分支执行重命名以及删除操作
  • fetchpush操作于不同名称的远程分支
  • 配置git fetchgit push命令仅作用于指定的分支

相对引用

你可以对提交使用相对引用。~用来表示与父提交节点的关系。比如下面的命令会输出HEAD的祖父提交节点。

git show HEAD~2

然而,当相对引用涉及到合并提交时,事情会变得有些棘手。合并提交的父节点不止一个,也就是说如果希望上溯提交路径的话,路径也不止一个。在三路合并场景中,第一个父节点来自于你当时用于执行合并命令的分支,第二个父节点则是传入git merge命令作为参数的那个分支。

使用~字符上溯父节点关系时,Git总会去第一个父节点的路径向上寻找。如果你希望寻找的是第二个路径上的提交节点,需要通过^字符来传入指定路径。如下例所示,如果HEAD是一个合并提交,那么^2则表示上溯第二个路径。

git show HEAD^2

你也可以使用多个^字符来表示向上追溯多代合并。比如下面的命令会输出HEAD(假设其为一次合并提交)的第二条路径上祖父提交节点。

git show HEAD^2^1

为了搞清楚~^是如何工作的,下面的图示展示了如何从A提交向上追溯不同的提交节点。对于有些情况,一个提交节点可以用多种不同的方式来表示。

 

Git命令可以像使用普通引用一样使用相对引用。如下例所示,所有命令都使用了相对引用

# Only list commits that are parent of the second parent of a merge commit
git log HEAD^2
# Remove the last 3 commits from the current branch
git reset HEAD~3
# Interactively rebase the last 3 commits on the current branch
git rebase -i HEAD~3

Reflog

作为Git的保险装置,reflog记录了几乎所有你在仓库中的修改,无论修改操作是否提交了快照。你可以将其看做是你在本地仓库中所有操作的时序日志记录。通过执行git reflog命令,可以查看reflog。输出的内容大致格式如下:

 400e4b7 HEAD@{0}: checkout: moving from main to HEAD~2 
 0e25143 HEAD@{1}: commit (amend): Integrate some awesome feature into `main` 
 00f5425 HEAD@{2}: commit (merge): Merge branch ';feature'; 
 ad8621a HEAD@{3}: commit: Finish the feature

这些内容大意如下:

  • 你刚刚检出了HEAD~2
  • 在这之前执行了一次commit amend操作
  • 在这之前将feature分支合并进main分支
  • 在这之前执行了一次提交

HEAD{}语法用于引用存储在reflog中的提交。它的功能与上一节介绍的HEAD~用法类似,不同点在于HEAD{}用于引用reflog中的记录而不是提交记录。

你可以利用这个特性来回退一些可能丢失的状态。比如说这样一个场景,当你使用git reset命令废弃了某个功能的代码。此时你的reflog看上去大概想这个样子:

ad8621a HEAD@{0}: reset: moving to HEAD~3 
298eb9f HEAD@{1}: commit: Some other commit message 
bbe9012 HEAD@{2}: commit: Continue the feature 
9cb79fa HEAD@{3}: commit: Start a new feature

git reset之前的那三次提交现在就处于悬空状态,意味着你无法引用他们——除了使用reflog。然后假设这时候你突然意识到不应该把这三次修改废弃掉。那么你只需要检出HEAD@{1}这次提交,恢复到执行git reset命令之前的状态即可。

git checkout HEAD@{1}

接下来你会处于游离HEAD状态,这时候可以基于此创建一个新的分支,然后就回到正常工作流程中了。

总结

现在你应该可以在Git仓库中如鱼得水般的引用提交了。我们学习到了分支和tag是如何存储在.git的子目录中,也学习了如何阅读一个packed-refs文件,以及HEAD如何表示,如何利用refspec进行高阶的pushfetch操作,最后我们还学习了如何使用相对引用。

我们也大概介绍了一下reflog,这是一种可以引用其他途径无法引用的提交的方法。对于想要恢复那些看上去木已成舟的删除非常有用。

学习这些技能的目的是为了能够精准地在开发场景中找到希望找到的提交记录。并且这些知识点对于引入到已有的Git操作中也并非难事,毕竟常用的Git命令即可以接受引用的简称作为参数,当然也可以接受引用的全称。

原文地址:

Refs and the Reflog | Atlassian Git Tutorial​www.atlassian.com/git/tutorials/refs-and-the-reflog

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

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

相关文章

结构型设计模式之代理模式【设计模式系列】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythi…

【iOS】对象底层学习

学习博客&#xff1a;[iOS]-OC对象底层探索 1. 类与对象 1.1 类和对象的本质 1.1.1 对象 对象的本质是结构体。 interface TestPerson : NSObject {// 成员变量// publicNSString *_age; // 4个字节 } property (nonatomic, copy) NSString *name; // 属性endimplementati…

C程序环境及预处理

​​​​​文章目录 一、程序的翻译环境和执行环境 1.程序编译过程 2.编译内部原理 3.执行环境 二、程序运行前的预处理 1.预定义符号归纳 2.define定义标识符 3.define定义宏 4.define替换规则 5.宏和函数的对比 三、头文件被包含的方式 四、练习&#xff1a;写一…

F.interpolate 数组采样操作

功能&#xff1a;利用插值方法&#xff0c;对输入的张量数组进行上\下采样操作&#xff0c;换句话说就是科学合理地改变数组的尺寸大小&#xff0c;尽量保持数据完整。 在计算机视觉中&#xff0c;interpolate函数常用于图像的放大(即上采样操作)。比如在细粒度识别领域中&…

【C#】MVC页面常见的重定向方式和场景

本篇文章主要简单讲讲&#xff0c;C# MVC 页面常见跳转或者重定向的方式和场景。 在实际项目开发中&#xff0c;在一些特定场景肯定会用到重定向&#xff0c;比如&#xff1a;不同角色跳转到不同视图地址 目录 一、种常见重定向方式1.1、RedirectToAction1.2、RedirectToRoute1…

猿人学14题—备而后动-勿使有变

猿人学14题—备而后动-勿使有变 抓包分析大致流程 mz参数生成m的值定位&参数组成补环境首先简单处理下十六进制编码问题提示&#xff1a;ReferenceError: window is not defined提示&#xff1a;document is not defined提示&#xff1a;$ is not definedASN1 is not defin…

【探索人工智能】我与讯飞星火认知大模型的对话

文章目录 讯飞星火认知大模型的地址概要讯飞星火认知大模型的发展历程讯飞星火认知大模型的主页利用讯飞星火大模型解决一些基本的数学问题讯飞星火认知大模型与OpenAI,ChatGPT没有关系&#xff01;让讯飞星火认知大模型编写传奇代码hello world小结 讯飞星火认知大模型的地址 …

chatgpt使用及辅助编程方面的体验

chatgpt使用及辅助编程方面的体验 文章目录 chatgpt使用及辅助编程方面的体验1 引言2 辅助编程体验2.1 辅助编写代码2.2 找出代码问题2.3 代码优化2.4 解释代码结束语 1 引言 最近几个月什么最火&#xff0c;那一定时chatgpt,虽然在国内使用存在各种限制&#xff0c;但是还是挡…

el-select和el-checkBox实现下拉菜单全选功能

el-select 和 el-checkbox 实现下拉菜单全选功能 示例代码&#xff1a; <el-selectpopper-class"select-container"v-model"ids"placeholder"请选择目标":multiple-limit"20"multiplefilterablecollapse-tagsclass"wd400&qu…

20230721 Essex UK, Dongbing Gu 公开讲座--机器人前沿

个人主页&#xff1a; https://www.essex.ac.uk/people/GUDON81301/dongbing-gu 机器人领域任务的特点&#xff1a;dull, dirty, dangerous tasks in remote spaces 机器鱼&#xff1a; 实时港口环境监测 机器鱼群探索算法 化学传感器 水面声呐定位系统/SLAM/通信问题 Robotic …

RocketMQ教程-安装和配置

Linux系统安装配置 64位操作系统&#xff0c;推荐 Linux/Unix/macOS 64位 JDK 1.8 Maven3.0 yum 安装jdk8 yum 安装maven 1.下载安装Apache RocketMQ RocketMQ 的安装包分为两种&#xff0c;二进制包和源码包。 点击这里 下载 Apache RocketMQ 5.1.3的源码包。你也可以从这…

网络安全 Day18-计算机网络知识03

计算机网络知识03 1. 路由器排查故障2. 设置和修改网关3. 设置修改DNS4. 私网地址5. VMware虚拟机NAT模式下上网原理6. DHCP工作原理 1. 路由器排查故障 排查网线&#xff0c;排查网卡&#xff0c;排查网卡的驱动查看网卡IP&#xff0c;没有配置IP、网关、DNS配置正确ping百度…

R语言贝叶斯METROPOLIS-HASTINGS GIBBS 吉布斯采样器估计变点指数分布分析泊松过程车站等待时间...

原文链接&#xff1a;http://tecdat.cn/?p26578 指数分布是泊松过程中事件之间时间的概率分布&#xff0c;因此它用于预测到下一个事件的等待时间&#xff0c;例如&#xff0c;您需要在公共汽车站等待的时间&#xff0c;直到下一班车到了&#xff08;点击文末“阅读原文”获取…

行为型模式 - 状态模式

概述 【例】通过按钮来控制一个电梯的状态&#xff0c;一个电梯有开门状态&#xff0c;关门状态&#xff0c;停止状态&#xff0c;运行状态。每一种状态改变&#xff0c;都有可能要根据其他状态来更新处理。例如&#xff0c;如果电梯门现在处于运行时状态&#xff0c;就不能进…

MySQL—事务

MySQL—事务 &#x1f50e;定义&#x1f50e;事务的特性原子性一致性持久性隔离性 &#x1f50e;并发执行事务可能产生的问题脏读不可重复读幻读总结 &#x1f50e;MySQL—事务的隔离级别 &#x1f50e;定义 事务的本质是将多条 SQL 语句打包成一个整体 要么全部成功, 要么全部…

html a标签换行显示

文章目录 用css display属性不用css&#xff0c;可以用<br>标签换行示例 用css display属性 可以使用CSS的display属性来实现多个a标签每行显示一个。 HTML代码&#xff1a; <div class"link-container"><a href"#">Link 1</a>…

# **基于TiDB Binlog架构的主备集群切换操作手册**

作者&#xff1a; Liuhaoao 原文来源&#xff1a; https://tidb.net/blog/dc65ef62 操作背景&#xff1a;最近手头有个系统&#xff0c;刚做完灾备建设及数据同步&#xff08; 文章链接在这 &#xff09;&#xff0c;需要进行灾备切换演练&#xff0c;验证灾备库建设是否…

HCIA静态路由综合实验(eNSP)

实验题目及要求&#xff1a; 1、分析IP地址分配。 主干IP掩码均为30&#xff1b; 环回IP掩码为28&#xff0c;方便汇总掩码27&#xff1b; 然后预留部分IP地址。 如下图&#xff1a; 2、按如上图片要求连接设备&#xff0c;并标记好IP分配信息&#xff0c;便于命令配置时一…

网页生成PDF表格诡异多出空白

环境&#xff1a; axios: 0.27.0 egg: 2.35.0 pdf-lib: 1.17.1 puppeteer-core: 17.1.3 node: 16.20.0 element-plus: 2.3.2 vue: 3.2.47 背景&#xff1a; 一个报告页面含有多个统计表格和描述文字&#xff0c;生成PDF用于下载查看&#xff0c;页面使用vue3element-plus…

使用ffmpeg合并视频遇到的坑

下面以Linux环境介绍为主 1.ffmpeg可执行命令不同的环境是不同的&#xff0c;Linux在执行命令前还需要授权。 2.合并视频命令&#xff1a; 主要命令: {} -f concat -auto_convert 0 -safe 0 -i {} -y -c:v copy 坑一&#xff1a;其中第一个花括号替换的是可执行命令所在的…