日常开发中,经常会遇到需要将做了一些修改的文件恢复原状的需求,在这里,尽量用简洁的描述来总结一些 Git 中不同状态下的文件如何撤销修改。
1. Git 分区
主要有 4 个分区:
- 工作区:即工作目录
- 暂存区:用于存放临时改动,通过
git add
命令即可将工作区的改动添加至暂存区 - 仓库区:用于存放提交,通过
git commit
命令即可将暂存区的内容提交至仓库区 - 远程仓库:用于托管本地仓库
2. 撤销新添加的文件(未被追踪的文件)
对于新增的文件,在仓库区
中并没有记录,对于这样未被追踪的文件,需要使用clean
命令,但clean
命令只能清理工作区
的文件,如果已经通过git add
命令添加到了暂存区
的文件,则需要先将文件退回到工作区
,然后再clean
。
1 | 针对在工作区的文件,直接clean |
3. 撤销修改的文件(已被追踪的文件)
对于已经存在于仓库区
的文件,即为已被追踪的文件,如果想要撤销这种文件的改动,需要使用restore
命令,同上面,如果文件已经添加到暂存区,那么也需要先退回到工作区,然后再撤销。
1 | 针对在工作区的文件,直接restore |
4. 撤销提交中的某个文件(已提交到仓库区的文件)
某次提交了多个文件,但是想将其中的某一个文件的修改撤回。这种情况,流程是这样的,首先需要确定文件需要回退到哪次提交的状态,比如,想撤回提交ID为C1中对文件的修改,那么也就是说,文件需要回到C1上一次的提交。然后,Git会列出目标状态之后的所有改动,只要放弃这些改动,那么文件便回到了目标状态。
1 | 查看与该文件相关的所有历史提交,用哪个都可以 |
当执行完git reset id file.name
之后,这个文件既存在于工作区,也存在于暂存区,工作区是最新的状态,暂存区是目标状态。这个时候,不管是通过git add
命令将工作区的文件添加到暂存区,还是通过git restore --staged
将暂存区的文件退回到工作区,最终都会使得这个文件变成最新状态,那么git reset
命令的效果就会消失,就像是无事发生。
只有通过git restore file.name
放弃工作区的最新状态,将暂存区的目标状态提交至仓库区,才可达到目的。
附加1: git reset 和 git revert
git reset
还可用来将分支的指针HEAD指向之前的某个提交,对于这个提交之后的所有改动,有3种处理方式:放到工作区、放到暂存区和直接丢弃。
1 | 放到工作区mixed(默认方式),两种写法是等同的 |
而git revert
用来反向修改某个提交的所有改动,然后和当前HEAD所在的提交进行合并,所以,反向修改后的内容,和最新状态的内容可能会出现冲突,这个时候需要处理冲突,然后再提交
1 | git revert commitId |
当使用git revert
恢复文件时,不用,也不能指定方式,对于目标状态之后的所有改动,只能手动处理。
附加2: git clean
这个命令只能清理工作区中未被追踪过的文件,必须同时满足这两个条件。同时,这个命令无法指定文件,是针对所有符合这两个条件的文件无差别攻击,所以,一般操作是将不需要被清理的文件先添加至暂存区避难。
删除 untracked files
1
git clean -f
删除 untracked directories
1
git clean -d
删除 gitignore 中的文件
1
git clean -x
显示将要被删除的文件(强烈建议)
1
git clean -n
以上参数可按需搭配使用,一般常用删除文件和目录,gitignore的轻易不需要删除(如果在参数加了n,那么此次操作并不会真的执行删除,只是列出会被删除的文件):
1 |
|
附加3: 文件名
所有指定文件名的地方,都支持模糊匹配,举个例子:
- 放弃工作区所有扩展名为txt文件的修改
1
2**表示任何文件夹,*.txt表示任何以.txt结尾的文件
git restore **/*.txt