1、撤銷操作說明
我們在使用Git版本管理時,往往需要撤銷某些操作。比如說我們想將某個修改後的檔案撤銷到上一個版本,或者是想撤銷某次多餘的提交,都要用到Git的撤銷操作,因此撤銷操作在平時使用中還是比較多的。
本文介紹幾種,對於已修改過的檔案,需要進行撤銷操作,根據修改檔案出現的位置,可以分為三種情況:
- 僅僅是工作區中內容進行了修改,還未新增到暫存區。
- 檔案已經新增到暫存區,但是還未提交到本地版本庫。
- 檔案已經提交到本地版本庫。
前兩種可以叫撤銷操作,後面一種叫回退版本,不同的情況具有不同的撤銷方式。
下面就撤銷操作給出詳細的解釋。
2、撤銷工作區中檔案的修改
如果工作區的某個檔案被改亂了,但還沒有提交,可以用git restore
或者git checkout
命令找回本次修改之前的檔案。
前提:test.txt
檔案已在本地版本庫中。
(1)修改test.txt
檔案中的內容。
# 1.檢視test.txt檔案內容
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ cat test.txt
hello git
# 2.進行修改內容
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ echo "hello git v2" >> test.txt
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ cat test.txt
hello git
hello git v2
(2)檢視工作目錄中檔案的狀態。
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
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: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
好好的說明一下這些提示資訊:
On branch master
:當前工作在主分支上。Changes not staged for commit:
:暫存區中沒有可提交的變化。git add <file>...
:可使用該命令把更新新增到暫存區。git restore <file>...
:丟棄工作區的修改。同git checkout -- <file>...
命令一樣。no changes added to commit (use "git add" and/or "git commit -a")
:可以使用git add
命令新增到暫存區,也可以使用git commit -a
命令直接提交到本地版本庫。
Git的命令提示是非常詳細的,我們按照提示資訊操作就可以。
說明:
老版本Git會提示: (use "git checkout -- <file>..." to discard changes in working directory)
新版本Git會提示: (use "git restore <file>..." to discard changes in working directory)
git restore <file>...
和git checkout -- <file>...
命令:
git checkout
這個命令承擔了太多職責,既被用來切換分支,又被用來恢復工作區檔案,對使用者造成了很大的認知負擔。- Git社群釋出了Git的2.23版本中,有一個特性非常引人矚目,就是引入了兩個新命令
git switch
和git restore
,用以替代現在的git checkout
。
即:Git2.23版本開始,git restore <file>...
命令可代替git checkout -- <file>...
命令檔案恢復的工作。
(3)撤銷工作區中test.txt
檔案的修改。
# 1.使用git restore 命令撤銷工作區中的操作
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git restore test.txt
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
nothing to commit, working tree clean
# 2.再次修改test.txt檔案
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ echo "hello git v3" >> test.txt
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
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: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
# 使用git checkout命令撤銷工作區中的操作
# 撤銷操作固定寫法“git checkout -- 檔案”
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git checkout -- test.txt
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
nothing to commit, working tree clean
說明:
git checkout -- file
命令中的--
很重要,沒有--
,就變成了“切換到另一個分支”的命令,我們在後面的分支管理中會再次遇到git checkout
命令。
(4)總結
git restore <file>...
和git checkout -- <file>...
命令原理:
這裡有兩種情況:
一種是test.txt
自修改後還沒有被放到暫存區,現在的撤銷修改就回到和版本庫一模一樣的狀態;
一種是test.txt
已經新增到暫存區後,又作了修改,現在的撤銷修改就回到新增到暫存區後的狀態。- 撤銷命令是一個危險的命令,這個很重要,你對該檔案做的任何修改都會消失。原理是你拷貝了該檔案在暫存區或者本地版本庫中的副本,來覆蓋工作區的該檔案。
即:工作區的檔案變化一旦被撤銷,就無法找回了,除非你確實不想要這個檔案了。
所以我的理解:撤銷命令實際的操作是重置(原檔案覆蓋),而實際的效果上是撤回。
3、撤銷暫存區中檔案的修改
如果已經把修改的個檔案新增到暫存區,可以用下面的命令撤銷。
還是以上面test.txt
檔案為例。
(1)修改test.txt
檔案並儲存到暫存區。
# 1.修改檔案
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
nothing to commit, working tree clean
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ echo "hello git v4" >> test.txt
# 2.新增檔案到暫存區
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git add test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory
# 3.檢視工作目錄中檔案狀態
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test.txt
說明:
Changes to be committed:
:表示暫存區中所做的更改如下,可以提交。git restore --staged <file>...
:該命令表示取消暫存,把暫存區中的檔案撤回到工作區。
Tips:
老版本Git會提示: (use "git reset HEAD <file>..." to unstage)
新版本Git會提示: (use "git restore --staged <file>..." to unstage)
和上面同理:
- 早期的Git中
git checkout
命令承載了分支操作和檔案恢復的部分功能,有點複雜,並且難以使用和學習,所以社群解決將這兩部分功能拆分開,Git 2.23.0版本中中引入了兩個新的命令git switch
和git restore
。 - 早期的Git中,檔案恢復涉及到兩個命令,一個是
git checkout
命令,一個是git reset
命令。git reset
命令除了重置分支之外,還提供了恢復檔案的能力。 - 而新的
git restore
命令,代替了checkout
命令和reset
命令(但是這兩個命令還可以進行檔案恢復),專門用來恢復暫存區和工作區的檔案。
(2)撤銷暫存區中test.txt
檔案的修改。
1)使用git restore --staged
命令撤銷暫存區中檔案的修改。
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git restore --staged test.txt
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
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: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
(重點)我們可以看到,test.txt
檔案從暫存區中撤銷到工作區中,但是不會撤銷工作區中檔案的更改。
2)使用git restore
命令,不帶--staged
引數,撤銷暫存區中檔案的修改。
# 1.檔案新增到暫存區中
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git add test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test.txt
# 2.使用`git restore`命令,撤銷暫存區中檔案的修改
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git restore test.txt
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test.txt
我們可以看到,工作目錄中test.txt
檔案狀態沒有改變,所以要撤銷暫存區中檔案的修改,必須加上--staged
引數。
這是為什麼呢?(個人理解)
因為git restore
命令,不帶--staged
引數,背後的執行邏輯是,把暫存中的test.txt
檔案複製一份,覆蓋掉工作區的test.txt
檔案,但是這樣就形成了test.txt
檔案在工作區和暫存區一樣的狀態,所以工作區和暫存區的狀態也一樣。這也就是上面執行完git restore test.txt
命令,在工作目錄test.txt
檔案的狀態,沒有變化的原因。
3)使用git reset HEAD <file>...
命令撤銷暫存區中檔案的修改。
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git reset HEAD test.txt
Unstaged changes after reset: # 表示重置後檔案未被跟蹤
M test.txt # M:應該是modified的意思吧
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
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: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
我們看到git reset HEAD <file>...
命令的執行效果和git restore --staged
命令執行的效果是一樣的,這裡就不多解釋了。
之後要在進行撤銷工作區中檔案的修改,就和上一步一樣了。
4、總結
前面通過詳細的步驟,分別演示了從工作區和暫存區做撤銷修改的操作。
下面我們總結一下,方便我們對前面知識的理解。
git checkout
命令,既可以用來切換分支,又可以用來恢復工作區檔案。
恢復檔案命令:git checkout -- 檔案
git reset
命令,除了能夠重置分支之外,還提供了恢復檔案的能力。
恢復檔案命令:git reset HEAD 檔案
- Git 2.23.0版本中,提供了
git restore
命令,代替了git checkout
命令和git reset
命令的恢復檔案功能。(但上面兩個命令也能恢復檔案)
修改的檔案只在工作區,沒有新增到暫存區中,使用git restore 檔案
命令。
修改的檔案已經新增到暫存區,但還沒有提交,使用git restore --staged 檔案
命令。
在來詳細說明一下git restore
命令:
這裡有兩種情況:
一種是test.txt
自修改後還沒有被放到暫存區,現在的撤銷修改就回到和版本庫一模一樣的狀態;
一種是test.txt
已經新增到暫存區後,又作了修改,現在的撤銷修改就回到新增到暫存區後的狀態。
而git restore --staged
命令:
用於已經把修改的檔案新增到暫存區,沒有被修改,但還未提交。這時執行該命令,直接撤銷暫存區總儲存的修改,將檔案恢復到工作區去。