如果修改过的文件,不仅添加到暂存去,还提交到了本地仓库,已经无法撤销修改,但是可以回退到修改前的版本。
前置知识
HEAD指针
git仓库初始化之后,默认会创建一个master分支,即主分支。分支是git对版本进行管理的时间线,记录着每次提交,自动把它们串成一条时间线。
在master这条分支时间线上有很多版本的时间节点【commit-id】,而HEAD指针指向的是当前分支最新一次的版本时间节点。
* 63cd517 (HEAD -> master) v3
* 678c5a5 v2
* c34a6ba v1
HEAD可以表示相对位置:
- 单独HEAD表示当前工作分支的最新提交版本
- 使用
^
表示前一个版本,例如HEAD^
,如果要表示前2个版本,HEAD^^
,依此类推。 - 如果版本跨度大,使用
^
就不科学,可使用~加数字
表示当前版本之前的第几个版本。使用HEAD~10
表示为最新版本往前第10个版本。 - 也可以使用
HEAD@{num}
的方式表示。HEAD@{0}
就相当于HEAD
,HEAD@{1}
相当于HEAD^
。
reflog命令介绍
git reflog可以查看到被退回的commit-id历史,而git log只能查看当前HEAD之前的提交版本。
所以git reflog是引用日志,可以查看所有历史版本信息,该命令大多是为了进行版本回退或恢复操作使用,可以从中找到所需的commit 索引。
reset命令
reset命令可以实现代码回退,有soft、mixed、hard三种类型回退方式。
—soft软回退
git reset --soft commit-id
,回退到指定的版本。soft软回退,仅仅修改分支中HEAD指针的位置,不改变工作区和暂存区代码。实际只是移动了本地仓库HEAD指针的指向。
在本地创建测试项目,并添加readme.md文件,添加内容并提交,目的是回退到该版本。
# 使用git log查看历史版本记录
shuais-MacBook-Pro:reset shuai$ git log --oneline
* 63cd517 (HEAD -> master) v3
* 678c5a5 v2
* c34a6ba v1
# 使用reflog查看历史版本记录
shuais-MacBook-Pro:reset shuai$ git reflog
63cd517 (HEAD -> master) HEAD@{0}: commit: v3
678c5a5 HEAD@{1}: commit: v2
c34a6ba HEAD@{2}: commit (initial): v1
# 查看readme.md文件内容
shuais-MacBook-Pro:reset shuai$ cat readme.md
v3
向readme文件添加一行数据,并提交到本地仓库
shuais-MacBook-Pro:reset shuai$ echo "new line" >> readme.md
shuais-MacBook-Pro:reset shuai$ cat readme.md
v3new line
shuais-MacBook-Pro:reset shuai$ git commit -a -m "commit new line v4"
[master a5e5191] commit new line v4
1 file changed, 1 insertion(+), 1 deletion(-)
shuais-MacBook-Pro:reset shuai$ git log --oneline
a5e5191 (HEAD -> master) commit new line v4
63cd517 v3
678c5a5 v2
c34a6ba v1
现在可以对比工作区、暂存区、本地仓库中代码的差异。此时他们三个并无差异
# 对比工作区和暂存区中,差异
shuais-MacBook-Pro:reset shuai$ git diff readme.md
# 对比 暂存区 和本地仓库中内容差异
shuais-MacBook-Pro:reset shuai$ git diff --cached readme.md
执行reset回退
# 回退到上一个提交记录
shuais-MacBook-Pro:reset shuai$ git reset --soft HEAD^
回退后对比文件内容
# 对比工作区和暂存区文件差异,此时并无差异
shuais-MacBook-Pro:reset shuai$ git diff readme.md
# 对比暂存区和仓库中文件差异
shuais-MacBook-Pro:reset shuai$ git diff --cached readme.md
diff --git a/readme.md b/readme.md
index 04d0d54..6f67266 100644
--- a/readme.md
+++ b/readme.md
@@ -1 +1 @@
-v3
\ No newline at end of file
+v3new line
# 对比工作区和仓库中文件的差异
shuais-MacBook-Pro:reset shuai$ git diff HEAD readme.md
diff --git a/readme.md b/readme.md
index 04d0d54..6f67266 100644
--- a/readme.md
+++ b/readme.md
@@ -1 +1 @@
-v3
\ No newline at end of file
+v3new line
对比后发现,三者之前文件的差异
- 工作区和暂存区无差异
- 暂存区 和 仓库中有差异
- 工作区和仓库中 有差异
说明: 使用soft参数工作区和暂存区中内容没有回退,只有仓库中内容回退
查看提交日志
# 使用log查看历史版本记录
shuais-MacBook-Pro:reset shuai$ git log --oneline
63cd517 (HEAD -> master) v3
678c5a5 v2
c34a6ba v1
# 使用reflog查看历史记录
shuais-MacBook-Pro:reset shuai$ git reflog
63cd517 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
a5e5191 HEAD@{1}: commit: commit new line v4
63cd517 (HEAD -> master) HEAD@{2}: commit: v3
678c5a5 HEAD@{3}: commit: v2
c34a6ba HEAD@{4}: commit (initial): v1
可以看到log和reflog命令的区别:
- 使用
git log
命令查看历史记录,已经看不到a5e5191
这次提交记录 - 使用
git reflog
命令查看历史记录,可以看到a5e5191
记录还在恢复到回退前版本
```git查看工作目录中文件状态
shuais-MacBook-Pro:reset shuai$ git status On branch master Changes to be committed: (use “git restore —staged…” to unstage) modified: readme.md
此时将文件退回了暂存区中,通过commit提交即可。
提交记录
shuais-MacBook-Pro:reset shuai$ git commit -m “append newline v5” [master d352dd8] append newline v5 1 file changed, 1 insertion(+), 1 deletion(-)
查看目录中文件状态
shuais-MacBook-Pro:reset shuai$ git status On branch master nothing to commit, working tree clean
使用log查看历史记录
shuais-MacBook-Pro:reset shuai$ git log —oneline d352dd8 (HEAD -> master) append newline v5 63cd517 v3 678c5a5 v2 c34a6ba v1
已经看不到第4次提交
使用reflog查看历史记录,可以查看到所有历史记录
shuais-MacBook-Pro:reset shuai$ git reflog d352dd8 (HEAD -> master) HEAD@{0}: commit: append newline v5 63cd517 HEAD@{1}: reset: moving to HEAD^ a5e5191 HEAD@{2}: commit: commit new line v4 63cd517 HEAD@{3}: commit: v3 678c5a5 HEAD@{4}: commit: v2 c34a6ba HEAD@{5}: commit (initial): v1
通过回退 a5e5191,还有回退到第4次提交
shuais-MacBook-Pro:reset shuai$ git reset —soft a5e5191
shuais-MacBook-Pro:reset shuai$ git log —oneline a5e5191 (HEAD -> master) commit new line v4 63cd517 v3 678c5a5 v2 c34a6ba v1
会生成一条新的commit提交日志,可以看出a5e5191和第4次提交的commit一样,说明已经回退到第4次
shuais-MacBook-Pro:reset shuai$ git reflog a5e5191 (HEAD -> master) HEAD@{0}: reset: moving to a5e5191 d352dd8 HEAD@{1}: commit: append newline v5 63cd517 HEAD@{2}: reset: moving to HEAD^ a5e5191 (HEAD -> master) HEAD@{3}: commit: commit new line v4 63cd517 HEAD@{4}: commit: v3 678c5a5 HEAD@{5}: commit: v2 c34a6ba HEAD@{6}: commit (initial): v1
<a name="IO3zf"></a>
### --mixed命令回退
> mixed是混合的,中等的回退。该命令不仅修改仓库的HEAD指针,还将暂存区的数据进行了回退。但是工作区的代码状态不变
创建本地测试文件,新建readme.md文件,并添加内容。
```git
# 使用log查看提交历史记录
shuais-MacBook-Pro:rest shuai$ git log --oneline
c45fa60 (HEAD -> master) v3
86d8436 v2
d5030ef v1
# 使用reflog查看历史记录
shuais-MacBook-Pro:rest shuai$ git reflog
c45fa60 (HEAD -> master) HEAD@{0}: commit: v3
86d8436 HEAD@{1}: commit: v2
d5030ef HEAD@{2}: commit (initial): v1
新增一行数据,并提交到仓库中
# 新增一行数据
shuais-MacBook-Pro:rest shuai$ echo "new line " >> readme.md
# 提交数据
shuais-MacBook-Pro:rest shuai$ git commit -a -m "第4次提交,add new line"
[master 7bce542] 第4次提交,add new line
1 file changed, 1 insertion(+)
# 查看此时仓库的日志
shuais-MacBook-Pro:rest shuai$ git log --oneline
7bce542 (HEAD -> master) 第4次提交,add new line
c45fa60 v3
86d8436 v2
d5030ef v1
现在对比工作区、暂存区、本地仓库中文件的差异。此时3者并无差异
# 对比工作区和暂存区文件差异
shuais-MacBook-Pro:rest shuai$ git diff readme.md
# 对比暂存区和仓库文件的差异
shuais-MacBook-Pro:rest shuai$ git diff --cached readme.md
# 对比工作区和仓库文件的差异
shuais-MacBook-Pro:rest shuai$ git diff HEAD readme.md
执行回退操作,退回v3版本
shuais-MacBook-Pro:rest shuai$ git reset --mixed HEAD^
Unstaged changes after reset:
M readme.md
- Unstaged changes after reset: 说明回退后,有未被追踪的文件
- M readme.md:表示readme.md文件修改后,未被追踪。即修改后,文件未添加到暂存区的状态
- 此时文件被退回到了工作区的状态
回退后,对比文件差异
# 对比工作区和暂存区中文件差异
shuais-MacBook-Pro:rest shuai$ git diff readme.md
diff --git a/readme.md b/readme.md
index 46b68dc..36125a4 100644
--- a/readme.md
+++ b/readme.md
@@ -1 +1,2 @@
hello world v3
+new line
# 对比暂存区和仓库中文件差异
shuais-MacBook-Pro:rest shuai$ git diff --cached readme.md
#对比工作区和仓库中文件差异
shuais-MacBook-Pro:rest shuai$ git diff HEAD readme.md
diff --git a/readme.md b/readme.md
index 46b68dc..36125a4 100644
--- a/readme.md
+++ b/readme.md
@@ -1 +1,2 @@
hello world v3
+new line
通过对比可以发现:
- 工作区和暂存区的内容出现了差异
- 暂存区和仓库中没有差异
- 工作区和仓库中 出现了差异
查看提交日志
```git使用log查看历史提交记录
shuais-MacBook-Pro:rest shuai$ git log —oneline c45fa60 (HEAD -> master) v3 86d8436 v2 d5030ef v1
使用reflog查看提交记录
shuais-MacBook-Pro:rest shuai$ git reflog c45fa60 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^ 7bce542 HEAD@{1}: commit: 第4次提交,add new line c45fa60 (HEAD -> master) HEAD@{2}: commit: v3 86d8436 HEAD@{3}: commit: v2 d5030ef HEAD@{4}: commit (initial): v1
- log查看时,第4次提交记录已经不存在
- reflog查看提交记录,第4次提交记录仍然存在
<a name="AKGoW"></a>
#### 恢复到回退之前版本
`git reset --mixed commit-id`命令回退,做了2个操作
- 移动HEAD指针,即回退仓库中的代码
- 回退暂存区中的内容,将暂存区内容退到HEAD指针指向的版本
```git
shuais-MacBook-Pro:rest shuai$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.md
no changes added to commit (use "git add" and/or "git commit -a")
readme.md文件是修改未暂存状态。接下来要先添加到暂存区【add】,然后在提交【commit】
# 添加到暂存区
shuais-MacBook-Pro:rest shuai$ git add .
#提交到仓库
shuais-MacBook-Pro:rest shuai$ git commit -m "append new line v5"
# 使用log查看提交历史
shuais-MacBook-Pro:rest shuai$ git log --oneline
ead44f4 (HEAD -> master) append new line v5
c45fa60 v3
86d8436 v2
d5030ef v1
#使用reflog查看提交历史
shuais-MacBook-Pro:rest shuai$ git reflog
ead44f4 (HEAD -> master) HEAD@{0}: commit: append new line v5
c45fa60 HEAD@{1}: reset: moving to HEAD^
7bce542 HEAD@{2}: commit: 第4次提交,add new line
c45fa60 HEAD@{3}: commit: v3
86d8436 HEAD@{4}: commit: v2
d5030ef HEAD@{5}: commit (initial): v1
# 执行回退到第四次提交7bce542
shuais-MacBook-Pro:rest shuai$ git reset --mixed 7bce542
# 查看文件状态
shuais-MacBook-Pro:rest shuai$ git status
On branch master
nothing to commit, working tree clean
# log查看版本提交历史
shuais-MacBook-Pro:rest shuai$ git log --oneline
7bce542 (HEAD -> master) 第4次提交,add new line
c45fa60 v3
86d8436 v2
d5030ef v1
# 使用reflog查看提交的历史
shuais-MacBook-Pro:rest shuai$ git reflog
7bce542 (HEAD -> master) HEAD@{0}: reset: moving to 7bce542
ead44f4 HEAD@{1}: commit: append new line v5
c45fa60 HEAD@{2}: reset: moving to HEAD^
7bce542 (HEAD -> master) HEAD@{3}: commit: 第4次提交,add new line
c45fa60 HEAD@{4}: commit: v3
86d8436 HEAD@{5}: commit: v2
d5030ef HEAD@{6}: commit (initial): v1
—hard命令回退
git reset --hard commit-id
回退到指定版本,hard强硬的,严格的回退。该参数的回退,会把工作区和暂存区中的数据都回退到指定版本。【该命令谨慎使用】
本地创建测试代码库,创建出readme.md文件,git init初始化项目
# 使用log查看历史记录
shuais-MacBook-Pro:reset shuai$ git log --oneline
229cc1f (HEAD -> master) v3
be516b5 v2
04b38f8 v1
#使用reflog查看历史记录
shuais-MacBook-Pro:reset shuai$ git reflog
229cc1f (HEAD -> master) HEAD@{0}: commit: v3
be516b5 HEAD@{1}: commit: v2
04b38f8 HEAD@{2}: commit (initial): v1
# 向readme.md文件新增数据new line
$ echo "new line" >> readme.md
# 提交到本地仓库
shuais-MacBook-Pro:reset shuai$ git commit -a -m "第4次提交,新增内容new line "
[master 6804892] 第4次提交,新增内容new line
1 file changed, 1 insertion(+), 1 deletion(-)
# 查看历史日志
shuais-MacBook-Pro:reset shuai$ git log --oneline
6804892 (HEAD -> master) 第4次提交,新增内容new line
229cc1f v3
be516b5 v2
04b38f8 v1
现在可以对比工作区、暂存区、本地仓库中代码的差异。此时他们三个并无差异。
执行回退操作,退回到v3版本
# 回退到前一个提交记录的版本
shuais-MacBook-Pro:reset shuai$ git reset --hard HEAD^
HEAD is now at 229cc1f v3
HEAD is now at 229cc1f v3 意思是HEAD现在位于 229cc1f 提交记录,可以看到就是v3的版本记录。
回退后对比文件差异
# 对比工作区和暂存区
shuais-MacBook-Pro:reset shuai$ git diff readme.md
# 对比暂存区和仓库
shuais-MacBook-Pro:reset shuai$ git diff --cached readme.md
# 对比工作区和仓库
shuais-MacBook-Pro:reset shuai$ git diff HEAD readme.md
查看提交日志记录
# 使用log查看提交历史记录
shuais-MacBook-Pro:reset shuai$ git log --oneline
229cc1f (HEAD -> master) v3
be516b5 v2
04b38f8 v1
# 使用reflog查看提交历史记录
shuais-MacBook-Pro:reset shuai$ git reflog
229cc1f (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
6804892 HEAD@{1}: commit: 第4次提交,新增内容new line
229cc1f (HEAD -> master) HEAD@{2}: commit: v3
be516b5 HEAD@{3}: commit: v2
04b38f8 HEAD@{4}: commit (initial): v1
- log命令查看时,第4次提交已经不存在
-
恢复到回退前版本
git reset --hard
命令回退,做了3个操作 移动HEAD执行,回退仓库中的记录
- 暂存区内容的回退到HEAD指针指向的版本
- 工作区内容,回退到HEAD指针指向的版本
如果要恢复到回退之前的版本,也只能使用git reset —hard命令操作。 ```git# 查看文件状态,工作目录是非常干净
shuais-MacBook-Pro:reset shuai$ git status
On branch master
nothing to commit, working tree clean
1查看下可以回退的历史版本
shuais-MacBook-Pro:reset shuai$ git reflog 229cc1f (HEAD -> master) HEAD@{0}: reset: moving to HEAD^ 6804892 HEAD@{1}: commit: 第4次提交,新增内容new line 229cc1f (HEAD -> master) HEAD@{2}: commit: v3 be516b5 HEAD@{3}: commit: v2 04b38f8 HEAD@{4}: commit (initial): v1
2,执行回退,回退到第4次提交,即6804892
shuais-MacBook-Pro:reset shuai$ git reset —hard 6804892 HEAD is now at 6804892 第4次提交,新增内容new line
3 查看文件状态
shuais-MacBook-Pro:reset shuai$ git status On branch master nothing to commit, working tree clean
4使用log命令查看版本历史
shuais-MacBook-Pro:reset shuai$ git log —oneline 6804892 (HEAD -> master) 第4次提交,新增内容new line 229cc1f v3 be516b5 v2 04b38f8 v1
5使用reflog命令查看可回退的版本历史
shuais-MacBook-Pro:reset shuai$ git reflog 6804892 (HEAD -> master) HEAD@{0}: reset: moving to 6804892 229cc1f HEAD@{1}: reset: moving to HEAD^ 6804892 (HEAD -> master) HEAD@{2}: commit: 第4次提交,新增内容new line 229cc1f HEAD@{3}: commit: v3 be516b5 HEAD@{4}: commit: v2 04b38f8 HEAD@{5}: commit (initial): v1 ``` 可以看到,readme.md文件内容完全恢复。
reset使用总结
关于reset版本回退。当在v4版本中,回退到v3版本
在工作区、暂存区,仓库中文件的状态
分别执行3中回退方式
- git reset —soft HEAD^ :软性回退
- git reset —mixed HEAD^ :混合回退
- git reset —hard HEAD^ :硬性回退
soft回退示意图
从v4版本回退到v3
目录中对应的文件状态
只有HEAD指针指向了v3。工作区和暂存区都还是v4版本
修改后再次提交:
修改readme文件再次提交,会在v3版本之上创建一个新的commit记录。并移动HEAD指针指向新commit提交
如果使用git log命令查看提交历史,就看不到v4的提交信息,只有v1、v2、v3、v5。但是v4并不会在git记录中删除,会存储在git 的本地仓库中,可以使用git reflog查看到v4提交信息。
mixed回退示意图
使用git reset —mixed HEAD^命令回退到v3版本
文件状态的变化
mixed命令,完成了2步操作:
- 把HEAD指针指向了v3版本
- 把暂存区中的文件回退到HEAD的指针,即v3版本
—mixed参数是git reset默认选项,不写任何参数时也是该参数。
hard回退示意图
执行命令git reset --hard HEAD^
命令回退到v3版本
hard命令,完成了3步操作:
- 把HEAD指针指向v3版本
- 把暂存区的指针指向HEAD,也退回的到了v3版本
- 把工作区的指针指向HEAD,也退回的到了v3版本
注意⚠️:—hard参数是reset命令唯一危险的用法,是能够是git真正的销毁数据的操作。 其他任何形式的reset操作都可以轻松撤销,但是—hard选项不能,因为它强制覆盖了工作区的文件 在这种情况下,只能从仓库中找回该文件的v4提交版本,可以通过reflog来找回它。但是如果该文件还未提交,那么reflog并不会有记录,git仍会覆盖它而导致无法恢复数据。