Git之提交和撤销操作

embedded/2025/1/12 16:09:51/

文章目录

  • 前言
  • 一、工作区、暂存区和版本库的概念
    • 1.介绍
    • 2.它们之间的关系
  • 二、命令介绍
  • 三、.git目录
  • 总结


前言

本文从工作区,暂存区和版本库的概念引入, 介绍了Git中的一些基础命令, 同时结合实例来学习如何将文件提交到git仓库,以及如何进行撤销修改等操作.


一、工作区、暂存区和版本库的概念

1.介绍

工作区: 我们在电脑上修改的代码文件所在的目录,简单来说就是你对代码进行修改的地方;
暂存区(stage|index): 一般是位于.git目录下的index文件中,我们也称之为索引。需要先将待提交的文件添加到暂存区,然后再提交到版本库;
版本库(repository): 又名仓库,位于工作区的隐藏目录.git中,它不属于工作区,而是独立出来的Git的版本库。版本库中将每一次git提交作为一个Git对象进行管理,每个文件的修改、删除都会被跟踪,以便在后续开发中对历史记录进行查看或者“还原”。

2.它们之间的关系

工作区、暂存区、版本库之间的关系可以参考下图
在这里插入图片描述

  1. 当创建Git版本库时,Git会自动创建一个唯一的master分支,以及指向master分支的HEAD;
  2. 当对工作区修改的内容(增/删/改文件)执行git add命令时,暂存区目录树的文件索引会被更新;
  3. 当执行git commit提交命令时,master分支会进行对应的更新,即将暂存区的目录树真正写入到版本库中。

总结来说,我们在工作区进行增删改文件等操作不会同步更新到仓库中,只有使用git addgit commit命令后,才能将修改提交到仓库中进行管理。

二、命令介绍

git_add_26">1.git add

git add [file1] [file2] [file3] #添加一个或多个文件 到暂存区
git add [dir] 					#添加指定目录(及其子目录) 到暂存区
git add							#添加当前目录下所有文件改动 到暂存区

git_commit_34">2.git commit

git commit -m "commit message" #提交修改内容到版本库,-m后跟上本次提交的具体描述,方便后续回顾历史记录

注意: message绝对不能省略,要描述你的提交细节,方便后续维护。
举例:
创建文件code1,在文件中写入内容为"git add",通过git add命令将code1文件添加到暂存区,再使用git commit命令将暂存区的内容提交到版本库中。
在这里插入图片描述
可以看到git commit命令的提示信息中说明:一个文件被修改(新增的文件code1),插入了一行内容(在code1中写入的"git add")。
也可以尝试add多个文件,然后一次commmit提交所有文件:
在这里插入图片描述
git commit是将暂存区中所有的修改提交到版本库中。
参考下面的例子,我们创建文件code5,然后使用命令git add code5将它添加进暂存区,接着创建code6,最后执行git commit -m "msg"将暂存区中的修改提交到版本库。可以看到,提交信息上显示的是1个文件被修改,即只提交了code5的修改,因为code6的修改没有被添加到暂存区中。
在这里插入图片描述
如果需要将code6的修改也提交到版本库,可以重复上面的过程,先执行git add,再执行git commit即可。
在这里插入图片描述

git_log_53">3.git log

git log #查看提交历史记录
git log --pretty=oneline #将日志信息精简为一行

在这里插入图片描述
可以看到我们先前进行的两次提交的日志信息,带上–pretty=oneline选项可以精简提交的日志信息为一行。
在这里插入图片描述
日志信息中commit后面跟着的一串乱码,实际上是每次提交的commit id(可以理解为版本号),是Git用于唯一标识某次提交的。commit id并非1,2,3,…依次递增的数字,而是通过计算得到的一个很大的数字,用十六进制表示。

commit id是由40位的SHA-1哈希值组成的,它是通过将提交内容和提交信息(比如作者、时间等)进行哈希函数处理后生成的。

git_status_66">4.git status

git status #查看最近一次提交后,当前对于文件的修改

在这里插入图片描述
提示信息告诉我们工作区的code2文件被修改过,但是还未完成添加到暂存区和提交到版本库等操作。
将修改添加到暂存区后,再执行git status可以看到:
在这里插入图片描述
最后执行git commit命令后,使用git status命令就显示没有修改了:
在这里插入图片描述

git_diff_77">5.git diff

通过git status命令我们只能查看到修改了那些文件,但是无法获取到具体修改的内容。如果修改的代码量过大,不便于我们进行查看和修改,通过git diff命令可以查询到当前修改的内容。

git diff [文件名] #查看暂存区和工作区文件的差异
git diff HEAD -- [file] #查看版本库和工作区文件的差异

在这里插入图片描述
显示信息的格式是Unix通用的diff格式:

a/code2 是修改前对应文件;
b/code2 是修改后对应文件;
--- 是删除;
+++ 是添加;

将修改添加到暂存区后,执行git diff [code2]可以发现没有显示差异,再执行git diff -- [code2]后可以看到版本库和工作区之间的差异:
在这里插入图片描述
最后执行git commit命令后,使用git diff命令就不会显示差异了:
在这里插入图片描述

git_reset_96">6.git reset

在我们实际开发过程中,会出现需要从历史的某个版本重新开发的情况,这时就需要用到git的版本回退功能了.
git reset命令可以指定回退到某次提交的版本.

git reset [--soft|--mixed|--hard] [HEAD] [file]#版本回退

举例:将代码回退到上一个版本
在这里插入图片描述
在这里插入图片描述

注意: 回退的本质是将版本库中的内容回退, 工作区或暂存区内容是否回退取决于配置的命令参数.

–soft 选项是将版本库回退到指定版本, 而暂存区和工作区内容保持不变.
–mixed 为默认选项, 即不带参数时相当于带这个选项. 该选项是将暂存区和版本库的内容回退到指定版本内容, 而工作区保持不变
–hard 选项是将工作区、暂存区和版本库都回退到指定版本. 注意: 当工作区有尚未提交的代码时谨慎使用这个命令, 因为一旦工作区回滚, 未提交的代码就再也找不回来了.
HEAD 选项用于指定回退的版本, 也可以写成指定版本的commit id.
HEAD表示当前版本(版本指的是版本库的版本);
HEAD^表示上一个版本;
HEAD^^表示上上一个版本;
以此类推.
也可以使用~数字的形式指明版本:
HEAD~0表示当前版本;
HEAD~1表示上一个版本;
HEAD~2表示上上一个版本;
以此类推.
file 可以指定要回退的具体文件file,没有指定则默认回退所有修改的文件。

git_reflog_124">7.git reflog

当我们回退到历史版本version2后, 又想重新回到该历史版本之后的版本version3该怎么办? 同样是使用 git reset命令, 但是必须要获取到对应版本的commit id。然而, 如果并非即时的进行版本回退,从上方的命令行中获取commit id,则此时无法获取到该版本的commit id。
下图可以看到再使用git log是无法打印出version2之后的版本信息(commit id)。
在这里插入图片描述
可以看到日志中最新的是当前版本的信息,无法查询到change code2的版本信息了。

这时可以使用git reflog命令:

git reflog #查看本地执行的所有git命令

通过这条命令可以找到本地所有的操作记录。
在这里插入图片描述
在这里插入图片描述

在实际操作中,我们会发现Git的版本回退非常快, 这是因为Git的版本回退本质是在Git里面有一个指向当前分支的HEAD指针(前文说过, HEAD指针是指向master的,而master是存储了最近一次提交的commit id). 当我们进行版本回退时,本质是将master中存储的commit id改成了指定版本的commit id,因此速度会很快。

git_checkout_141">8.git checkout

上文中的git reset命令主要是对于版本库文件的回退版本来说的,如果我们在工作区进行了较长时间的修改, 但是目前不想要这些修改, 想恢复到上一个版本应该如何做?
当改动较小,则可以尝试用git diff命令来查看当前工作区的修改,然后将修改重置回去。但是,当改动较多,此时手动一个个改回去就不太现实,耗时量大并且容易将代码改出bug,因此可以使用git checkout --命令来将文件直接恢复到最近一次add/commit的状态。

git checkout -- [file] #将工作区指定文件恢复到最近一次add/commit的状态

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

注意:只有携带--时, 该命令才是这个功能, 该命令的其他选项及其对应功能会在后续文章中进行介绍。

如果在工作区修改的内容还未add到暂存区,则可以使用命令git checkout -- [file]将指定文件恢复到最近一次add/commit的状态.
如果工作区修改的内容已经add到暂存区了或者已经commit到版本库了, 我们想要丢弃工作区当前的修改, 则可以参考前文的命令来进行撤销修改.

  1. add到暂存区的情况:
    使用git reset [--mixed] HEAD [file] 命令, 可以将暂存区的内容回退到当前版本(当前版本库的版本)。然后,再使用git checkout -- [file]将工作区的修改回退到当前版本
    或者直接使用git reset --hard HEAD [file]命令,将暂存区和工作区的修改都回退到当前版本。
  2. commit到版本库的情况:
    使用git reset --hard HEAD^命令, 可以将工作区和暂存区的内容回退到上一个版本。
    注意, 这种操作的前提是你还没有将自己的本地仓库的修改push到远程仓库,也就是commit之后还没有push。
    我们进行撤销的目的,就是避免有问题的代码影响到远程仓库!!!只有被push到远程仓库之前的撤销才是有效的

git_rm_file_163">9.git rm [file]

git rm [file] #将暂存区中的文件file删除

当我们需要从版本库中删除某个文件file时,可以执行以下步骤:

  1. 执行rm file命令将工作区的file文件删除,此时使用git status可以看到有一个修改待add和commit。
    在这里插入图片描述
  2. 然后执行git add file命令,将工作区中删除file的这个修改添加到暂存区中,此时使用git status可以看到有一个修改待commit。
  3. 最后执行git commit -m "rm file"将暂存区中的修改提交到版本库中,至此版本库中的file文件就被删除了。
    在这里插入图片描述

当然,git为我们提供了一种更简化步骤的命令 git rm,步骤简化为:

  1. 执行git rm [file]命令,可以将工作区中的file命令删除,同时将这个修改添加到暂存区中,此时使用git status可以看到有一个修改待commit。
  2. 然后执行git commit -m "git rm file"将暂存区中的修改提交到版本库中,至此版本库中的file文件就被删除了。
    在这里插入图片描述

git_180">三、.git目录

使用命令tree .git 查看.git目录的子目录
在这里插入图片描述
在这里插入图片描述
子目录的介绍:

  1. .git 目录下的index就是暂存区,执行git add后会将对应的Git对象索引添加到index中。
  2. HEAD 是默认指向master分支的指针:
    在这里插入图片描述
    我们再查看master中的内容:
    在这里插入图片描述
    可以看到master中保存的内容和最新一次的commit id是相同的,即master中保存的是当前最近一次的commit id。
  3. objects 是Git的对象库,其中存储了所创建的各个版本库对象及其内容。当我们执行git add命令时,工作区中对文件内容进行的修改会被创建出的Git对象记录,并写入objects目录下,同时暂存区内对应的目录树会被更新。
    在这里插入图片描述
    可以看到在我们进行了几次提交后,objects目录下多了几个子目录,子目录的名称实际上是我们每次commit得到的commit id的前两位数,而子目录下的文件的文件名则是commit id的后38位。
    在这里插入图片描述
    由于版本库对象对应的文件是经过sha(安全哈希算法)加密过的,所以我们无法直接查看该文件的具体内容,但是可以使用命令git cat-file来查看版本库对象的内容:
    在这里插入图片描述
    可以看到版本库对象中记录了提交人信息,提交描述以及两个特殊的commit id。
    其中,parent 对应的是当前版本库对象对应的提交的上一次提交的commit id:
    在这里插入图片描述
    tree 对应的是当前所有提交的记录:
    在这里插入图片描述

总结

以上就是今天要讲的内容,本文介绍了 的相关概念。本文作者目前也是正在学习C++相关的知识,如果文章中的内容有错误或者不严谨的部分,欢迎大家在评论区指出,也欢迎大家在评论区提问、交流。
最后,如果本篇文章对你有所启发的话,希望可以多多支持作者,谢谢大家!


http://www.ppmy.cn/embedded/153326.html

相关文章

网络安全系列 之 协议安全

1. SSL/TLS协议 对于HTTPS、FTPS等协议,其底层使用了SSL/TLS协议。 目前SSL/TLS协议版本共有5个:SSL2.0、SSL3.0、TLS1.0、TLS1.1、TLS1.2 SSL2.0禁止使用,原因:MD5做消息认证算法、容易受到中间人攻击从而被选择弱加密算法、加密…

Linux常用指令

目录 1 概述2 指令2.1 简单指令2.2 解压缩2.2.1 tar.bz2和tar.gz2.2.2 单独bz22.2.3 zip2.2.4 7z 2.3 网卡操作 1 概述 本章主要是记录一些日常用到的Linux指令,方便自己忘记的时候查找,也为有需要的人提供参考。 2 指令 2.1 简单指令 指令解释cat /…

双指针算法专题

目录 1. 移动零 1.1 算法原理 1.2 算法代码 2. 复写零 2.1 算法原理 2.2 算法代码 3. 快乐数 3.1 算法原理 3.2 算法代码 4. 盛水最多的容器 4.1 算法原理 4.2 算法代码 5. 有效三角形的个数 5.1 算法原理 5.2 算法代码 6. 剑指 offer:和为 s 的两个…

Tableau和PowerBI实现报表数据的下钻

Tableau实现报表数据下钻 用集操作实现树状图的数据下钻:连接数据源后,在类别字段上右键新建集。创建计算字段用于类别表头,将计算字段拖入视图,选中的集内成员显示自身,未被选中的显示加号。基于钻取字段创建下一层的…

基于单片机的指纹密码锁

【摘要】 本设计是一款基于单片机的指纹识别电子密码锁系统。该系统以STC89C52单片机作为模块核心同时结合ZFM-60指纹模块实现录取指纹并存储指纹数据的功能,并且通过HS12864-15C液晶显示比对流程及比对结果,该指纹电子密码锁通过直流继电器与发光二极管…

金山WPS Android面试题及参考答案

说说你所知道的所有集合?并阐述其内部实现。 在 Android 开发(Java 语言基础上)中有多种集合。 首先是 List 集合,主要包括 ArrayList 和 LinkedList。 ArrayList 是基于数组实现的动态数组。它的内部有一个数组来存储元素,当添加元素时,如果数组容量不够,会进行扩容操作…

英文字体:复古八十年代优雅品牌邀请函电影标题设计衬线字体 Eighties Nostalgia Font

嘿,大家好,我希望你们一切顺利,考虑到现在世界上发生的一切,你们在生活的各个方面都取得了进步。过去 3 年对我们所有人来说都是过山车,我一直非常怀念美好的时光。怀旧之情将我带到了 Pinterest,自然而然地…

【Web安全】SQL 注入攻击技巧详解:UNION 注入(UNION SQL Injection)

【Web安全】SQL 注入攻击技巧详解:UNION 注入(UNION SQL Injection) 引言 UNION注入是一种利用SQL的UNION操作符进行注入攻击的技术。攻击者通过合并两个或多个SELECT语句的结果集,可以获取数据库中未授权的数据。这种注入技术要…