使用git checkout和git reset回退到历史版本

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值,然后再次恢复。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章