转自大神周沫凡:https://mofanpy.com/tutorials/others/git/
Git book:https://git-scm.com/book/zh/v2(p40)
目录
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既回到了过去,又改写了未来。
NOTE:git checkout --[file] 是一个危险的命令。你对那个文件做的所有修改都会消失——你只是拷贝了另一个文件来覆盖它。除非你确实不想要那个文件了,否则不要使用这个命令。
如果你仍然想保留对那个文件作出的修改,但是现在仍然需要撤销,这时使用git 分支中的保存进度与分支(通常是更好的办法)。
git 中任何已提交的东西几乎总是可以恢复的,甚至那些被删除的分支中的提交或使用 -- amend选项覆盖的提交也可以恢复。然而,任何你未提交的东西丢失后很可能再也找不到了。
总结:
- --amend 修改已commit的版本
- git reset HEAD <file> 取消暂存的文件
- git reset --hard 取消已经commit的文件
- git checkout 2d350cb -- 1.txt 撤销对文件的修改