進階Git:學會使用更強大命令

進階Git:學會使用更強大命令

Git是一個功能強大的版本控制工具,在這一領域具有一定的壟斷地位。對於大多數日常工作而言,Git的命令重複性使其簡單易用。然而,在很多情況下,你需要的不僅僅是基本的操作。因此,有很多高階 Git 命令可以讓你的 Git 技能更上一層樓。

這也會讓你瞭解到很多平時接觸不到的 Git 概念。例如,相對於提交改動的 “儲存”(stashing),”重定向”(rebasing),以及將檔案新增到暫存區(staging area)。一旦你學會了這些,你可能會發現自己對團隊的價值會更大。

在這篇博文中,介紹了你想知道的不同的強大Git命令。然而,要使用這些命令,你需要掌握一些技能、概念和資訊。讓我們先來了解一下。

  1. 推薦先決條件
  2. 進階Git:你想知道的12個強大命令

雖然您可能已經掌握了Git的基礎知識,並能理解一些中級命令,比如 git delete,但您還需要更多的工具箱來處理高階命令。

我們在此分享的技巧並不適合Git初學者,所以如果您對版本控制還很陌生,我們建議您先花些時間日常使用基本命令,然後再考慮新增更多命令。

簡而言之,以下是您必須瞭解的幾個方面:

  • Git的核心概念,如提交、分支、拉取請求等。
  • 熟悉 Git 的基本命令,如 git addgit mergegit commitgit push
  • 對於高階 Git 任務,您需要能夠瀏覽終端。

有在團隊環境中使用 Git 的經驗會更有幫助,因為很多命令都會對共享程式碼庫產生重大影響。例如,您可能只在負責的崗位上使用其中的某些命令。這意味著你需要小心謹慎,並瞭解何時使用這些命令。

進階Git:你想知道的12個強大命令

本文接下來將介紹12個不同的高階Git命令,它們將帶你超越基礎,成為Git嚮導。讓我們從您可能使用較多的命令開始。

1. 重定向

首先,重定向(rebasing)是一個強大的 Git 命令,它可以替代拉取請求。它可以將分支分歧後的所有新提交拉入一個新分支,並將這些改動放在基本分支的頂端。如果出於某種原因,您想在不建立合併提交的情況下納入另一個分支的變更,這將非常有用。

重定向的一個常見用例是,當您在特性分支上工作時,希望在不建立合併提交的情況下納入來自主分支的變更。這有助於保持專案歷史的整潔,不過執行時間會更長,而且合併時可能會出現更多錯誤。

使用 git rebase 命令來重置分支。下面是一個例子,我們將一個分支重定向到另一個分支上:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git checkout foo-branch
git rebase main
git checkout foo-branch git rebase main
git checkout foo-branch
git rebase main

您還可以列出您將要釋出的提交,併為您提供事先編輯的機會。因此,你可以壓制提交、編輯提交資訊等等。你可以使用 --interactive 或 --i 標誌來執行 “interactive rebase”。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git rebase --interactive <other-branch-name>
git rebase --interactive <other-branch-name>
git rebase --interactive <other-branch-name>

說到這一點,將提交合併為一個提交來整理提交歷史是rebasing的一個常見用例。這可以讓你的提交歷史更容易閱讀和理解。

在rebase過程中,您可以在標記後加上您希望壓扁的提交次數,這樣就可以將提交合併為一個提交:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git rebase -i HEAD~3
git rebase -i HEAD~3
git rebase -i HEAD~3

這將開啟一個互動式的rebase視窗,就像提交視窗一樣,在這裡您可以選擇和編輯您想要刪除的提交:

在終端執行 git rebase

在終端執行 git rebase。

螢幕上方是提交列表,下方是命令選項,以及一些其他相關資訊。預設選項是 pick 一個提交,將其作為您要使用的提交,不做任何改動。

不過,還有很多其他命令可以幫助你瀏覽rebase。例如,你可以重寫一個提交,或者將多個提交合並在一起。要進行修改和使用這些命令,你需要使用終端的編輯器。預設的編輯器通常是Vim,這意味著你需要熟悉該編輯器

最後一步是儲存修改,然後推送到遠端分支。

2. 回退、重置和解除快取

Git在撤銷修改方面是出了名的。一般來說,這個過程很困難,而且容易出錯。不過,如果你想撤銷對工作目錄或暫存區域的改動,有一些 Git 命令可以幫到你。

事實上,Git會在執行 git status 時告訴您如何解除檔案快取:

Git 會在狀態輸出中告訴您如何解除檔案快取

Git 會在狀態輸出中告訴您如何解除檔案快取。

因此,您可以輕鬆地從當前分支移除提交,並將其傳送到其他分支:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git reset HEAD <commit>
git reset HEAD <commit>
git reset HEAD <commit>

這樣做的效果是將分支向後移動一個提交,就像移除最後一個已知提交一樣。您甚至可能需要將分支重置為原始狀態。在這種情況下,可以使用 git reset --hard origin/main 來重置遠端起源。不過請注意,這些改動將永遠消失。

雖然 git checkout 命令是您會經常用到的基本命令,但您也可以用它在提交前解除檔案的快取:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git checkout -- <filename>
git checkout -- <filename>
git checkout -- <filename>

注意破折號和檔名佔位符之間的空格。在這裡,命令將取消您指定的檔案並丟棄工作目錄中的更改。請注意,這將刪除您對檔案所做的任何本地更改。因此,請反覆確認您不需要這些未儲存的改動。

您也可以使用 git revert 來還原提交的改動。不過,這並不是回滾修改,而是在撤銷前一個提交的基礎上建立一個新的提交。

這裡的主要區別是,命令不會移動任何引用指標到新提交,但會保留舊提交。當你想在不從提交歷史中刪除改動的情況下撤銷改動時,這很有用。

該命令期望收到一個引用,並且可以直接還原最新的提交:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git revert HEAD
git revert HEAD
git revert HEAD

不過,您可以在更大的範圍內恢復、修改檔案和提交。本 Git 高階命令列表的下兩個條目將介紹它們。

3. 將檔案恢復到預設狀態

在 Git 中,你可以使用一條新命令: git restore ,輕鬆地將檔案恢復到預設狀態。事實上,在大多數情況下,您應該把它當作 git reset 的替代品,因為它提供了更強大的功能。例如,使用 git restore --staged <filename> 和使用 git reset HEAD 可以獲得相同的結果。

該命令還能做更多–您還能將檔案恢復到預設狀態。如果您也執行 git status ,就能看到如何做到這一點:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git restore <filename>
git restore <filename>
git restore <filename>

這將從工作目錄中移除修改,就像什麼都沒發生過一樣。和 git checkout -- <filename> 一樣,您需要確保您不需要任何本地變更,因為它們將永遠消失。

4. 修改提交

很多時候,當您推送了一個提交,卻發現忘了包含一些重要的內容。有了Git,你可以很容易地修改提交,把遺漏的改動包括進去。

這需要一個特定的過程:

  • 首先,在專案需要的檔案中進行修改。
  • 使用 git add 將它們作為典型的暫存檔案。
  • 在暫存區域使用不同的命令重新提交這些改動:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git commit --amend
git commit --amend
git commit --amend

這將使用您的暫存區域用新提交修改原始提交。因此,請確保您不需要舊版本的提交,因為它將丟失。我們也建議您在本地提交時使用 --amend 標誌,而不是遠端提交,原因與我們在本篇文章中提到的類似。

您也可以使用 git commit --amend 只編輯提交資訊,命令如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git commit --amend -m "New commit message"
git commit --amend -m "New commit message"
git commit --amend -m "New commit message"

5. Git 日誌

使用 Git 的日誌可以幫助您瞭解倉庫的歷史。不過,我們不會把 git log 命令列為高階命令。相反,您可以使用各種選項來過濾輸出,以滿足您的需要:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git log
git log --decorate
git log --stat
git log git log --decorate git log --stat
git log
git log --decorate
git log --stat

例如,裝飾日誌條目會列印出所有顯示提交的 ref 名稱。 --stat 選項顯示一個提交的插入和刪除:

在終端執行 git log -stat 命令

在終端執行 git log -stat 命令。

您還可以使用其他選項來定製日誌的輸出–稱為 “提交限制”。例如,使用以下命令

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git log --author=<author-name>
git log --grep=<pattern-string>
git log --author=<author-name> git log --grep=<pattern-string>
git log --author=<author-name>
git log --grep=<pattern-string>

在這裡,您可以通過特定的作者姓名或文字模式過濾日誌。事實上,您可以結合多個選項和標誌來生成特定用途的日誌。例如

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git log --oneline --author=<author-name> --since=<date> feature-temp
git log --oneline --author=<author-name> --since=<date> feature-temp
git log --oneline --author=<author-name> --since=<date> feature-temp

搜尋自指定日期以來,某個作者在 feature-temp 分支中的所有提交,然後用單行條目列印出來。注意 <date> 引數也可以是字串:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
--since=”Two weeks ago”
--since=”Two weeks ago”
--since=”Two weeks ago”

此外,如果您想搜尋特定檔案而不是分支,可以執行以下命令:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git log --oneline --author=bartonfink --since=”5 days ago” -- readme.rm
git log --oneline --author=bartonfink --since=”5 days ago” -- readme.rm
git log --oneline --author=bartonfink --since=”5 days ago” -- readme.rm

這組示例只是略微介紹了您可以用日誌做的事情,但根據您的搜尋條件,您可以在日誌中找到精確的提交。

6. Git鉤子

您有時可能會使用巨集或其他自動化指令碼來幫助執行程式碼。Git也以鉤子的形式提供了此類功能。這些指令碼會在某些事件(如提交或推送)發生時自動執行。還有很多方法可以使用鉤子來強制程式碼格式化、執行測試等等。

鉤子有兩種型別:客戶端和伺服器端:

  • 客戶端鉤子基於提交和合並等本地操作觸發。
  • 伺服器端鉤子會根據網路操作觸發。例如,當倉庫收到推送的提交時。

Git 會在您執行 git init 時為您的 repo 新增幾個鉤子示例。不過,您需要移除 .sample 副檔名才能使用它們:

顯示 Git 在啟動時安裝的鉤子示例

MacOS 中的一個資料夾,顯示 Git 在啟動時安裝的鉤子示例。

需要注意的是,一次只能執行一種鉤子型別,不過也可以同時使用多個腳本。因此,檔名應根據示例指令碼對應鉤子型別:預提交(pre-commit)、更新(update)等。

建立 Git 鉤子

要建立一個 Git 掛鉤,需要在 .git/hooks 子目錄下建立一個可執行指令碼(不帶副檔名)。只要把它新增到hooks資料夾,它就能執行。

您可以使用任何指令碼語言,只要它能作為可執行檔案執行即可。我們建議您使用RubyPython,但您也可以使用Bash、Perl等其他語言。你所需要做的就是改變你的直譯器的路徑,而不是預設的Bash:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/usr/bin/env python
#!/usr/bin/env python
#!/usr/bin/env python

在這裡,你可以像正常一樣編寫程式碼。例如,這裡是一個 Python 的 prepare-commit 指令碼,它提示使用者寫好提交資訊:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/usr/bin/env python
import sys, os
path_commit_msg = sys.argv[1]
with open(commit_msg_filepath, 'w') as f:
f.write("# You’ll need to provide a better commit message than that, buddy!")
#!/usr/bin/env python import sys, os path_commit_msg = sys.argv[1] with open(commit_msg_filepath, 'w') as f: f.write("# You’ll need to provide a better commit message than that, buddy!")
#!/usr/bin/env python
import sys, os
path_commit_msg = sys.argv[1]
with open(commit_msg_filepath, 'w') as f:
f.write("# You’ll need to provide a better commit message than that, buddy!")

我們建議您在命令列中執行 chmod +x .git/hooks/<hook-name> 以確保可以執行。

總的來說,鉤子是自動化重複任務和在團隊中執行最佳實踐的有力工具。

7. 提交引用

在 Git 中,您可以通過 SHA-1 加密雜湊值來識別提交。雖然也可以通過完整的雜湊值來引用提交,但這樣做既繁瑣又容易出錯:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
bc7623b7a94ed3d8feaffaf7580df3eca4f5f5ca
bc7623b7a94ed3d8feaffaf7580df3eca4f5f5ca
bc7623b7a94ed3d8feaffaf7580df3eca4f5f5ca

Git 提供了幾種更簡短、更易記的提交名。例如,可以使用分支或標籤名。例如,我們可以使用一個名為 “develop” 的分支。下面是一個例子,我們引用這個分支上的最新提交:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git diff develop..HEAD
git diff develop..HEAD
git diff develop..HEAD

這顯示了 “develop” 分支上的最新提交( HEAD )與當前提交之間的差異。

您也可以通過提交歷史中的相對位置來引用提交。例如,你可以用 HEAD~2 來表示當前提交之前的兩次提交:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git diff HEAD~2..HEAD
git diff HEAD~2..HEAD
git diff HEAD~2..HEAD

Git還提供了其他幾種引用提交的方式,比如用”@”符號引用當前分支,或者用”^”符號引用提交的父分支。通過使用這些速記符號,您可以在處理提交時節省時間並避免錯誤。

8. 儲存

在通常情況下,您會認為沒有辦法在不提交的情況下儲存您對檔案所做的更改。暫存就是臨時儲存的方法。當你需要切換分支或處理不同的任務,但又不想提交修改時,這種方法非常有用。

例如,如果你需要切換分支來處理流程中的某些事情,你可以把修改儲存在當前分支,然後簽出另一個分支。從那裡,您可以在另一個分支上工作,然後提交併推送這些變更。然後,您就可以在原始分支上籤出並檢索您的工作。

儲存變更有兩種方法:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git stash
git stash
git stash

這將把您的改動儲存到一個新的儲藏庫中,並把您的工作目錄還原到上一次 HEAD 提交的狀態(即您做新改動之前的狀態)。您可以用 git stash list 列出改動,並用 git stash show 檢視。後一個命令也可以接受任何 git diff 接受的格式。

在這裡,您可以切換分支或處理其他任務。當您想取回您的改動時,執行下面的命令:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git stash apply
git stash apply
git stash apply

這將把上次隱藏的更改應用到您的工作目錄中。不過要注意的是,如果您對檔案改動過大,仍然可能會遇到衝突。畢竟, git stash 只是暫時解決問題的辦法。

您也可以有多個儲藏庫,您可以使用下面的命令指定應用哪個儲藏庫:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git stash apply stash@{n}
git stash apply stash@{n}
git stash apply stash@{n}

佔位符 {n} 是一個整數, stash@{0} 代表最新的 stash。Git 官方文件中還有一些其他的 git stash 例子。

9. Bisecting

我們敢打賭,每個人都會遇到 bug 或問題,卻不知道從哪裡開始查詢。在這種情況下,”bisecting” 可以幫助你快速找出引入問題的提交。

簡而言之,該命令通過搜尋您的提交來找出bug。一旦找到問題提交,它就會返回給你。這個命令的強大之處在於它的子命令。

要使用bisecting,首先需要執行 git bisect start 命令。Git 會將您帶到專案歷史中的第一次提交。

從這裡開始,您需要使用相關命令指出該提交是好是壞:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git bisect good
git bisect bad
git bisect good git bisect bad
git bisect good
git bisect bad

然後,Git 會將您轉到下一個提交,以測試其 “質量”。注意,您也可以用 “舊的” 替換 “好的”,用 “新的 “替換 “壞的”,以符合您的特定用例(但不能混用術語)。

從這裡開始,您可以繼續將每個提交標記為 “好” 或 “壞”,直到找到引入錯誤的提交。不過,您不必遍查每個提交–您可以指定確切的識別符號來幫助縮小搜尋範圍並縮短搜尋時間:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git bisect bad feature-test
git bisect bad feature-test
git bisect bad feature-test

這裡使用的是分支名稱,但也可以是使用整數、雜湊引用等的具體修訂版本。無論如何,一旦您找到錯誤,您可以執行以下命令之一來返回最新程式碼:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git bisect reset
git bisect reset
git bisect reset

與本列表中的所有 Git 高階命令一樣,還有很多內容需要消化,Git 文件將是必不可少的讀物。

10. 比較分支

我們在 “提交引用” 條目中提到了使用 git diff 。現在,是時候詳細瞭解一下了。您經常會發現自己的多個分支包含了不同的改動。Git 允許您使用 git diff 命令比較兩個分支之間的差異。事實上,您可以通過多種方式使用它,通常與其他命令一起使用,來調查和分析一個 repo。

基本的 git diff 命令會輸出變化概覽。它看起來很像提交合並調查的輸出:

顯示 git diff 請求的輸出

顯示 git diff 請求的輸出。

不過,您還可以深入到精確的分支、雜湊值等等。例如,要比較兩個分支,您可以執行 git diff branch1..branch2 ,然後替換佔位符:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git diff feature-branch pre-prod
git diff feature-branch pre-prod
git diff feature-branch pre-prod

您還可以比較當前分支與其他分支之間的差異:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git diff HEAD..pre-prod
git diff HEAD..pre-prod
git diff HEAD..pre-prod

請注意,這裡使用兩個點將返回兩個分支頂端之間的差值。相比之下,三個點將返回兩個分支的共同祖先之間的差異,並以此進行測試。

git log 一樣,您也可以清理輸出並細化其返回的內容。例如,git diff --name-only branch1..branch2 將只檢查哪些檔案不同,而省略上下文:

在終端執行 git diff -name-only 命令

在終端執行 git diff -name-only 命令。

您可能會發現輸出很難解析,尤其是當 “diff” 很長的時候。在這種情況下,您可以使用 --color-words 選項:

執行 git diff -color-words 命令並在終端中檢視輸出

執行 git diff -color-words 命令並在終端中檢視輸出。

總的來說, git diff 和其他命令一樣強大,尤其是當您呼叫某些選項並細化返回的差異時。

11. 應用單個提交

有時,您可能想在不合並兩個分支的情況下,將某個特定的提交從一個分支應用到另一個分支。Git 提供了 git cherry-pick 功能。您應該小心使用,但您會發現 git cherry-pick 在一些情況下可以幫到您。

一種情況是,您有一些過時的特性分支沒有合併到 main 或 trunk 中。您可以使用命令組合(比如 git log )把相關的舊提交挖掘出來,重新應用到其他地方。

使用 git log 查詢某個提交的引用。從那裡,確保您在您想cherry pick的分支上。例如,假設您想把提交 xxxxxaaaa 挑選到分支 ” trunk “。首先,簽出您的分支…

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git checkout trunk
git checkout trunk
git checkout trunk

……然後選擇您的提交:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git cherry-pick xxxxxaaaaaa
git cherry-pick xxxxxaaaaaa
git cherry-pick xxxxxaaaaaa

在很多情況下,您的提交資訊可能會過時。為了解決這個問題,你可以在命令中加入 --edit 選項。這將讓你在剔除之前提供一個新的提交資訊。

12. 給 “git add” 加點料

最後一個高階Git命令是 git add 。不,這不是個錯別字–這個最基本的 Git 命令有著驚人的力量。

舉例來說,如果您發現自己在快取區新增單個檔案,您可以使用下面的命令:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git add -p
git add -p
git add -p

通過 -p 選項,您可以在互動的基礎上對修改進行分期。 你可以檢視你對每個檔案所做的修改,然後選擇哪些需要暫存。這可以節省你大量的時間,幫助你避免不需要的修改。

雖然您可能知道可以對單個檔案進行暫存,但您也可以指定一個目錄。例如,暫存 ” new-feature“目錄下的所有檔案:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git add new-feature
git add new-feature
git add new-feature

您甚至可能想在不執行完整過程的情況下檢視 git add 的結果。您可以選擇

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git add --dry-run
git add -n
git add --dry-run git add -n
git add --dry-run
git add -n

執行後,Git會顯示是新增還是忽略這些檔案。說到忽略的檔案,你也可以把它們新增到暫存區:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git add --force
git add -f
git add --force git add -f
git add --force
git add -f

向暫存區域新增檔案可能比簡單的二進位制 “新增或不新增” 更復雜。因此,Git最核心的命令之一可以涵蓋無數種可能的情況。

小結

一旦掌握了基本的 Git 命令,您就擁有了執行專案常規版本控制任務所需的 80%的知識。然而,最後的20%才是高階Git命令大顯身手的地方。

重新排序、分段、恢復檔案等命令和技術都能讓您快速擺脫困境。更重要的是,你可以為團隊和專案提供更大的價值,幫助簡化工作流程,提高工作效率,全面提升開發者的能力。

這些高階Git命令會成為你日常工作的一部分嗎?請在下面的評論區告訴我們!

評論留言