版本回退
上一章我们学习了Git的基本操作通过,git log
可以查看历史记录,git show
查看提交日志的相关信息。
那么假如我今天不小心把不该提交的文件给提交了。也就是修改了本地的代码,然后使用:
git add file
git commit -m '修改原因'
执行commit后,还没执行push(把修改同步到远程仓库,后面讲)时,想要撤销这次的commit,该怎么办?
这时我们可以git reset
命令,如下:
$git reset --soft HEAD^
这个命令撤销commit的修改并把修改的内容回到暂存区,测试如下:
codemaxi@codemaxi-PC:~/git_test$ git commit -m "test reset"
[master cb46378] test reset
1 file changed, 1 insertion(+)
codemaxi@codemaxi-PC:~/git_test$ git log
commit cb463782fb1a62be5b95acf9ece72155c1cb99ae (HEAD -> master)
Author: codemaxi <374867193@qq.com>
Date: Wed May 26 06:56:54 2021 +0800
test reset
commit a8d38c4eca3245e489ef1684322e5a68c6265a8b (tag: v1.0)
Author: codemaxi <374867193@qq.com>
Date: Sun May 23 22:08:15 2021 +0800
direct commit without add
codemaxi@codemaxi-PC:~/git_test$
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
无文件要提交,干净的工作区
codemaxi@codemaxi-PC:~/git_test$ git reset --soft HEAD^
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
要提交的变更:
(使用 "git reset HEAD <文件>..." 以取消暂存)
修改: test2.txt
codemaxi@codemaxi-PC:~/git_test$ git log
commit a8d38c4eca3245e489ef1684322e5a68c6265a8b (HEAD -> master, tag: v1.0)
Author: codemaxi <374867193@qq.com>
Date: Sun May 23 22:08:15 2021 +0800
direct commit without add
我们上面的测试如下:
- 修改文件并commit文件
- 通过git status查看当前已经是干净的工作区,我们使用git reset --soft HEAD^回退commit
- reset后再使用git status查看发现文件已经被回退到暂存区。
当然如果想要完全回退版本也是可以的,我们看下下面这个命令:
$git reset --hard HEAD^
这个命令不单撤销commit的修改并把add也撤销,并且还会删除工作空间的改动代码,也就是执行后这个文件彻被还原,测试如下:
codemaxi@codemaxi-PC:~/git_test$ git commit -m "test reset"
[master 1af76cf] test reset
1 file changed, 1 insertion(+)
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
无文件要提交,干净的工作区
codemaxi@codemaxi-PC:~/git_test$ git reset --hard HEAD^
HEAD 现在位于 a8d38c4 direct commit without add
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
无文件要提交,干净的工作区
codemaxi@codemaxi-PC:~/git_test$
以上就是–soft 和 --hard 的区别:–hard 会清空工作目录和暂存区的改动,而 --soft则会保留工作目录的内容,并把因为保留工作目录内容所带来的新的文件差异放进暂存区。
那么有些人可能需要将版本回退,但是我不想把修改全撤销,想把修改的内容退回工作区,这样还可以继续修改然后再次提交,这时reset mixed命令就很好的满足你了,如下:
$git reset --mixed HEAD^
测试如下:
codemaxi@codemaxi-PC:~/git_test$ git add -A
codemaxi@codemaxi-PC:~/git_test$ git commit -m "test reset mixed"
[master 0fa84f9] test reset mixed
1 file changed, 1 insertion(+)
codemaxi@codemaxi-PC:~/git_test$
codemaxi@codemaxi-PC:~/git_test$ git reset --mixed HEAD^
重置后取消暂存的变更:
M test.txt
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git checkout -- <文件>..." 丢弃工作区的改动)
修改: test.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
codemaxi@codemaxi-PC:~/git_test$
使用git reset --mixed
重置位置的同时,只保留Working Tree工作目录的內容,但会将 Index暂存区 和 Repository 中的內容更改和reset目标节点一致,因此原节点和Reset节点之间的【差异变更集】会放入Working Tree工作目录中。所以效果看起来就是原节点和Reset节点之间的所有差异都会放到工作目录中。
reset 如果不加参数,那么默认使用 --mixed 参数。它的行为是:保留工作目录,并且清空暂存区。也就是说,工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录。简而言之,就是「把所有差异都混合(mixed)放在工作目录中」。
下面就是reset三种模式最直观的区别:
- –hard:重置位置的同时,直接将 working Tree工作目录、 index 暂存区及 repository 都重置成目标Reset节点的內容,所以效果看起来等同于清空暂存区和工作区。
- –soft:重置位置的同时,保留working Tree工作目录和index暂存区的内容,只让repository中的内容和 reset 目标节点保持一致,因此原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files)。所以效果看起来就是工作目录的内容不变,暂存区原有的内容也不变,只是原节点和Reset节点之间的所有差异都会放到暂存区中。
- –mixed(默认):重置位置的同时,只保留Working Tree工作目录的內容,但会将 Index暂存区 和 Repository 中的內容更改和reset目标节点一致,因此原节点和Reset节点之间的【差异变更集】会放入Working Tree工作目录中。所以效果看起来就是原节点和Reset节点之间的所有差异都会放到工作目录中。
如果想要回退到其他版本可以如下:
HEAD 表示当前版本
HEAD^ 上一个版本
HEAD^^ 上上一个版本
HEAD^^^ 上上上一个版本
以此类推...
也可以使用 ~数字表示
HEAD~0 表示当前版本
HEAD~1 上一个版本
HEAD^2 上上一个版本
HEAD^3 上上上一个版本
以此类推...
撤销修改
那如果我不是想回退版本,而是想撤销工作区的修改呢?可以用:git checkout -- file
,测试如下:
codemaxi@codemaxi-PC:~/git_test$ echo "add four line, test checkout" >> test.txt
codemaxi@codemaxi-PC:~/git_test$ cat test.txt
test-second line
test files third line
add four line, test checkout
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git checkout -- <文件>..." 丢弃工作区的改动)
修改: test.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
codemaxi@codemaxi-PC:~/git_test$ git checkout -- test.txt
codemaxi@codemaxi-PC:~/git_test$
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
无文件要提交,干净的工作区
codemaxi@codemaxi-PC:~/git_test$
上面的情况是,我修改了文件,但是还未add到暂存区,使用git checkout -- <file>
则是从版本库中还原文件,使文件跟版本库一致。
下面再来看看这种情况:
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
要提交的变更:
(使用 "git reset HEAD <文件>..." 以取消暂存)
修改: test.txt
codemaxi@codemaxi-PC:~/git_test$
codemaxi@codemaxi-PC:~/git_test$ cat test.txt
test-second line
test files third line
test reset --mixed
codemaxi@codemaxi-PC:~/git_test$ echo "test workspace" >> test.txt
codemaxi@codemaxi-PC:~/git_test$ cat test.txt
test-second line
test files third line
test reset --mixed
test workspace
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
要提交的变更:
(使用 "git reset HEAD <文件>..." 以取消暂存)
修改: test.txt
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git checkout -- <文件>..." 丢弃工作区的改动)
修改: test.txt
codemaxi@codemaxi-PC:~/git_test$ git checkout -- test.txt
codemaxi@codemaxi-PC:~/git_test$ git status
位于分支 master
要提交的变更:
(使用 "git reset HEAD <文件>..." 以取消暂存)
修改: test.txt
codemaxi@codemaxi-PC:~/git_test$ cat test.txt
test-second line
test files third line
test reset --mixed
codemaxi@codemaxi-PC:~/git_test$
上面这种情况是
- 修改了文件并add到暂存区
- 再次修改文件,这时可以看到该文件在工作区和暂存区都有变更。
- 使用
git checkout -- <file>
回退该文件,我们查看文件内容发现该暂存区的内容一直而不是版本库的。
通过上面两种测试,总结git checkout -- <file>
就是把工作区的修改全部撤销,至于撤销到哪个状态这里有两种情况:
- file自修改后还没有提交到暂存区,这时使用撤销就会回到跟版本考一样的状态。
- file修改后如果已经添加到暂存区,然后又做了新的修改,这时使用撤销则是回到根暂存区一样的状态。
总之,就是让这个文件回到最近一次
git commit
或git add
时的状态。
好了,今天的内容就到这里了,下章我们再继续。