《精通git》笔记之九(重置揭密)

2024-03-30 03:32
文章标签 精通 笔记 重置 git 揭密

本文主要是介绍《精通git》笔记之九(重置揭密),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

三棵树

理解 reset 和 checkout 的最简方法,就是以 Git 的思维框架(将其作为内容管理器)来管理三棵不同的树。“树” 在我们这里的实际意思是 “文件的集合”,而不是指特定的数据结构。(在某些情况下索引看起来并不像一棵树,不过我们现在的目的是用简单的方式思考它。)Git 作为一个系统,是以它的一般操作来管理并操纵这三棵树的:

用途
HEAD上一次提交的快照,下一次提交的父结点
Index预期的下一次提交的快照
Working Directory沙盒
HEAD

HEAD 是当前分支引用的指针,它总是指向该分支上的最后一次提交。这表示 HEAD 将是下一次提交的父结点。
通常,理解 HEAD 的最简方式,就是将它看做 你的上一次提交 的快照。

索引

索引是预期的下一次提交。我们也会将这个概念引用为 Git 的 “暂存区域”,这就是当运行 git commit 时 Git 看起来的样子。
Git 将上一次检出到工作目录中的所有文件填充到索引区,它们看起来就像最初被检出时的样子。之后你会将其中一些文件替换为新版本,接着通过 git commit 将它们转换为树来用作新的提交。
索引并非技术上的树结构,它其实是以扁平的清单实现的。

工作目录

另外两棵树以一种高效但并不直观的方式,将它们的内容存储在 .git 文件夹中。工作目录会将它们解包为实际的文件以便编辑。可以把工作目录当做沙盒。在你将修改提交到暂存区并记录到历史之前,可以随意更改。

工作流程

Git 主要的目的是通过操纵这三棵树来以更加连续的状态记录项目的快照。
在这里插入图片描述
git add : 获取工作目录中的内容,并将其复制到索引中。
git commit : 它首先会移除索引中的内容并将它保存为一个永久的快照,然后创建一个指向该快照的提交对象,最后更新 master 来指向本次提交。
三棵树完全相同时。 运行git status,会发现没有任何改动。
如果有条目在索引与工作目录之间存在不同,运行 git status,会看到文件显示在 “Changes not staged for commit,” 下面并被标记为红色。
索引和 HEAD 不同,若运行 git status 的话就会看到 “Changes to be committed” 下的该文件变为绿色——也就是说,现在预期的下一次提交与上一次提交不同。

检出一个分支时,它会修改 HEAD 指向新的分支引用,将 索引 填充为该次提交的快照,然后将 索引 的内容复制到 工作目录 中。

重置的作用

示例:
在这里插入图片描述
第 1 步:移动 HEAD
reset 做的第一件事是移动 HEAD 的指向。这与改变 HEAD 自身不同(checkout 所做的);reset 移动HEAD 指向的分支。这意味着如果 HEAD 设置为 master 分支(例如,你正在 master 分支上),运行 git reset 9e5e64a 将会使 master 指向 9e5e64a。
在这里插入图片描述
第 2 步:更新索引(–mixed)
注意,如果你现在运行 git status 的话,就会看到新的 HEAD 和以绿色标出的它和索引之间的区别。
接下来,reset 会用 HEAD 指向的当前快照的内容来更新索引。
在这里插入图片描述
如果指定 --mixed 选项,reset 将会在这时停止。这也是默认行为,所以如果没有指定任何选项(在本例中只是 git reset HEAD~),这就是命令将会停止的地方。
它依然会撤销一上次 提交,但还会 取消暂存 所有的东西。于是,我们回滚到了所有 git add 和 git commit 的命令执行之前。

第 3 步:更新工作目录(–hard)
reset 要做的的第三件事情就是让工作目录看起来像索引。如果使用 --hard 选项,它将会继续这一步。
在这里插入图片描述
hard操作撤销了最后的提交、git add 和 git commit 命令以及工作目录中的所有工作。

–hard 标记是 reset 命令唯一的危险用法,它也是 Git 会真正地销毁数据的仅有的几个操作之一。其他任何形式的 reset 调用都可以轻松撤消,但是 --hard 选项不能,因为它强制覆盖了工作目录中的文件。

回顾

reset 命令会以特定的顺序重写这三棵树,在你指定以下选项时停止:

  1. 移动 HEAD 分支的指向 (若指定了 --soft,则到此停止)
  2. 使索引看起来像 HEAD (若未指定 --hard,则到此停止)
  3. 使工作目录看起来像索引
通过路径来重置

还可以给git reset提供一个作用路径。若指定了一个路径,reset 将会跳过第 1 步,并且将它的作用范围限定为指定的文件或文件集合。这样做自然有它的道理,因为 HEAD 只是一个指针,你无法让它同时指向两个提交中各自的一部分。不过索引和工作目录 可以部分更新,所以重置会继续进行第 2、3 步。现在,假如我们运行 git reset file.txt(这其实是 git reset --mixed HEAD file.txt 的简写形式,因为你既没有指定一个提交的 SHA-1 或分支,也没有指定 --soft 或 --hard),它会:

  1. 移动 HEAD 分支的指向 (已跳过)
  2. 让索引看起来像 HEAD (到此处停止)

所以它本质上只是将 file.txt 从 HEAD 复制到索引中。
在这里插入图片描述
它还有 取消暂存文件 的实际效果。
我们可以不让 Git 从 HEAD 拉取数据,而是通过具体指定一个提交来拉取该文件的对应版本。只需运行类似于 git reset eb43bf file.txt 的命令即可。
reset 命令也可以接受一个 --patch 选项来一块一块地取消暂存的内容。这样你就可以根据选择来取消暂存或恢复内容了。

压缩

假设你有一个项目,第一次提交中有一个文件,第二次提交增加了一个新的文件并修改了第一个文件,第三次提交再次修改了第一个文件。由于第二次提交是一个未完成的工作,因此你想要压缩它。
在这里插入图片描述
那么可以运行 git reset --soft HEAD~2 来将 HEAD 分支移动到一个旧一点的提交上(即你想要保留的第
一个提交):
在这里插入图片描述
然后只需再次运行 git commit:
在这里插入图片描述

检出

和 reset 一样,checkout 也操纵三棵树,不过它有一点不同,这取决于你是否传给该命令一个文件路径。

不带路径

运行 git checkout [branch] 与运行 git reset --hard [branch] 非常相似,它会更新所有三棵树使其看起来像 [branch],不过有两点重要的区别。
首先不同于 reset --hard,checkout 对工作目录是安全的,它会通过检查来确保不会将已更改的文件吹走。它会在工作目录中先试着简单合并一下,这样所有 还未修改过的 文件都会被更新。而 reset --hard 则会不做检查就全面地替换所有东西。
第二个重要的区别是如何更新 HEAD。reset 会移动 HEAD 分支的指向,而 checkout 只会移动 HEAD 自身来指向另一个分支。
例如,假设我们有 master 和 develop 分支,它们分别指向不同的提交;我们现在在 develop 上(所以HEAD 指向它)。如果我们运行 git reset master,那么 develop 自身现在会和 master 指向同一个提交。而如果我们运行 git checkout master 的话,develop 不会移动,HEAD 自身会移动。现在 HEAD 将会指向 master。
所以,虽然在这两种情况下我们都移动 HEAD 使其指向了提交 A,但做法是非常不同的。reset 会移动 HEAD分支的指向,而 checkout 则移动 HEAD 自身。
在这里插入图片描述

带路径

运行 checkout 的另一种方式就是指定一个文件路径,这会像 reset 一样不会移动 HEAD。它就像 git reset [branch] file 那样用该次提交中的那个文件来更新索引,但是它也会覆盖工作目录中对应的文件。
checkout 也接受一个 --patch 选项,允许根据选择一块一块地恢复文件内容。

总结

下面的速查表列出了命令对树的影响。“HEAD” 一列中的 “REF” 表示该命令移动了 HEAD 指向的分支引
用,而`‘HEAD’’ 则表示只移动了 HEAD 自身。特别注意 WD Safe? 一列 - 如果它标记为 NO,那么运行该命令之前请考虑一下。

HEAD 2IndexWorkdirWD Safe?
Commit Level
reset --soft [commit]REFNONOYES
reset [commit]REFYESNOYES
reset --hard [commit]REFYESYESNO
checkout [commit]HEADYESYESYES
File Level
reset (commit) [file]NOYESNOYES
checkout (commit) [file]NOYESYESNO

这篇关于《精通git》笔记之九(重置揭密)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/860368

相关文章

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

从入门到精通详解LangChain加载HTML内容的全攻略

《从入门到精通详解LangChain加载HTML内容的全攻略》这篇文章主要为大家详细介绍了如何用LangChain优雅地处理HTML内容,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录引言:当大语言模型遇见html一、HTML加载器为什么需要专门的HTML加载器核心加载器对比表二

IDEA中新建/切换Git分支的实现步骤

《IDEA中新建/切换Git分支的实现步骤》本文主要介绍了IDEA中新建/切换Git分支的实现步骤,通过菜单创建新分支并选择是否切换,创建后在Git详情或右键Checkout中切换分支,感兴趣的可以了... 前提:项目已被Git托管1、点击上方栏Git->NewBrancjsh...2、输入新的分支的

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE