我们在使用Git版本管理时,往往需要撤销某些操作。比如说我们想将某个修改后的文件撤销到上一个版本,或者是想撤销某次多余的提交,都要用到Git的撤销操作,因此撤销操作在平时使用中还是比较多的。
本文介绍几种,对于已修改过的文件,需要进行撤销操作,根据修改文件出现的位置,可以分为三种情况:
前两种可以叫撤销操作,后面一种叫回退版本,不同的情况具有不同的撤销方式。
下面就撤销操作给出详细的解释。
如果工作区的某个文件被改乱了,但还没有提交,可以用git restore
或者git checkout
命令找回本次修改之前的文件。
前提:test.txt
文件已在本地版本库中。
(1)修改test.txt
文件中的内容。
# 1.查看test.txt文件内容 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ cat test.txt hello git # 2.进行修改内容 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ echo "hello git v2" >> test.txt L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ cat test.txt hello git hello git v2
(2)查看工作目录中文件的状态。
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ 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: test.txt no changes added to commit (use "git add" and/or "git commit -a")
好好的说明一下这些提示信息:
On branch master
:当前工作在主分支上。Changes not staged for commit:
:暂存区中没有可提交的变化。git add <file>...
:可使用该命令把更新添加到暂存区。git restore <file>...
:丢弃工作区的修改。同git checkout -- <file>...
命令一样。no changes added to commit (use "git add" and/or "git commit -a")
:可以使用git add
命令添加到暂存区,也可以使用git commit -a
命令直接提交到本地版本库。Git的命令提示是非常详细的,我们按照提示信息操作就可以。
说明:
老版本Git会提示: (use "git checkout -- <file>..." to discard changes in working directory)
新版本Git会提示: (use "git restore <file>..." to discard changes in working directory)
git restore <file>...
和git checkout -- <file>...
命令:
git checkout
这个命令承担了太多职责,既被用来切换分支,又被用来恢复工作区文件,对用户造成了很大的认知负担。git switch
和git restore
,用以替代现在的git checkout
。git restore <file>...
命令可代替git checkout -- <file>...
命令文件恢复的工作。(3)撤销工作区中test.txt
文件的修改。
# 1.使用git restore 命令撤销工作区中的操作 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git restore test.txt L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git status On branch master nothing to commit, working tree clean # 2.再次修改test.txt文件 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ echo "hello git v3" >> test.txt L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ 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: test.txt no changes added to commit (use "git add" and/or "git commit -a") # 使用git checkout命令撤销工作区中的操作 # 撤销操作固定写法“git checkout -- 文件” L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git checkout -- test.txt L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git status On branch master nothing to commit, working tree clean
说明:
git checkout -- file
命令中的--
很重要,没有--
,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout
命令。
(4)总结
git restore <file>...
和git checkout -- <file>...
命令原理:test.txt
自修改后还没有被放到暂存区,现在的撤销修改就回到和版本库一模一样的状态;test.txt
已经添加到暂存区后,又作了修改,现在的撤销修改就回到添加到暂存区后的状态。所以我的理解:撤销命令实际的操作是重置(原文件覆盖),而实际的效果上是撤回。
如果已经把修改的个文件添加到暂存区,可以用下面的命令撤销。
还是以上面test.txt
文件为例。
(1)修改test.txt
文件并存储到暂存区。
# 1.修改文件 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git status On branch master nothing to commit, working tree clean L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ echo "hello git v4" >> test.txt # 2.添加文件到暂存区 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git add test.txt warning: LF will be replaced by CRLF in test.txt. The file will have its original line endings in your working directory # 3.查看工作目录中文件状态 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: test.txt
说明:
Changes to be committed:
:表示暂存区中所做的更改如下,可以提交。git restore --staged <file>...
:该命令表示取消暂存,把暂存区中的文件撤回到工作区。Tips:
老版本Git会提示: (use "git reset HEAD <file>..." to unstage)
新版本Git会提示: (use "git restore --staged <file>..." to unstage)
和上面同理:
git checkout
命令承载了分支操作和文件恢复的部分功能,有点复杂,并且难以使用和学习,所以社区解决将这两部分功能拆分开,Git 2.23.0版本中中引入了两个新的命令git switch
和git restore
。git checkout
命令,一个是git reset
命令。git reset
命令除了重置分支之外,还提供了恢复文件的能力。git restore
命令,代替了checkout
命令和reset
命令(但是这两个命令还可以进行文件恢复),专门用来恢复暂存区和工作区的文件。(2)撤销暂存区中test.txt
文件的修改。
1)使用git restore --staged
命令撤销暂存区中文件的修改。
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git restore --staged test.txt L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ 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: test.txt no changes added to commit (use "git add" and/or "git commit -a")
(重点)我们可以看到,test.txt
文件从暂存区中撤销到工作区中,但是不会撤销工作区中文件的更改。
2)使用git restore
命令,不带--staged
参数,撤销暂存区中文件的修改。
# 1.文件添加到暂存区中 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git add test.txt warning: LF will be replaced by CRLF in test.txt. The file will have its original line endings in your working directory L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: test.txt # 2.使用`git restore`命令,撤销暂存区中文件的修改 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git restore test.txt L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: test.txt
我们可以看到,工作目录中test.txt
文件状态没有改变,所以要撤销暂存区中文件的修改,必须加上--staged
参数。
这是为什么呢?(个人理解)
因为git restore
命令,不带--staged
参数,背后的执行逻辑是,把暂存中的test.txt
文件复制一份,覆盖掉工作区的test.txt
文件,但是这样就形成了test.txt
文件在工作区和暂存区一样的状态,所以工作区和暂存区的状态也一样。这也就是上面执行完git restore test.txt
命令,在工作目录test.txt
文件的状态,没有变化的原因。
3)使用git reset HEAD <file>...
命令撤销暂存区中文件的修改。
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ git reset HEAD test.txt Unstaged changes after reset: # 表示重置后文件未被跟踪 M test.txt # M:应该是modified的意思吧 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ 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: test.txt no changes added to commit (use "git add" and/or "git commit -a")
我们看到git reset HEAD <file>...
命令的执行效果和git restore --staged
命令执行的效果是一样的,这里就不多解释了。
之后要在进行撤销工作区中文件的修改,就和上一步一样了。
前面通过详细的步骤,分别演示了从工作区和暂存区做撤销修改的操作。
下面我们总结一下,方便我们对前面知识的理解。
git checkout
命令,既可以用来切换分支,又可以用来恢复工作区文件。git checkout -- 文件
git reset
命令,除了能够重置分支之外,还提供了恢复文件的能力。git reset HEAD 文件
git restore
命令,代替了git checkout
命令和git reset
命令的恢复文件功能。(但上面两个命令也能恢复文件)git restore 文件
命令。git restore --staged 文件
命令。在来详细说明一下git restore
命令:
这里有两种情况:
一种是test.txt
自修改后还没有被放到暂存区,现在的撤销修改就回到和版本库一模一样的状态;
一种是test.txt
已经添加到暂存区后,又作了修改,现在的撤销修改就回到添加到暂存区后的状态。
而git restore --staged
命令:
用于已经把修改的文件添加到暂存区,没有被修改,但还未提交。这时执行该命令,直接撤销暂存区总存储的修改,将文件恢复到工作区去。