撤銷更改
相信你已經瞭解了 git
的基本概念,也清楚了工作區,暫存區和版本庫的關係,現在讓我們用所學的知識繼解決實際問題吧!
背景
正常看得見的目錄是我們最為熟悉的工作區,在工作中不可能總是100%的精力,難免會犯錯,尤其是下午犯困,晚上加班更是如此.下面列舉了常見的一些場景
- 場景一: 工作區出現意外更改且尚未新增到暫存區
北京時間現在是晚上10點鐘,你正在趕製一份工作報告,儘管心中一萬個不願意,還是不得不做.
開始模擬意外更改前,先檢視一下 test.txt
檔案相關資訊:
# 列出當前目錄的檔案
$ ls
file1.txt file2.txt file3.txt newFile.txt test.txt
# 檢視 `test.txt` 檔案內容
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
# 檢視 `test.txt` 檔案狀態
$ git status
On branch master
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: test.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
no changes added to commit (use "git add" and/or "git commit -a")
# 檢視 `test.txt` 檔案差異
$ git diff
diff --git a/test.txt b/test.txt
index d31bdd2..56c76b7 100644
--- a/test.txt
+++ b/test.txt
@@ -3,4 +3,4 @@ git init
git diff
understand how git control version
how git work
-git tracks changes
+git tracks changes of files
$
複製程式碼
還記得在上一節中我們講解 git
版本控制的到底是什麼,為了證明 git
管理的是更改而不是檔案本身,我們特意在第二次更改時沒有新增到暫存區,現在我們先把這個遺留問題解決掉.
# 工作區更改新增到暫存區
$ git add test.txt
# 暫存區內容提交到版本沒哭
$ git commit -m "git tracks changes of files"
[master b7bda05] git tracks changes of files
1 file changed, 1 insertion(+), 1 deletion(-)
# 檢視檔案狀態
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
nothing added to commit but untracked files present (use "git add" to track)
$
複製程式碼
現在正在加班加點幹活,一不小心將心中的不滿表露出來了,於是有了下面的內容:
# 意外更改正是這麼犯傻的一句話
$ echo "My stupid boss still prefers svn" >> test.txt
# 當前檔案內容
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
My stupid boss still prefers svn
$
複製程式碼
雖然強打精神,可還是很困,於是打算喝杯咖啡提提神,猛然發現 stupid boss 可能會讓你丟掉這個月的獎金!
暗自慶幸,咖啡果然是個好東西,既然發現了問題,那就事不宜遲趕緊修復,因為不適宜的話正是 stupid boss ,所以你完全可以手動刪除,但是假如你說了一大堆不合適的話,或者複製貼上時弄錯了,這就不是刪除一兩行那麼簡單了!
既然手動解決比較麻煩,那git
有沒有什麼好方法來解決這類問題呢?在尋求git
幫助前,首先再看一下當前檔案狀態(git status
).正所謂"知己知彼方能百戰百勝",還是看一眼吧!
# 檢視檔案狀態
$ git status
On branch master
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: test.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
no changes added to commit (use "git add" and/or "git commit -a")
$
複製程式碼
git
不負眾望,果然給了我們希望,(use "git checkout -- <file>..." to discard changes in working directory)
這句話的告訴我們可以丟棄工作區的更改!
腦海中在快速回憶一下工作區,暫存區,版本庫三者之間的關係,其實git checkout -- <file>
命令的意思是用暫存區的內容替換掉工作區內容,因此也就是丟棄掉工作區的更改了.
事不宜遲,執行 git checkout -- <file>
命令試試看吧:
# 丟棄工作區的更改
$ git checkout -- test.txt
# 檢視檔案內容: My stupid boss still prefers svn 終於不見了
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
# 檢視檔案狀態
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
nothing added to commit but untracked files present (use "git add" to track)
$
複製程式碼
一頓操作猛如虎,撤銷掉意外更改,回到上一次版本控制狀態,世界如此美好...
注意:
git checkout -- <file>
中的--
至關重要,沒有它就是切換分支了!
- 場景二: 工作區出現意外更改且已經新增到暫存區,但尚未提交到版本庫
時間一分一秒過去了,轉眼間已經11點了,假設你不但寫了一些胡話,還新增到暫存區了(git add
).可想而知,這次意外比場景一要糟糕.
# 模擬正常提交(不然豈不是從場景一到場景二你什麼都沒做,那還能叫做趕製工作報告嗎?!)
$ echo "someone prefers svn,but i don't care it" >> test.txt
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
$ git add test.txt
$ git commit -m "normal commit"
[master ab1cbd2] normal commit
1 file changed, 1 insertion(+)
# 意外更改的前夕
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
# 意外更改內容: my teammate is stupid too.
$ echo "my teammate is stupid too." >> test.txt
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
my teammate is stupid too.
# 意外操作: 將意外更改內容提交到暫存區
$ git add test.txt
複製程式碼
不過慶幸的是,在提交到版本庫(git commit
)之前及時發現問題,還是看一下現在的檔案狀態(git status
)吧!
# 檢視檔案狀態: 救命稻草 (use "git reset HEAD <file>..." to unstage)
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: test.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
$
複製程式碼
git
同樣告訴我們,可以使用 git reset HEAD <file>
命令撤銷暫存區更改.
其實 git reset HEAD <file>
命令是用版本庫的內容替換掉暫存區的內容,也就是說原來暫存區的內容已被丟棄了!
所以說這個命令並不會影響工作區內容,不如我們現在再看一眼工作區內容,方便執行 git reset HEAD <file>
命令後證實我們的結論.
# 檢視檔案內容: my teammate is stupid too.
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
my teammate is stupid too.
$
複製程式碼
迫不及待執行 git reset HEAD <file>
命令,先睹為快!
# 救命稻草: 版本庫內容替換掉暫存區內容
$ git reset HEAD test.txt
Unstaged changes after reset:
M test.txt
# 效果: 目標檔案已修改但未新增到暫存區
$ git status
On branch master
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: test.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
no changes added to commit (use "git add" and/or "git commit -a")
# 目標檔案內容: 仍然保持不變
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
my teammate is stupid too.
$
複製程式碼
現在場景二已經退化成場景一了,目標檔案發生意外更改但還沒新增到暫存區,如何撤銷工作區更改,請參考場景一方法.
提示:
git checkout -- test.txt
- 場景三: 工作區出現意外更改不僅已新增到暫存區,還已提交到版本庫,但尚未推送到遠端倉庫
時間不緊不慢地已經到凌晨了,睏意越來越濃,洋洋灑灑寫下幾千字的工作報告,總算是寫完了,新增到暫存區(git add
),提交到版本庫(git commit
)一氣呵成,等等,好像有什麼不對勁,難免會犯糊塗,這不又發生意外了!
# 銜接場景二
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
# 正常提交一
$ echo "i love working,work makes me happy" >> test.txt
$ git add test.txt
$ git commit -m "encourage myself"
[master a44cf7a] encourage myself
1 file changed, 1 insertion(+)
# 正常提交二
$ echo "fix 110 bugs,so happy" >> test.txt
$ git add test.txt
$ git commit -m "fix bugs"
[master c66399d] fix bugs
1 file changed, 1 insertion(+)
sunpodeMacBook-Pro:demo sunpo$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
nothing added to commit but untracked files present (use "git add" to track)
# 意外更改: hate to work overtime
$ echo "hate to work overtime" >> test.txt
$ git add test.txt
$ git commit -m "test.txt"
[master c965724] test.txt
1 file changed, 1 insertion(+)
$
複製程式碼
天妒英才,加班加點做事情,本想贏得老闆的賞識,沒想到最後一句話"hate to work overtime"讓所有的努力都付之一炬,怎麼辦?
死馬當活馬醫,還是照例看看git status
能提供什麼建議吧!
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
nothing added to commit but untracked files present (use "git add" to track)
$
複製程式碼
沒有提供任何意見能幫助我們撤銷意外更改,先別慌,容我深思三秒鐘...
既然意外更改已經提交到版本庫,那麼應該用什麼內容替換版本庫內容呢?有了,既然最新版本庫不可用,那上一個版本庫內容可用的啊,完全可以用上一個版本庫內容替換最新版本庫內容,真乃"天生我材必有用"!
# 當前檔案內容: 闖禍的"hate to work overtime"
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
i love working,work makes me happy
fix 110 bugs,so happy
hate to work overtime
# 版本回退: 回到過去假裝什麼都沒發生過
$ git reset --hard HEAD^
HEAD is now at c66399d fix bugs
sunpodeMacBook-Pro:demo sunpo$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
nothing added to commit but untracked files present (use "git add" to track)
# 歲月靜好,一切似乎都沒發生過
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
i love working,work makes me happy
fix 110 bugs,so happy
# 當前檔案狀態
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
nothing added to commit but untracked files present (use "git add" to track)
$
複製程式碼
詳情請參考回到過去,時空穿越之旅就是這麼方便哈!
提示:
git reset --hard HEAD^
- 場景四: 工作區出現意外更改不僅已新增到暫存區,還提交到版本庫,還已推送到遠端倉庫
場景一到場景三都是本地倉庫,所有的檔案更改只能本機訪問,小夥伴也好,上級領導也罷都無法檢視到你本地更改,但是一旦你推送到遠端倉庫了,那麼其他人就能檢視你的更改了!
正常的提交更改還好,怕就怕這種"stupid boss"被領導看到就不好了,那應該怎麼辦?暫時還是自求多福吧!
小結
- 丟棄工作區更改:
git checkout -- <file>
- 丟棄暫存區更改:
git reset HEAD <file>
- 丟棄本地版本庫更改:
git reset --hard HEAD^
- 丟棄遠端版本庫更改: 自求多福