Git 时光穿梭

时间:2024-04-18 17:56:47

文章目录

    • 一、问题引入
    • 二、前置知识
    • 三、工作区暂存区和版本库
    • 四、版本回退
      • 1、版本回退命令
      • 2、四大常见场景
      • 3、删除文件
    • 总结

一、问题引入

假设这样一个场景:有一天你的老板让你整理一份报告,结果你很轻松的整理完了第一版,但是你的老板并不满意,于是老板给你不断的提出建议,你不断的修改,于是报告就迭代出了版本1、版本2、版本3……但是老板拿到最新版本的报告之后,摇了摇头说:“我还是觉得版本1比较好,你把版本1拿给我吧”。这个时候你可能想“杀”他的心都有了,因为你是在一个报告中迭代的,版本1你早就不知道长什么样了。

这次经历之后,你留了一个心眼,每次你在进行修改的时候,都创建一个副本,结果就是一份报告分散出好多的文件,可是如果过了一周,看着这些乱起八糟的文件,你想找到修改的内容,但是已经记不清保存在哪个文件中了,只好一个一个文件去找,非常麻烦。并且如果你想保留最新的文件,然后把其他文件删掉,但是你又不敢删,怕哪天还会用到,真郁闷。

针对以上问题,难道就没有一种完美的解决方案的吗?于是 Git 等版本控制系统横空出世。其中 Git 版本回退可以说是 Git 的杀手锏之一,注意是之一,后面还有之二、之三……这个我们之后在介绍。

二、前置知识

为了更好的理解 Git ,在讲 Git 之前,我们先引入一些前置知识:

  1. git add 将文件提交到暂存区。
  2. git commit 将文件提交到本地仓库。
  3. git status 可以让我们随时掌握工作区的状态(哪些文件被修改过)。
  4. git diff 顾名思义就是查看difference,可以查看修改内容,显示的格式是Unix通用的diff格式。
  5. git log 命令显示从最近到最远的提交日志(加上--pretty=oneline会更加可观)。

上面这些命令不作为本期重点,大家可以自行了解。

三、工作区暂存区和版本库

  • 工作区:就是你在电脑里能看到的目录。
  • 暂存区:英文叫 stageindex。一般存放在 “.git” 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
  • 版本库:工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

下面这张图就展示了

其实细心的小伙伴就发现了,除了工作区,暂存区,版本库,还有两个就是 objectmaster

  • 在Git中,所有的数据都以对象(objects)的形式存储(文件内容,提交信息,分支引用等等)。objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容。
  • 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。

Git 跟踪并管理的是修改(新增、删除、更改、新建)

四、版本回退

1、版本回退命令

git reset 命令在 Git 中被用来移动 HEAD 指针和重置当前分支的位置。它有几种不同的用法,主要包括以下三种模式:soft、mixed 和 hard。

1. Soft 模式git reset --soft <commit_id>:该命令将 HEAD 指向 <commit_id>,但不会更改暂存区和工作目录的内容。你可以重新提交更改,新的提交将建立在指定的 <commit_id> 之上。

2. Mixed 模式git reset --mixed <commit_id>(默认行为):该命令将 HEAD 指向 <commit_id>,并重置暂存区的内容为指定 <commit_id> 的内容,但不会更改工作目录的内容。这样你可以重新选择要提交的内容。

3. Hard 模式git reset --hard <commit_id>:该命令将 HEAD 指向 <commit_id>,同时重置暂存区和工作目录的内容为指定 <commit_id> 的内容。慎用此命令,因为会丢失工作目录中未提交的更改。

除了以上几种模式外,git reset 还可以结合使用一些选项和参数来实现不同的操作,如:

(1)git reset HEAD <file>:将指定文件从暂存区中移除,但保留在工作目录中的更改。

(2)git reset --hard HEAD:将工作目录和暂存区都重置为最近一次提交的状态,丢弃所有未提交的更改。

(3)git checkout -- [file]: 命令让⼯作区的文件回到最近⼀次 addcommit 时的状态。要注意 git checkout – [file] 命令中的-- 很重要,切记不要省略,⼀旦省略,就变成了“切换到另一个分支”的命令。

注:

  • HEAD 表示当前版本
  • HEAD^ 上⼀个版本
  • HEAD^^ 上上⼀个版本
    以此类推…

也可以使⽤ 〜数字表示:

  • HEAD~0 表示当前版本
  • HEAD~1 上⼀个版本
  • HEAD^2 上上⼀个版本
    以此类推…

2、四大常见场景

(1)场景一:使用 --hard 将工作区、暂存区、版本库进行了回退,结果后悔了怎么办

在Git中,总是有后悔药可以吃的。例如当你用 git reset --hard HEAD^ 回退到上一个版本时,再想恢复到之前的版本,就必须找到之前版本的 commit id。Git提供了一个命令 git reflog 用来记录你的每一次命令,你可以通过这个命令找到之前的版本 id,然后使用 git reset --hard <commit_id> 进行恢复。

(2)场景二:对于⼯作区的代码,还没有 add

直接使用 git checkout -- <file_name> 即可回退到最近一次工作区修改。

(3)场景三:已经 add ,但没有 commit

先使用 git reset --mixed HEAD <file_name> 回到场景二。

再使用 git checkout -- <file_name> 回退到最近一次工作区修改。

(4)场景四:已经 add ,并且也 commit 了

不要担心,我们可以 git reset --hard HEAD^ 回退到上⼀个版本!不过,这是有条件的,就是你还没有把⾃⼰的本地版本库推送到远程。还记得Git是分布式版本控制系统吗?我们后⾯会讲到远程版本库,⼀旦你推送到远程版本库,你就真的惨了……

3、删除文件

再 Git 中删除也是修改,也可以被 Git 管理起来。

一般情况下,你直接在工作区中把文件给删除了,这个时候 Git 是可以知道你删除了文件的,你可以使用 git status 命令查看哪些文件被删除了。

其实在实际的工作中,删除文件的操作是比较少见的,此时一般会存在两种情况:

情况一:确实想要从版本库中删除文件

  1. 使用 git rm <file_name> 删除掉
  2. 使用 git commit 提交删除

情况二:不小心删错了,属于误删情况

  • git checkout – <file_name> 恢复即可

总结

值得注意的是,Git 的版本回退速度非常快,因为 Git 在内部有个指向当前版本的 HEAD 指针,当你回退版本的时候,Git 仅仅是把 HEAD 指针指向回退的版本即可。