使用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值,然後再次恢復。

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