Git 是一个分布式版本控制系统,它会保存文件修改的历史版本,可以使用下面的命令回退文件到某个历史版本:
-
git checkout <commit>
:把整个 git 仓库文件回退到 commit 参数指定的版本 -
git checkout [<commit>] [--] <filepath>
:回退 filepath 文件为 commit 参数指定的版本 -
git reset <commit>
:把 git 的 HEAD 指针指向到 commit 对应的版本,本地文件内容不会被回退 -
git reset --hard <commit>
:把 git 的 HEAD 指针指向到 commit 对应的版本,本地文件内容也会被回退
git checkout <commit>
git checkout <commit>
命令把整个 git 仓库文件回退到 commit 参数指定的版本,该参数值可以是具体的 commit hash 值,也可以通过 HEAD index 来指定。例如,HEAD^
对应最新版本的上一个版本,那么 git checkout HEAD^
命令回退 git 仓库下的文件内容到上一个版本,同时从当前分支脱离,处在一个未命名分支下面:
$ git checkout HEAD^
Note: checking out 'HEAD^'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at 8ba05ec...
$ git branch
* (detached from 8ba05ec)
master
此时用 git log 命令查看 log 信息,最新的 log 已经变成前面 HEAD^ 指定的 commit 信息。
由于脱离了原先的分支,修改本地文件,并执行 git commit 进行提交,不会影响原先分支。
即,如果想在原先分支上直接回退代码,不能使用这个命令。
git checkout [<commit>] [–] <filepath>
git checkout [<commit>] [--] <filepath>
命令只回退 filepath 文件到 commit 参数指定的版本,不影响其他文件,[--]
表示 --
是可选参数,用于指定后面跟着的参数只是文件路径,而不是 branch 分支名或者 commit 信息。
如果当前有一个 branch 分支名是 hello.c,且当前目录下有一个 hello.c 文件,那么不加
--
参数时,git checkout hello.c
表示切换到 hello.c 分支,而不是覆盖 hello.c 文件的改动。这种场景下,必须用git checkout -- hello.c
指定覆盖 hello.c 文件的改动,--
参数可以消除歧义。
当前 git checkout [<commit>] [--] <filepath>
命令的行为跟 git checkout [<commit>]
命令有所差异,具体说明如下:
-
git checkout [<commit>]
回退整个 git 仓库的文件。而当前命令只回退指定文件 -
git checkout [<commit>]
会从原先分支脱离,并影响 git log 显示的 commit 信息。而当前命令会停留在原先分支下,不影响 git log 显示的 commit 信息 -
git checkout [<commit>]
切换之后,用 git status 查看,会提示 ”nothing to commit, working directory clean”;而当前命令切换后,用 git status 查看,提示 ”Changes to be committed”,指定回退的文件被添加到了 git 的 staged 区域,执行 git commit,会多出一条新的 commit 信息
git reset <commit>
git reset <commit>
命令把 git 的 HEAD 指针指向到 commit 对应的版本,本地文件内容不会被回退,会停留在原先分支下。此时,用 git log 命令查看 log 信息,最新的 log 已经变成 commit 对应的信息。用 git status 命令查看,一般会提示有些文件被改动,即本地文件内容和 git 的 staged 区域内容不一致,类似于本地文件在当前 git 仓库的版本上进行了一些修改:
$ git reset HEAD^
Unstaged changes after reset:
M hello.c
$ git status
On branch new_branch_name
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: hello.c
no changes added to commit (use "git add" and/or "git commit -a")
在执行这个 git reset 命令之后,如果想让本地文件也回退到指定的版本,可以再使用 git checkout [--] <filepath>
命令来覆盖本地文件内容。
执行 git reset 命令后不会从当前分支脱离,如果想在当前分支上,将本地代码回退,就可以使用这种方法。
git reset –hard <commit>
git reset --hard <commit>
命令把 git 的 HEAD 指针指向到 commit 对应的版本,本地文件内容也会被回退,不需要再执行 git checkout 命令来回退本地文件内容。
由于 git reset 会回退 git log 显示的 commit 信息,使用 git log
命令看不到原先最新的 commit hash 值,无法使用该 commit hash 值来恢复成原先最新的版本,可以使用 git log -g
命令来看到所有操作过程的 commit 信息,就能看到原先最新的 commit hash 值,然后再次恢复。