git回退到指定版本的两种方式:reset、revert

在我们使用git管理代码过程中,有时会遇到代码错误提交的情况,需要回退到之前节点的某个版本。

两种回退方式:revert, 回退到之前的某个版本用reset;
1.三棵树工作区

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

Git 作为一个系统,是以它的一般操作来管理并操纵这三棵树的:
树 用途

HEAD

上一次提交的快照,下一次提交的父结点

Index

预期的下一次提交的快照

Working Directory

沙盒

HEAD

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

其实,查看快照的样子很容易。 下例就显示了 HEAD 快照实际的目录列表,以及其中每个文件的 SHA-1 校验和:
git cat-file -p HEAD

1
2
3
4
5
6
$  git cat-file -p HEAD
tree 7307a09b3133fc28722faa0611ec8e679082560c
parent c15d2fdfa6900db63b847390b8f524cedd52d353
author haiming <brave.yhm@gmail.com> 1704732740 +0800
committer haiming <brave.yhm@gmail.com> 1704732740 +0800
update:细节调整

git ls-tree -r HEAD

1
2
3
4
5
6
7
8
9
$git ls-tree -r HEAD
100644 blob 34317f337e89d14062fcd05988e417255c05434d .gitignore
100644 blob 24e8c7df85b004a198dec213d0c49ae9c5b8a7b0 README.md
100644 blob 9f940974b6fb56251f4dd7a8e6fa95dcc02c8426 _config.anzhiyu.yml
100644 blob 466437de259f6b22bddd5d272aca49f365645275 _config.yml
100644 blob 4fa50c3b13d4317538890a8721c3a86ee0fc5107 package-lock.json
100644 blob 972b2f1a6c30b303c9b2458d671a7a87451feddd package.json


Git 的 cat-file 和 ls-tree 是底层命令,它们一般用于底层工作,在日常工作中并不使用。 不过它们能帮助我们了解到底发生了什么。
索引
索引是你的 预期的下一次提交。 我们也会将这个概念引用为 Git 的“暂存区”,这就是当你运行 git commit 时 Git 看起来的样子。
Git 将上一次检出到工作目录中的所有文件填充到索引区,它们看起来就像最初被检出时的样子。 之后你会将其中一些文件替换为新版本,接着通过 git commit 将它们转换为树来用作新的提交。

1
2
3
4
5
6
7
git ls-files -s      
100644 34317f337e89d14062fcd05988e417255c05434d 0 .gitignore
100644 3f6db9f763c71c046ce7ee8ab81eecc9284c990e 0 README.md
100644 bb2617e85aeccc66d6f812611ac286c111d38daf 0 _config.anzhiyu.yml
100644 7b4885ada19a3cf5e31c9a41b8a2d5bfd0cec296 0 _config.yml
100644 4fa50c3b13d4317538890a8721c3a86ee0fc5107 0 package-lock.json
100644 972b2f1a6c30b303c9b2458d671a7a87451feddd 0 package.json

再说一次,我们在这里又用到了 git ls-files 这个幕后的命令,它会显示出索引当前的样子。

确切来说,索引在技术上并非树结构,它其实是以扁平的清单实现的。不过对我们而言,把它当做树就够了。

工作目录

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

$ tree
.
├── README
├── Rakefile
└── lib
    └── simplegit.rb
 
1 directory, 3 files

2.工作流程

经典的 Git 工作流程是通过操纵这三个区域来以更加连续的状态记录项目快照的。

git_images

  1. git revert

  2. 查看版本号:
    可以通过命令行查看(输入git log):

2.使用“git revert -n 版本号”反做,并使用“git commit -m 版本名”提交:
(1)反做,使用“git revert -n 版本号”命令。如下命令,我们反做版本号为8b89621的版本:

git revert -n 3f6db9f763c71c046ce7ee8ab81eecc9284c990e

注意: 这里可能会出现冲突,那么需要手动修改冲突的文件。而且要git add 文件名。

(2)提交,使用“git commit -m 版本名”,如:

git commit -m “revert add text.txt”

此时可以用“git log”查看本地的版本信息,可见多生成了一个新的版本

3.使用“git push”推上远程库:

git push

  1. git reset

原理: git reset的作用是修改HEAD的位置,即将HEAD指向的位置改变为之前存在的某个版本;

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

移动 HEAD 分支的指向 (若指定了 --soft,则到此停止)

使索引看起来像 HEAD (若未指定 --hard,则到此停止)

使工作目录看起来像索引

操作过程:

git log 查看提交记录的版本号;

git reset –hard 版本号 :回退到指定版本, git reset –hard 0afbc228ff7e5568303e6f9a52b7146973a3e672

git push -f 将回退的后版本强推到远程主机。此时如果用“git push”会报错,因为我们本地库HEAD指向的版本比远程库的要旧: