← 上一章:【狀況題】等等,這行程式誰寫的? 下一章:【狀況題】剛才的 Commit 後悔了,想要拆掉重做… →


【狀況題】啊!不小心把檔案或目錄刪掉了…

貼心小提示

本章節用到的 rm 指令使用請小心,請不要在精神不好的時候使用,以免造成連 Git 都救不了你的悲劇。

人有失蹄馬有失手,總是有不小心或沒睡飽精神不好的時候。不管是有心或無心,在 Git 裡面如果不小心把檔案或目錄刪掉是救得回來的,這也是我們之所以使用版本控制系統最主要原因之一。這裡我先故意使用 rm 指令,把專案裡所有的 HTML 檔刪掉:

$ rm *.html

$ ls -al
total 8
drwxr-xr-x   6 eddie  wheel   204 Aug 17 04:38 .
drwxrwxrwt  65 root   wheel  2210 Aug 17 03:38 ..
drwxr-xr-x  15 eddie  wheel   510 Aug 17 04:44 .git
-rw-r--r--   1 eddie  wheel   232 Aug 16 17:14 .gitignore
drwxr-xr-x   3 eddie  wheel   102 Aug 16 16:45 config
drwxr-xr-x   2 eddie  wheel    68 Aug 16 17:19 images

的確可以看到所有的 HTML 檔都不見了。接著看一下目前的 Git 狀態:

$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	deleted:    cinderella.html
	deleted:    index.html
	deleted:    welcome.html
	deleted:    world.html

no changes added to commit (use "git add" and/or "git commit -a")

看得出來目前這四個檔案都是處於被刪除(deleted)的狀態。

別擔心,這時如果要把 cinderella.html 救回來,可以使用 git checkout 指令:

$ git checkout cinderella.html

看一下檔案列表:

$ ls -al
total 8
drwxr-xr-x   7 eddie  wheel   238 Aug 17 04:46 .
drwxrwxrwt  65 root   wheel  2210 Aug 17 04:45 ..
drwxr-xr-x  15 eddie  wheel   510 Aug 17 04:46 .git
-rw-r--r--   1 eddie  wheel   232 Aug 16 17:14 .gitignore
-rw-r--r--   1 eddie  wheel     0 Aug 17 04:46 cinderella.html
drwxr-xr-x   3 eddie  wheel   102 Aug 16 16:45 config
drwxr-xr-x   2 eddie  wheel    68 Aug 16 17:19 images

那個檔案回來了!如果想一口氣把所有被刪掉的檔案救回來:

$ git checkout .

看一下檔案列表:

$ ls -al
total 24
drwxr-xr-x  10 eddie  wheel   340 Aug 17 05:34 .
drwxrwxrwt  65 root   wheel  2210 Aug 17 04:45 ..
drwxr-xr-x  15 eddie  wheel   510 Aug 17 05:34 .git
-rw-r--r--   1 eddie  wheel   232 Aug 16 17:14 .gitignore
-rw-r--r--   1 eddie  wheel     0 Aug 17 04:46 cinderella.html
drwxr-xr-x   3 eddie  wheel   102 Aug 16 16:45 config
drwxr-xr-x   2 eddie  wheel    68 Aug 16 17:19 images
-rw-r--r--   1 eddie  wheel   161 Aug 17 05:34 index.html
-rw-r--r--   1 eddie  wheel    27 Aug 17 05:34 welcome.html
-rw-r--r--   1 eddie  wheel     0 Aug 17 05:34 world.html

你可以發現,不只六師弟回來了,剛剛被刪掉的所有檔案也都回來了。

使用 SourceTree 的話,這些被刪除的檔案前面會被標記一個減號。可以選取一個或多個檔案後,按滑鼠右鍵選擇「Reset…」功能:

reset

然後會跳出一個確認對話框,問你是否確認:

reset

按下 OK 鈕之後,剛剛刪除的那些檔案就救回來了。

這個技巧不只用在刪除的檔案可以救回來,當你修改某個檔案但後悔了,也可以用這個指令把檔案回復成它上一次 Commit 的狀態。

再怎麼樣都救得回來嗎?

也不能這麼說,因為整個 Git 的紀錄都是放在根目錄的 .git 目錄裡,所以如果這個目錄被刪了,也就是表示歷史紀錄也被刪了,那就沒得救了。

【冷知識】Git 是去哪裡把檔案救回來的?

其實是使用《火影忍者》忍術「穢土轉生」把檔案救回來的!

開玩笑的,當然不是用忍術。這裡用的 git checkout 指令,在後面提到關於分支的時候也會再度出現。當使用 git checkout 分支名稱 的時候,Git 會切換到指定的分支,但如果後面接的是檔名或路徑,Git 則不會切換分支,而是把檔案從 .git 目錄裡拉一份到目前的工作目錄。

更精準的來說,這個指令會把暫存區(Staging Area)裡的內容或檔案,拿來覆蓋工作目錄(Working Directory)的內容或檔案。所以當在上面執行 git checkout welcome.htmlgit checkout . 的時候,它會把 welcome.html 這個檔案,或是當下目錄所有檔案回復到上一次 Commit 的狀態。

如果在執行這個指令的時候這樣做多加了一個參數:

$ git checkout HEAD~2 welcome.html

這樣就會拿距離現在兩個版本以前的那個 welcome.html 檔案來覆蓋現在的工作目錄裡的 welcome.html 檔案,但要注意的是,這同時也會更新暫存區的狀態喔。

如果能理解上面這個指令的意思:

$ git checkout HEAD~2 .

這個指令的意思就是「拿距離現在兩個版本以前的檔案來覆蓋現在工作目錄的檔案,同時也更新暫存區裡的狀態」。


← 上一章:【狀況題】等等,這行程式誰寫的? 下一章:【狀況題】剛才的 Commit 後悔了,想要拆掉重做… →

Comments