【git原理与使用】git基本操作及底层原理(二)

文章目录

  • [1. Git 跟踪并管理的是修改的内容,而非文件本身](#1. Git 跟踪并管理的是修改的内容,而非文件本身)
    • [git status 命令](#git status 命令)
    • [git diff 命令](#git diff 命令)
  • [2. 版本回退](#2. 版本回退)
    • [2.1 git reset](#2.1 git reset)
    • [2.2 git reflog (后悔药)](#2.2 git reflog (后悔药))
    • [2.3 版本回退的底层原理](#2.3 版本回退的底层原理)
  • [3. 撤销修改](#3. 撤销修改)
    • [3.1 工作区修改,还未add](#3.1 工作区修改,还未add)
    • [git checkout](#git checkout)
    • [3.2 已经add,还没commit](#3.2 已经add,还没commit)
    • [3.3 已经add和commit](#3.3 已经add和commit)
  • [4. 删除文件](#4. 删除文件)

1. Git 跟踪并管理的是修改的内容,而非文件本身

Git 跟踪并管理的是修改的内容,而非文件本身,这是 Git 区别于 SVN 等其他版本控制系统的根本:

之前我们上传了一个readme文件,即它已经被提交到版本库了,现在我们来修改一下它

可以git log查看一下提交日志
那现在我们来修改一下readme文件
随便新增两行内容
修改完毕,保存退出

git status 命令

然后我们再来介绍一个命令------git status

通过上一篇文章的学习,我们知道了 Git 有工作区、暂存区和版本库。但在日常写代码时,我们不可能每次都去 .git 目录里扒底层文件。
git status 命令的作用就是:随时查看当前工作区和暂存区的状态,告诉你哪些文件被修改了、哪些准备提交、哪些还没被 Git 管理。
那刚才我们修改了readme文件,现在我们来使用git status命令查看一下

看一下它都展示了什么信息

git diff 命令

下面再介绍一个命令------git diff

用 git status 知道了"哪些文件被修改了",但 git status 不会告诉你具体改了什么。
而 git diff可以用来查看工作区(你刚改的代码)和暂存区(上次 git add 进去的代码)的内容差异。
直接敲 git diff,对比的是当前工作区所有被修改的文件和暂存区。
如果你改了三四个文件,但只想看其中某一个文件的差异,就可以把文件名跟在后面:git diff Readme
我们这里只改了一个,加不加无所谓

所以:

只要工作区的文件内容发生了改变,我们就需要重新执行 git add 和 git commit,才能把新版本记录到 Git 版本库中。
这就是 Git 最经典的开发循环:修改 -> 暂存(add) -> 提交(commit)。

2. 版本回退

我们知道git是一个版本控制器,那么其中版本回退是一个非常重要的功能,这使得git能够管理文件的历史版本,并可以回退到某一个指定版本

如果有一天你发现之前的工作做的出现了很大的问题,需要在某个特定的历史版本重新开始,这个时候,就需要版本回退的功能了

比如还来看我们之前举的这个例子

假如现在你把最后这个版本提交上去,但是老师说我觉得你这个版本的报告还没有第一版符合我的预期,你还是把第一版交上来吧!
那由于我们这里对所有的历史版本进行了管理,所以就可以很方便地找到第一版报告。

2.1 git reset

git当然也可以完成这个功能,那么git如何实现版本回退呢?------使用git reset命令来完成

要注意的是:
"回退"的本质,是将版本库中的状态(分支指针)进行回退,而工作区或暂存区是否跟着回退,完全由你添加的命令参数决定。

我们通过一个具体的案例来介绍这个命令:


之前我们提交过两个文件,并且readme文件进行了修改,修改后重新进行了add和commit。

现在Readme文件有这样三行内容,但是不要忘记了

第一次的提交readme文件中只有一行,后面两行是我们后面修改新增的。
所以对于这个readme文件来说,它是有两个版本的

"回退"的本质,是将版本库中的状态(分支指针)进行回退,而工作区或暂存区是否跟着回退,完全由你添加的命令参数决定。

当前现在这三个里面的readme肯定都是最新的这个版本。
使用git reset进行回退,后面通常跟这三个选项,对应三种情况

第一个:git reset --soft <commit_id> 只回退版本库,工作区和暂存区不变

第二个:git reset --mixed <commit_id> (默认选项,git reset 的默认模式 )------将暂存区的内容退回为指定提交版本,工作区文件保持不变。

第三个:git reset --hard <commit_id>------将暂存区与工作区都退回到指定版本。
切记工作区有未提交的代码时不要用这个命令,因为工作区会回滚,你没有提交的代码就再也找不回了,所以使用该参数前一定要慎重。

然后我们来实操一下,用用这个命令,这里重点演示一下hard

首先通过 git log命令是可以查看到每次提交的信息以及对应的cimmit id(上面命令的最后一个参数即填要回退版本的commit id)
比如现在我们发现readme文件修改错了,想要回退到第一次提交后的这个版本,即readme中只有第一行内容,并想让工作区的内容也回退到这

git reset --hard 80a6a4d8dd4b10f7c8b9cb6db5ae839e5aeb7b42

那现在就回退成功了

此时我们发现,现在这个目录下就只有readme这一个文件了,并且readme里面的内容也只有最初的第一行了(因为工作区也回退了),git log也只打印了第一次的提交了!

到这里一般回退功能就演示完了,但现在如果我后悔了,想再回到修改readme文件的那个版本怎么办?

我们可以继续使用 git reset 命令,回退到这个版本,但我们必须要拿到这个版本对应的 commit id。

但是此时git log已经看不到这个版本的提交记录和commit id了!
好在终端之前的历史记录还保留了


现在就成功回到这个版本了

但是,在实际开发中,由于长时间的开发或者你中间关闭了服务器,commit id 可能无法在历史终端记录找到了,这时候还能回退吗?

2.2 git reflog (后悔药)

git log 是"正统历史":

它展示的是 Commit 链表(顺着 parent 指针走),如果你用 reset 退回了旧版本,那些被抛弃的提交在 git log 里就看不见了。

git reflog 是"操作流水账":

不管你是提交、回退、切换分支、重置版本还是合并,只要指针动了,它就会在你的本地留底。哪怕这些提交在 git log 里已经"消失"了,reflog 依然记得它们。

所以回到上面那个问题:


我们看到这里面,commit reset都被记录下来了,所以这样就可以找到修改readme文件的那个版本的commit id,但我们看到这个commit id怎么变得这么短了?
没关系,依然能用

🆗,这就回退成功了。

2.3 版本回退的底层原理

上面的操作中我们能感受到git版本回退的速度是非常快的,那它是怎么做到的呢?

通过上一篇文章的学习,我们知道Git 内部有个指向当前分支(此处是master)的 HEAD 指针,它里面存着 ref: refs/heads/master, refs/heads/master 文件里存的其实就是当前master分支里最新的一个 commit id。

(比如现在version3的提交是最新的)
当我们在回退版本的时候,Git 仅仅是给 refs/heads/master 中存储的commit id修改为要回退版本的commit id即可。

可以任务,版本回退的本质,其实就是移动指针。这自然是非常快的!

3. 撤销修改

如果我们在工作区写了很长时间的代码,发现写的实在垃圾,想恢复到原状怎么办?

这里介绍三种情况:

3.1 工作区修改,还未add

我们来看一个例子:


现在readme文件的内容是这样的,并且之前这个文件的修改我们也更新到了暂存区和版本库了
现在我们再来在工作区修改这个文件

那现在我想撤销这个修改怎么办:

直接再次编辑这个文件,然后把刚才新增那一行删掉不就行了。
这当然也没啥问题。
但如果你已经进行了很长时间的开发了,新增了很多代码在很多个地方,并且可能在很多地方进行了修改。
你可能已经忘了自己在哪些地方进行了修改了,这时候这种方法其实就不太可靠了。

git checkout

Git 其实还为我们提供了更好的方式,我们可以使用 git checkout -- file 命令让工作区的文件回到最近一次 add 或 commit 时的状态。
要注意 git checkout -- file 命令中的 -- 很重要,切记不要省略。

演示一下:

git checkout -- Readme
就成功撤销掉上次的修改了。

3.2 已经add,还没commit

工作区进行了修改,而且已经进行了add,这种情况如何撤销呢?

演示一下:

准备工作,再次修改readme,并add更新到暂存区


那现在我们想恢复到修改之前,可以怎么做呢?

回忆一下上面讲过的git reset命令


现在的情况是什么

工作区进行了修改,并且已经add,所以现在工作区和暂存区都已经发生了变化,但版本库还保留的是上一个版本的状态。
那我们这个场景可以来使用git reset嘛?
当然也是可以的,我们上面讲的用法都是使用git reset回退到历史版本,其实也可以回退到当前版本 。
怎么理解?
当前我们的版本库中是没有更新readme的这次修改的,所以当前版本库的这个版本就是没有发生修改的版本,那不这次readme文件修改之前的版本嘛。
所以我们可以回退到当前版本,那应该用哪个选项呢?

是不是可以用hard,重置工作区和暂存区到当前版本(即readme修改之前的那个版本)

这样工作区和暂存区就和当前版本库的版本一样了,那之前的修改不就被撤销了嘛。
我们来试一下,同时给大家补充一个小知识点:
我们上面介绍的gitreset 后面是跟commit id表示对应的某个版本,也可以这样:
HEAD 表示当前版本
HEAD^ 上一个版本
HEAD^^ 上上一个版本

以此类推...
还可以使用 〜数字表示:
HEAD~0 表示当前版本
HEAD~1 上一个版本
HEAD~2 表示上上一个版本

试一下:
git reset --hard HEAD

就成功撤销修改了。
那其实还有第二种方法:
我们也可以使用mixed选项,这样只把暂存区恢复到当前版本,变成这样

那这样不就变成我们讲的情况一了嘛!(这种方法大家自行尝试,不再演示)

3.3 已经add和commit

那其实就是我们第二小节(2. 版本回退)介绍的内容了嘛,依然使用git reset命令来处理:


我们后面会讲到远程版本库,一旦你推送到远程版本库(git push),本地回退的话(你的本地环境确实退回去了),但无法直接同步到远程(直接 push 会被拒绝)。

4. 删除文件

来看一个例子:


当前我们的工作区有这两个文件,并且已经提交到版本库进行管理了。
那如果现在我想删掉text.txt文件,要怎么做呢?

两种方法:

法一:

直接rm删除可以吗
这样只是在工作区进行了删除,暂存区和版本库并没有同步。
之前提到过,对工作区的修改(这里的"修改"包括:新增,修改,删除),要重新进行add和commit,才能同步到版本库。
所以:

这样就可以了。

法二:

再来介绍一个命令:git rm 文件名
Git 会把这个文件从你的电脑(工作区)里删掉,同时把"删除这个文件"的动作更新至暂存区
所以后面只需commit一次就可以从版本库中删除这个文件了

相关推荐
武子康1 小时前
H3-World 写了 CPU offload,为什么还不能保证塞进 48GB?
大数据·人工智能·深度学习
演艺大赏2 小时前
Doris 数据导出实战:SeaTunnel、EXPORT 与 OUTFILE 性能对比及 9.5 亿行写入故障复盘
大数据
isfox3 小时前
MapReduce 作业慢?别乱调参数,先找到瓶颈在哪
大数据
玩美数据4 小时前
市场调研数据分析与数据集驱动的行业格局变革深度解析
大数据·人工智能
Elasticsearch4 小时前
从结账告警到故障跨度:使用 Elastic 人工智能 agent 和 Elastic 应用性能监控浮出面板开展调查
elasticsearch
Elasticsearch5 小时前
认识全新的 Elastic 数据流:面向遥测数据的托管数据管道
elasticsearch
微订校园外卖系统5 小时前
校园代取快递系统选型:现成系统与定制开发的技术核对项
大数据·运维·人工智能·外卖系统·本地生活·微订
程序员爱德华6 小时前
Git 命令
git
Elasticsearch7 小时前
使用 SpiceDB 为 Elasticsearch 检索增强生成实现细粒度授权
elasticsearch