章節 ▾ 第二版

7.2 Git 工具 - 互動式暫存

互動式暫存

在本節中,你將瞭解一些互動式 Git 命令,它們可以幫助你精心組織提交,使其只包含特定檔案組合和檔案部分。如果你對大量檔案進行了大量修改,然後決定將這些更改劃分為多個重點突出的提交,而不是一個龐大而混亂的提交,那麼這些工具會很有幫助。這樣,你就可以確保你的提交是邏輯上獨立的一組更改,並且可以輕鬆地被與你合作的開發人員審查。

如果你執行帶 -i--interactive 選項的 git add 命令,Git 會進入互動式 Shell 模式,顯示如下內容:

$ git add -i
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb

*** Commands ***
  1: [s]tatus     2: [u]pdate      3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff        7: [q]uit       8: [h]elp
What now>

你可以看到,這個命令為你顯示了一個與你平時習慣的暫存區檢視大不相同的介面——基本上,它提供了與 git status 相同的資訊,但更簡潔、更具資訊量。它在左側列出了已暫存的更改,在右側列出了未暫存的更改。

接下來是“命令”部分,它允許你執行多項操作,例如暫存和取消暫存檔案、暫存檔案的一部分、新增未跟蹤檔案以及顯示已暫存內容的差異。

暫存和取消暫存檔案

如果你在 What now> 提示符處鍵入 u2 (表示更新),系統會提示你選擇要暫存的檔案:

What now> u
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Update>>

要暫存 TODOindex.html 檔案,你可以鍵入它們的編號:

Update>> 1,2
           staged     unstaged path
* 1:    unchanged        +0/-1 TODO
* 2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Update>>

每個檔案旁邊的 * 表示該檔案已被選中待暫存。如果你在 Update>> 提示符處未輸入任何內容就按下 Enter 鍵,Git 會將所有選中的內容為你暫存。

Update>>
updated 2 paths

*** Commands ***
  1: [s]tatus     2: [u]pdate      3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff        7: [q]uit       8: [h]elp
What now> s
           staged     unstaged path
  1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb

現在你可以看到 TODOindex.html 檔案已暫存,而 simplegit.rb 檔案仍未暫存。如果你想此時取消暫存 TODO 檔案,可以使用 r3 (表示恢復) 選項:

*** Commands ***
  1: [s]tatus     2: [u]pdate      3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff        7: [q]uit       8: [h]elp
What now> r
           staged     unstaged path
  1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Revert>> 1
           staged     unstaged path
* 1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Revert>> [enter]
reverted one path

再次檢視 Git 狀態,你可以看到你已取消暫存 TODO 檔案。

*** Commands ***
  1: [s]tatus     2: [u]pdate      3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff        7: [q]uit       8: [h]elp
What now> s
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb

要檢視已暫存內容的差異,你可以使用 d6 (表示差異) 命令。它會顯示你已暫存的檔案列表,你可以選擇要檢視已暫存差異的檔案。這與在命令列中指定 git diff --cached 非常相似。

*** Commands ***
  1: [s]tatus     2: [u]pdate      3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff        7: [q]uit       8: [h]elp
What now> d
           staged     unstaged path
  1:        +1/-1      nothing index.html
Review diff>> 1
diff --git a/index.html b/index.html
index 4d07108..4335f49 100644
--- a/index.html
+++ b/index.html
@@ -16,7 +16,7 @@ Date Finder

 <p id="out">...</p>

-<div id="footer">contact : support@github.com</div>
+<div id="footer">contact : email.support@github.com</div>

 <script type="text/javascript">

透過這些基本命令,你可以使用互動式新增模式更輕鬆地處理你的暫存區。

暫存補丁

Git 還可以只暫存檔案的某些部分而非全部。例如,如果你對 simplegit.rb 檔案進行了兩處修改,並希望只暫存其中一處而保留另一處不暫存,這在 Git 中非常容易實現。在上一節中解釋過的同一個互動式提示符下,鍵入 p5 (表示補丁)。Git 會詢問你希望部分暫存哪些檔案;然後,對於所選檔案的每個部分,它會顯示檔案差異的“hunk”(塊),並逐一詢問你是否希望暫存它們:

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index dd5ecc4..57399e0 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -22,7 +22,7 @@ class SimpleGit
   end

   def log(treeish = 'master')
-    command("git log -n 25 #{treeish}")
+    command("git log -n 30 #{treeish}")
   end

   def blame(path)
Stage this hunk [y,n,a,d,/,j,J,g,e,?]?

此時你有很多選項。鍵入 ? 會顯示你可以執行的操作列表:

Stage this hunk [y,n,a,d,/,j,J,g,e,?]? ?
y - stage this hunk
n - do not stage this hunk
a - stage this and all the remaining hunks in the file
d - do not stage this hunk nor any of the remaining hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

通常,如果你想暫存每個 hunk,你會鍵入 yn,但一次性暫存某些檔案中的所有 hunk,或者將某個 hunk 的決定推遲到以後再做,也可能會很有幫助。如果你暫存了檔案的一部分而將另一部分保留為未暫存狀態,你的狀態輸出將如下所示:

What now> 1
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:        +1/-1      nothing index.html
  3:        +1/-1        +4/-0 lib/simplegit.rb

simplegit.rb 檔案的狀態很有趣。它顯示有幾行已暫存,有幾行未暫存。你已經部分暫存了此檔案。此時,你可以退出互動式新增指令碼並執行 git commit 來提交部分暫存的檔案。

你也不必處於互動式新增模式才能進行部分檔案暫存——你可以在命令列上使用 git add -pgit add --patch 來啟動相同的指令碼。

此外,你可以使用補丁模式透過 git reset --patch 命令部分重置檔案,透過 git checkout --patch 命令檢出檔案部分,以及透過 git stash save --patch 命令暫存檔案部分。當我們介紹這些命令的更高階用法時,我們將詳細講解每一種用法。

scroll-to-top