12/19 本篇章節
第五篇 · 19 章
開始使用 Git
- 01 新增、初始 Repository
- 02 把檔案交給 Git 控管
- 03 工作區、暫存區與儲存庫
- 04 檢視紀錄
- 05 【狀況題】如何在 Git 裡刪除檔案或變更檔名?
- 06 【狀況題】修改 Commit 紀錄
- 07 【狀況題】追加檔案到最近一次的 Commit
- 08 【狀況題】新增目錄?
- 09 【狀況題】有些檔案我不想放在 Git 裡面...
- 10 【狀況題】檢視特定檔案的 Commit 紀錄
- 11 【狀況題】等等,這行程式誰寫的?
- 12 【狀況題】啊!不小心把檔案或目錄刪掉了…
- 13 【狀況題】剛才的 Commit 後悔了,想要拆掉重做…
- 14 【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎?
- 15 【冷知識】HEAD 是什麼東西?
- 16 【狀況題】可以只 Commit 一個檔案的部份的內容嗎?
- 17 【冷知識】那個長得很像亂碼 SHA-1 是怎麼算出來的?
- 18 【超冷知識】在 .git 目錄裡有什麼東西?Part 1 僅收錄於電子書
- 19 【超冷知識】在 .git 目錄裡有什麼東西?Part 2 僅收錄於電子書
第五篇 · 開始使用 Git
【狀況題】啊!不小心把檔案或目錄刪掉了…
貼心小提示
本章節用到的
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...」功能:

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

按下 OK 鈕之後,剛剛刪除的那些檔案就救回來了。
這個技巧不只用在刪除的檔案可以救回來,當你修改某個檔案但後悔了,也可以用這個指令把檔案回復成它上一次 Commit 的狀態。
再怎麼樣都救得回來嗎?
也不能這麼說,因為整個 Git 的紀錄都是放在根目錄的 .git 目錄裡,所以如果這個目錄被刪了,也就是表示歷史紀錄也被刪了,那就沒得救了。
【冷知識】Git 是去哪裡把檔案救回來的?
其實是使用《火影忍者》忍術「穢土轉生」把檔案救回來的!
開玩笑的,當然不是用忍術。這裡用的 git checkout 指令,在後面提到關於分支的時候也會再度出現。當使用 git checkout 分支名稱 的時候,Git 會切換到指定的分支,但如果後面接的是檔名或路徑,Git 則不會切換分支,而是把檔案從 .git 目錄裡拉一份到目前的工作目錄。
更精準的來說,這個指令會把暫存區(Staging Area)裡的內容或檔案,拿來覆蓋工作目錄(Working Directory)的內容或檔案。所以當在上面執行 git checkout welcome.html 或 git checkout . 的時候,它會把 welcome.html 這個檔案,或是當下目錄所有檔案回復到上一次 Commit 的狀態。
如果在執行這個指令的時候這樣做多加了一個參數:
$ git checkout HEAD~2 welcome.html
這樣就會拿距離現在兩個版本以前的那個 welcome.html 檔案來覆蓋現在的工作目錄裡的 welcome.html 檔案,但要注意的是,這同時也會更新暫存區的狀態喔。
如果能理解上面這個指令的意思:
$ git checkout HEAD~2 .
這個指令的意思就是「拿距離現在兩個版本以前的檔案來覆蓋現在工作目錄的檔案,同時也更新暫存區裡的狀態」。