Git --fast-version-control

2.4 Git 基礎 - 復原

復原

在任何時間點,或許讀者會想要復原一些事情。 接下來我們會介紹一些基本的復原方式。 但要注意,由於有些復原動作所做的變更無法再被還原。 這是少數在使用 Git 時,執行錯誤的動作會遺失資料的情況。

更動最後一筆更新

最常見的復原發生在太早提交更新,也許忘了加入某些檔案、或者搞砸了提交的訊息。 若想要試著重新提交,可試著加上 --amend 選項:

$ git commit --amend

此命令取出暫存區資料並用來做本次的提交。 只要在最後一次提交後沒有做過任何修改(例如:在上一次提交後,馬上執行此命令),那麼整個快照看起來會與上次提交的一模一樣,唯一有更動的是提交時的訊息。

同一個文書編輯器被帶出來,並且已包含先前提交的更新內的訊息。 讀者可像往常一樣編輯這些訊息,差別在於它們會覆蓋上一次提交。

如下例,若提交了更新後發現忘了一併提交某些檔案,可執行最後一個命令:

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

這些命令的僅僅會提交一個更新,第二個被提交的更新會取代第一個。

取消已被暫存的檔案

接下來兩節展示如何應付暫存區及工作目錄的復原。 用來判斷這兩個區域狀態的命令也以相當好的方式提示如何復原。 比如說已經修改兩個檔案,並想要以兩個不同的更新提交它們,不過不小心執行 git add * 將它們同時都加入暫存區。 應該如何將其中一個移出暫存區? git status 命令已附上相關的提示:

$ git add .
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README.txt
        modified:   benchmarks.rb

在 “Changes to be commited” 文字下方,註明著使用 “git reset HEAD <file>...,將 file 移出暫存區”。 因此,讓我們依循該建議將 benchmarks.rb 檔案移出暫存區:

$ git reset HEAD benchmarks.rb
Unstaged changes after reset:
M       benchmarks.rb
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README.txt

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:   benchmarks.rb

這個命令看起來有點奇怪,不過它的確可行。 benchmarks.rb 檔案被移出暫存區了。

復原已被更動的檔案

若讀者發現其者並不需要保留 benchmarks.rb 檔案被更動部份,應該如何做才能很容易的復原為最後一次提交的狀態(或者最被複製儲存庫時、或放到工作目錄時的版本)? 很幸運的,git status 同樣也告訴讀者如何做。 在最近一次檢視狀態時,暫存區看起來應如下所示:

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:   benchmarks.rb

在這訊息中已很明確的說明如何拋棄所做的修改(至少需升級為 Git 1.6.1或更新版本。 若讀者使用的是舊版,強烈建議升級,以取得更好用的功能。) 讓我們依據命令執行:

$ git checkout -- benchmarks.rb
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README.txt

在上述文字可看到該變更已被復原。 讀者應該瞭解這是危險的命令,任何對該檔案做的修改將不復存在,就好像複製別的檔案將它覆蓋。 除非很清楚真的不需要該檔案,絕不要使用此檔案。 若需要將這些修改排除,我們在下一章節會介紹備份及分支。 一般來說會比此方法來的好。

切記,任何在 Git 提交的更新幾乎都是可復原的。 即使是分支中的更新被刪除或被 --amend 覆寫,皆能被覆原。(參考第九章關於資料的復原) 然而,未被提交的則幾乎無法救回。