git 如何把单个文件回退到某一版本
概要
应用场景:在进行一次完整的提交后,你可能有有这样的需求:需要将某个单文件A的内容回退或者替换为某个历史版本。
或者将某个提交C1记录下文件A替换成提交C3下记录下的文件A内容。
四条命令
下面涉及到的四条命令:
git restore #恢复命令
git reset #回退重置命令
git checkout #签出命令
git cherry-pick #单特色功能应用,挑拣樱桃~
这四条命令均可以实现文章开头提到的应用需求。下面详述具体操作和他们之间的区别。
git restore
下面以t1.txt为例,进行说明:
$cat t1.txt
Home Hello world
1
2
3
4
5
6
7
4-1
4-3
$git restore --source 88018 --worktree -- t1.txt
$ cat t1.txt
Home Hello world
1
2
3
4-1
4-2
$git status
On branch br-0
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: t1.txt
上面的脚本说明:
首先查看t1.txt里面的内容: cat t1.txt;
然后通过restore命令恢复:
git restore --source 88018 --worktree – t1.txt;
souce 指定要恢复的历史提交SHA256前5位,如本例的88018
worktree选项指定为工作目录恢复,亦即将本地工作目录内的t1.txt
内容全部替换。
如果只想替换暂存区的t1.txt,而不想替换工作目录的t1.txt的内容,可以使用–stage命令;或者可同时使用–stage --worktree选项对暂存区和工作目录进行恢复。
再通过cat t1.txt命令可以看到t1.txt里面的内容已经替换完成;
最后通过 git status查看现在工作区状态,t1.txt文件的状态为“未暂存、未提交”。
git reset
$ git reset 88018 -- t1.txt
Unstaged changes after reset:
M t1.txt
$ cat t1.txt
Home Hello world
1
2
3
4
5
6
7
4-1
4-3
$ git restore -- t1.txt
$ cat t1.txt
Home Hello world
1
2
3
4-1
4-2
$ git status
On branch br-0
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: t1.txt
一般git reset命令本身并不能起到恢复单个某版本文件的作用,它需要配合git restore – filepath。
在git 官方说明文档中,点明如果使用git reset 命令回退某个文件,那么它只能暂存区被恢复。工作区的t1.txt不会被回退。
…These forms reset the index entries for all paths that match the <pathspec> to their state at <tree-ish>. (It does not affect the working tree or the current branch.)…
一种特殊情况下可以只通过git reset本身回退某个文件至某个版本。那就是某个历史版本(提交记录)下提交的变更只有t1.txt这个文件。
如下
git reset --hard 88018
git reset命令共有5种回退模式:
- - -soft
- - -mixed
- - -hard
- - -keep
- - -merge
前面三种是常见的模式,下面着重说一下keep和merge;
- - - keep 指在回退文件版本时,保留当前工作目录中t1.txt的状态,只将暂存区和仓库重置到所需的某个历史版本(即历史提交);但不是所有时候都可以这么做,当如下情况出现时,禁止使用该选项(使用该选项会失败报错):
在当前目录下文件t1.txt有未提交的变更并且当前提交和所需重置的历史提交中t1.txt状态不一 - - -merge 和keep类似,指在回退文件版本时,保留当前工作目录中t1.txt的状态,只将暂存区和仓库重置到所需的某个历史版本(即历史提交);但不是所有时候都可以这么做,当如下情况出现时,禁止使用该选项(使用该选项会失败报错):
在当前目录下文件t1.txt有未提交的变更并且当前暂存区和所需重置的历史提交中t1.txt状态不一
在这里需要注意:一个文件,如t1.txt,的状态在重置前可能有三种状态,亦即它在工作目录、暂存区、仓库这三个地方的状态均不相同,在重置发生时,同样需要注意该文件在三个地方的状态变化。
其实上面5个重置选项一直在围绕着文件t1.txt在重置前后三个地方的状态。哪些需要重置,哪些需要保留。下面是Git官方给出的某文件在重置前后使用各选项策略的状态变化:
在使用这些选项时,请注意和checkout选项的区别
git checkout
git checkout --theirs 88018 -- t1.txt
使用theirs选项从88018签出文件t1.txt的内容到工作目录以及暂存区。
这里改变的是暂存区和工作区,当前提交不变(仓库中t1.txt内容保持原样)
git cherry-pick
git cherry-pick 88018
这里将提交88018中所有和当前提交的不同的变化重新应用于当前目录,并自动暂存和提交形成一个新的提交记录。
如果历史提交88018中只有t1.txt和当前提交不同,那么同样可以起到恢复t1.txt到历史版本的作用,只是在当前HEAD上又重新形成了一个新提交。
如果提交88018中不止t1.txt文件发生变化,那所有和当前目录下不同的提交都将发生变化。
注意:在应用该命令时,要求工作目录必须干净,否则禁止使用该命令