章節 ▾ 第二版

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 相同的資訊,但更加簡潔和資訊豐富。它在左側列出了你已暫存的更改,在右側列出了未暫存的更改。

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

暫存和取消暫存檔案

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

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 (表示 revert) 選項。

*** 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

要檢視你已暫存內容的 diff,你可以使用 d6 (表示 diff) 命令。它會顯示一個已暫存檔案的列表,你可以選擇你想要檢視暫存 diff 的檔案。這很類似於在命令列中指定 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">

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

暫存補丁

Git 也可以暫存檔案的某些部分而忽略其餘部分。例如,如果你修改了你的 simplegit.rb 檔案兩次,並只想暫存其中一次修改而不是另一次,在 Git 中這樣做非常容易。在上一節解釋的互動式提示符下,輸入 p5 (表示 patch)。Git 會詢問你想要部分暫存哪些檔案;然後,對於選定檔案的每個部分,它會顯示檔案 diff 的“hunks”(塊),並逐個詢問你是否要暫存它們。

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

通常,你會輸入 yn 來決定是否暫存每個 hunk,但一次性暫存某些檔案中的所有 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 來提交部分暫存的檔案。

你不需要處於互動式 add 模式也可以進行部分檔案暫存 — 你可以透過在命令列中使用 git add -pgit add --patch 來啟動相同的指令碼。

此外,你還可以使用 patch 模式來部分重置檔案(使用 git reset --patch 命令),部分檢出檔案(使用 git checkout --patch 命令),以及部分暫存檔案(使用 git stash save --patch 命令)。當涉及到這些命令的高階用法時,我們會更詳細地介紹它們。