git代码管理(3)—撤销操作(reset 和 checkout)

转自大神周沫凡:https://mofanpy.com/tutorials/others/git/

Git book:https://git-scm.com/book/zh/v2(p40)

目录

1.回到从前(reset)

1.1 修改已commit的版本(--amend)

1.2 取消暂存的文件(reset回到add之前:git reset HEAD )

1.3 取消已经commit的文件(reset回到commit之前:git reset --hard )

2.回到从前(撤销对文件的修改:checkout针对单个文件)


有时候我们总会忘了什么, 比如已经提交了 commit 却发现在这个 commit 中忘了附上另一个文件. 接下来我们模拟这种情况. 上节内容中, 我们最后一个 commit 是 change 2, 我们将要添加另外一个文件, 将这个修改也 commit 进 change 2. 所以我们复制 1.py 这个文件, 改名为 2.py. 并把 2.py 变成 staged, 然后使用 --amend 将这次改变合并到之前的 change 2 中.

git log --oneline   显示所有已经提交的版本,且每个 commit 内容显示在单独一行)接上节内容,首先查看一下所有log

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline    # 看看所有的log  显示已经提交的版本
2f7e561 (HEAD -> master) change 2
2d350cb change 1
d19b6a5 1.txt

1.回到从前(reset)

1.1 修改已commit的版本(--amend)

我们有时候提交完才发现漏掉了几个文件没有添加,或者提交信息写错了。此时,可以运行带有--amend选项的提交命令尝试重新提交,最终第二次提交覆盖第一次提交,且在git log --oneline命令下只显示第二次提交。

在1.txt同级文件目录下复制1.txt为2.txt【2.txt为上次提交忘记的文件】

git commit --amend 会将缓存区(已经add未commit的)的文件提交

git commit --amend --no-edit   # "--no-edit": 不编辑, 直接合并到上一个 commit

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git add 2.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git commit --amend --no-edit   # "--no-edit": 不编辑, 直接合并到上一个 commit
[master a5df2d0] change 2
 Date: Thu May 23 14:43:34 2019 +0800
 2 files changed, 6 insertions(+), 1 deletion(-)
 create mode 100644 2.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline    # "--oneline": 每个 commit 内容显示在一行
a5df2d0 (HEAD -> master) change 2   # 合并过的 change 2,此时ID改变
2d350cb change 1
d19b6a5 1.txt

由上面git log --oneline结果可知,最终第二次提交代替(覆盖)第一次提交的结果,即第二次的change 2代替第一次的change 2,且change 2 id改变

新实验:在1.py中添加b的信息,提交时错误的将提交信息写错了(写成了add a)。此时就可以应用amend重新进行编辑。

Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git add 1.py                                           #add 1.py

Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git commit -m "add a"                                  #commit 1.py,提交信息写错
[master d065dbf] add a
 1 file changed, 3 insertions(+), 1 deletion(-)

Administrator@PC201710130840 MINGW64 /f/Git (master)      #查看当下log
$ git log --oneline
d065dbf (HEAD -> master) add a
7cbef99 do a little change
434a45c create 1.py

Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git commit --amend                                   #使用amend进行修正,此时会跳入编辑框
[master 0b05ad5] add b
 Date: Wed Aug 26 14:36:08 2020 +0800
 1 file changed, 3 insertions(+), 1 deletion(-)

Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git log --oneline                         #查看当下log:最新提交信息已纠正,且覆盖,id改变
0b05ad5 (HEAD -> master) add b
7cbef99 do a little change
434a45c create 1.py

1.2 取消暂存的文件(reset回到add之前:git reset HEAD <file>)

git reset HEAD <file>将已经add过(staged状态)的文件,退回到modified状态

【多用于已经修改了两个文件,且想它们作为两次独立的修改提交,但却输入git add *暂存了两个,如何取消暂存其中的一个呢?】

例:对1.txt修改后add,后又想撤回到modified状态(add 1.txt后想取消add)

$ git add 1.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git status -s  # "-s": status 的缩写模式
M  1.txt  # staged

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git reset 1.txt     #调用reset
Unstaged changes after reset:
M       1.txt
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git status -s
 M 1.txt             # unstaged

1.3 取消已经commit的文件(reset回到commit之前:git reset --hard

git reset --hard HEAD #方式一:回到HEAD处,即最新版本

git reset --hard id  #方式二:回到指针为2d350cb所指的版本

git reset --hard HEAD@{4}  #方式三:选择想要挽救的版本(或者使用这种指定HEAD名称的方式)

在穿梭到过去的 commit 之前, 我们必须了解 git 是如何一步一步累加更改的. 我们截取网上的一些图片

 http://bramus.github.io/ws2-sws-course-materials/xx.git.html

 

(即不同的版本号是HEAD指针所在位置)

每个 commit 都有自己的 id 数字号, HEAD 是一个指针, 指引当前的状态是在哪个 commit. 最近的一次 commit 在最右边, 我们如果要回到过去, 就是让 HEAD 回到过去并 reset 此时的 HEAD 到过去的位置.

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline  #查看所有已经提交的版本
a5df2d0 (HEAD -> master) change 2  #最新版
2d350cb change 1
d19b6a5 1.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git add 1.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git reset --hard HEAD       #方式一:回到HEAD处,即最新版本
HEAD is now at a5df2d0 change 2

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git status -s   #没有输出,表示没有更新

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git reset --hard 2d350cb    #方式二:回到指针为2d350cb所指的版本  
HEAD is now at 2d350cb change 1
#回到某个版本的方式有3种,1.指定版本ID, 2.git reset --hard HEAD^^^(回到前3个版本)   3.git reset --hard HEAD~3(回到前3个版本)

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline  #此时没有change 2对应的版本了
2d350cb (HEAD -> master) change 1
d19b6a5 1.txt

git reflog查看最近做的所有HEAD的改动)怎么 change 2 消失了!!! 还有办法挽救消失的 change 2 吗? 我们可以查看 $ git reflog 里面最近做的所有 HEAD 的改动, 并选择想要挽救的 commit id 或指针名称:

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline   #当前保留的版本号
2d350cb (HEAD -> master) change 1
d19b6a5 1.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git reflog  #查看最近做的所有 HEAD 的改动
2d350cb (HEAD -> master) HEAD@{0}: reset: moving to 2d350cb
a5df2d0 HEAD@{1}: reset: moving to HEAD
a5df2d0 HEAD@{2}: commit (amend): change 2
2f7e561 HEAD@{3}: commit: change 2
2d350cb (HEAD -> master) HEAD@{4}: commit: change 1
d19b6a5 HEAD@{5}: commit (initial): 1.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git reset --hard 2f7e561   #选择想要挽救的版本:通过id
HEAD is now at 2f7e561 change 2

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline
2f7e561 (HEAD -> master) change 2
2d350cb change 1
d19b6a5 1.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git reflog
2f7e561 (HEAD -> master) HEAD@{0}: reset: moving to 2f7e561
2d350cb HEAD@{1}: reset: moving to 2d350cb
a5df2d0 HEAD@{2}: reset: moving to HEAD
a5df2d0 HEAD@{3}: commit (amend): change 2
2f7e561 (HEAD -> master) HEAD@{4}: commit: change 2
2d350cb HEAD@{5}: commit: change 1
d19b6a5 HEAD@{6}: commit (initial): 1.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git reset --hard HEAD@{4}  #选择想要挽救的版本:或者使用这种指定HEAD名称的方式
HEAD is now at 2f7e561 change 2

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline
2f7e561 (HEAD -> master) change 2
2d350cb change 1
d19b6a5 1.txt

这样我们就再次奇迹般的回到了 change 2.

NOTE:调用时加上--hard选项会使git reset成为一个危险的命令(可能导致工作目录中所有当前进度丢失)。不加选项的的git reset并不危险,它只会修改暂存区域。

新实验:

Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git reflog                                 #查看最近HEAD的改动
0b05ad5 (HEAD -> master) HEAD@{0}: commit (amend): add b
d065dbf HEAD@{1}: commit: add a
7cbef99 HEAD@{2}: commit: do a little change
434a45c HEAD@{3}: commit (initial): create 1.py

Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git reset --hard d065dbf                  #如果想退回add a这个信息的版本
HEAD is now at d065dbf add a

Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git reflog
d065dbf (HEAD -> master) HEAD@{0}: reset: moving to d065dbf
0b05ad5 HEAD@{1}: commit (amend): add b
d065dbf (HEAD -> master) HEAD@{2}: commit: add a
7cbef99 HEAD@{3}: commit: do a little change
434a45c HEAD@{4}: commit (initial): create 1.py

2.回到从前(撤销对文件的修改:checkout针对单个文件)

(其作用相当于add+commit的逆操作,使得文件从本地仓库回退到本地)

 git checkout 2d350cb -- 1.txt  #表示1.txt文件回到id号为2d350cb的版本)

                    

之前我们使用 reset 的时候是针对整个版本库(commit与commit之间来回穿梭), 回到版本库的某个过去. 不过如果我们只想回到某个文件的过去, 又该怎么办呢?

  • 改写文件checkout

其实 checkout 最主要的用途并不是让单个文件回到过去, 我们之后会继续讲 checkout 在分支 branch 中的应用, 这一节主要讲 checkout 让文件回到过去

同前面2.txt一样,创建3.txt文件

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git add 3.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git commit --amend --no-edit
[master 11f06ae] change 2
 Date: Thu May 23 14:43:34 2019 +0800
 2 files changed, 6 insertions(+), 1 deletion(-)
 create mode 100644 3.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline
11f06ae (HEAD -> master) change 2
2d350cb change 1
d19b6a5 1.txt

我们现在的版本库有两个文件:

1.txt  和 3.txt

其内容均为

查看当前版本

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline
11f06ae (HEAD -> master) change 2
2d350cb change 1
d19b6a5 1.txt

调用checkout回到过去版本

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git checkout 2d350cb -- 1.txt  #表示1.txt文件回到id号为2d350cb的版本

此时,1.txt文件内容变为:

而3.txt内容没有发生改变。

对1.txt重新进行编辑为如下:

然后add并commit 1.txt:

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git add 1.txt

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git commit -m "back to change 1 and add commit for 1.txt"
[master edb3ff8] back to change 1 and add commit for 1.txt
 1 file changed, 2 insertions(+), 3 deletions(-)

Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline
edb3ff8 (HEAD -> master) back to change 1 and add commit for 1.txt
11f06ae change 2
2d350cb change 1
d19b6a5 1.txt

可以看出,不像reset时那样,此时change 2版本仍然保留,且不影响新添加的 back to change 1 and add commit for 1.txt 版本。即1.txt既回到了过去,又改写了未来。

NOTEgit checkout --[file] 是一个危险的命令。你对那个文件做的所有修改都会消失——你只是拷贝了另一个文件来覆盖它。除非你确实不想要那个文件了,否则不要使用这个命令。

如果你仍然想保留对那个文件作出的修改,但是现在仍然需要撤销,这时使用git 分支中的保存进度与分支(通常是更好的办法)。

git 中任何已提交的东西几乎总是可以恢复的,甚至那些被删除的分支中的提交或使用 -- amend选项覆盖的提交也可以恢复。然而,任何你未提交的东西丢失后很可能再也找不到了。

总结

  • --amend 修改已commit的版本
  • git reset HEAD <file> 取消暂存的文件
  • git reset --hard 取消已经commit的文件
  • git checkout 2d350cb -- 1.txt 撤销对文件的修改
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值