章節 ▾ 第二版

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)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

在“要提交的更改”文字下方,它提示使用 git reset HEAD <file>…​ 來取消暫存。那麼,我們按照這個建議來取消暫存 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 命令你只需要知道這個神奇的用法。我們將在揭秘 Reset中更詳細地探討 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

你可以看到更改已被還原。

重要提示

重要的是要理解 git checkout -- <file> 是一個危險的命令。你對該檔案所做的任何本地更改都將消失——Git 只是用上次暫存或提交的版本替換了該檔案。除非你完全確定不想要那些未儲存的本地更改,否則絕不要使用此命令。

如果你想保留對該檔案所做的更改但現在仍需要將其移開,我們將在Git 分支中介紹儲藏和分支;這些通常是更好的方法。

請記住,Git 中任何“已提交”的內容幾乎總是可以恢復的。即使是已刪除分支上的提交或被 --amend 提交覆蓋的提交也可以恢復(請參閱資料恢復瞭解資料恢復)。但是,任何你丟失的、從未提交的內容,很可能再也找不回來了。

使用 git restore 撤消操作

Git 2.23.0 版本引入了一個新命令:git restore。它基本上是我們剛才介紹的 git reset 的一個替代品。從 Git 2.23.0 版本開始,Git 將在許多撤消操作中使用 git restore 而不是 git reset

讓我們重新回顧我們的步驟,並使用 git restore 而不是 git reset 來撤消操作。

使用 git restore 取消暫存已暫存的檔案

接下來的兩節將演示如何使用 git restore 處理你的暫存區和工作目錄的更改。好訊息是,你用來確定這兩個區域狀態的命令也會提醒你如何撤消對它們的更改。例如,假設你更改了兩個檔案並希望將它們作為兩個單獨的更改提交,但你意外地輸入了 git add * 並將它們都暫存了。你如何取消暫存其中一個呢?git status 命令會提醒你

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

在“要提交的更改”文字下方,它提示使用 git restore --staged <file>…​ 來取消暫存。那麼,我們按照這個建議來取消暫存 CONTRIBUTING.md 檔案

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

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   CONTRIBUTING.md

CONTRIBUTING.md 檔案已修改但再次取消暫存。

使用 git restore 取消修改已修改的檔案

如果你意識到不想保留對 CONTRIBUTING.md 檔案的更改怎麼辦?如何輕鬆地取消修改它——將其恢復到你上次提交時(或最初克隆時,或無論你如何將其放入工作目錄時)的樣子?幸運的是,git status 也會告訴你如何做到這一點。在上次的輸出示例中,未暫存區域看起來是這樣的

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   CONTRIBUTING.md

它非常明確地告訴你如何放棄你所做的更改。讓我們按照它說的做

$ git restore CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	renamed:    README.md -> README
重要提示

重要的是要理解 git restore <file> 是一個危險的命令。你對該檔案所做的任何本地更改都將消失——Git 只是用上次暫存或提交的版本替換了該檔案。除非你完全確定不想要那些未儲存的本地更改,否則絕不要使用此命令。

scroll-to-top