撤銷操作 —— Git 學習筆記 12

ARM的程式設計師敲著詩歌的夢發表於2018-09-07

撤銷操作

寫在前面有些撤消操作是不可逆的。 這是在使用 Git 的過程中,會因為操作失誤而導致之前的工作丟失的少有的幾個地方之一。

修改最新提交

有時候我們提交完了才發現漏掉了幾個檔案沒有新增,或者提交資訊寫錯了。 此時,可以執行帶有 --amend
項的提交命令嘗試重新提交:

$ git commit --amend

如果自上次提交以來你還未做任何修改(例如,在上次提交後馬上執行此命令),那麼快照會保持不變,而你所修改的只是提交資訊。文字編輯器啟動後,可以看到之前的提交資訊。 編輯後儲存會覆蓋原來的提交資訊。

如果你忘了提交一些檔案,那麼把這些檔案加入暫存區後,這個命令會將暫存區中的檔案提交。

例如第一次提交:

git commit -m 'initial commit'

這時候發現forgotten_file這個檔案沒有暫存,按理說應該在第一次提交。可以這樣操作:

$ git add forgotten_file
$ git commit --amend

最終你只會有一個提交,第二次提交將代替第一次提交的結果。

我們們實操一下。

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

        new file:   bar.c

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        hello.c

按理說應該把 hello.c 也加入索引,但是給忘了:

$ git commit -m "abcdefg"
[master 1380bcd] abcdefg
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bar.c

為了補救,可以執行:

$ git add hello.c

$ git commit --amend

這時候文字編輯器會啟動,可以看到之前的提交資訊。 編輯後(比如我在後面新增了幾個加號)儲存,退出文字編輯器。這時候命令列顯示:

[master 8f19240] abcdefg+++
 Date: Fri Sep 7 21:08:07 2018 +0800
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bar.c
 create mode 100644 hello.c

可以看到,後面的這次提交和之前的提交合並了,最終只有一次提交。

實際上,不管最新提交如何,你都可以編輯檔案,再更新索引(比如git add或者git rm),最後發出git commit --amend來修正最新提交。

用圖來說明就是:

這裡寫圖片描述

取消暫存的檔案

如果誤將某個檔案暫存了,可以用

git reset HEAD <file>

舉個例子。

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

實際上你不想暫存 CONTRIBUTING.md,那麼可以用

$ git reset HEAD CONTRIBUTING.md

執行後會顯示:

Unstaged changes after reset:
M   CONTRIBUTING.md

這時候你再檢視一下:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    renamed:    README.md -> README
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:   CONTRIBUTING.md

CONTRIBUTING.md 檔案已經是修改未暫存的狀態了。

如果想知道這個命令的細節,可以參考我的博文 git reset 命令詳解(二)

提示:雖然在呼叫時加上 --hard 選項可以讓 git reset 成為一個危險的命令(可能導致工作目錄中所有當前進度丟失!),但本例中工作目錄中的檔案並不會被修改。不加選項地呼叫 git reset 並不危險 —— 它只會修改暫存區。

撤消對檔案的修改

如果你不想保留對 CONTRIBUTING.md 檔案的修改怎麼辦? 你該如何將它還原成上次提交時的樣子(或者剛克隆完的樣子)? 幸運的是,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:   CONTRIBUTING.md

它非常清楚地告訴了你如何撤消之前所做的修改。 讓我們來按照提示執行:

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

可以看到那些修改已經被撤消了, CONTRIBUTING.md 確實回到了上次提交時的樣子。

注意:你需要知道 git checkout -- [file] 是一個危險的命令, 它就像是 git reset -- hard[branch] file,不僅用某次提交中的那個檔案來更新索引,同時也會覆蓋工作目錄中對應的檔案 —— 這樣對工作目錄並不安全!

寫在最後:在 Git 中任何 “已提交” 的東西幾乎總是可以恢復的。甚至那些被刪除的分支中的提交或使用 –amend 選項覆蓋的提交也可以恢復。然而,任何你“未提交”的東西丟失後很可能再也找不回來。




參考資料

【1】《Pro Git》(Scott Chacon, Ben Straub Version 2.1.14, 2018-05-19)

【2】《Git 版本控制管理(第2版)》,人民郵電出版社

相關文章