Git是一個功能強大的版本控制工具,在這一領域具有一定的壟斷地位。對於大多數日常工作而言,Git的命令重複性使其簡單易用。然而,在很多情況下,你需要的不僅僅是基本的操作。因此,有很多高階 Git 命令可以讓你的 Git 技能更上一層樓。
這也會讓你瞭解到很多平時接觸不到的 Git 概念。例如,相對於提交改動的 “儲存”(stashing),”重定向”(rebasing),以及將檔案新增到暫存區(staging area)。一旦你學會了這些,你可能會發現自己對團隊的價值會更大。
在這篇博文中,介紹了你想知道的不同的強大Git命令。然而,要使用這些命令,你需要掌握一些技能、概念和資訊。讓我們先來了解一下。
推薦先決條件
雖然您可能已經掌握了Git的基礎知識,並能理解一些中級命令,比如 git delete
,但您還需要更多的工具箱來處理高階命令。
我們在此分享的技巧並不適合Git初學者,所以如果您對版本控制還很陌生,我們建議您先花些時間日常使用基本命令,然後再考慮新增更多命令。
簡而言之,以下是您必須瞭解的幾個方面:
- Git的核心概念,如提交、分支、拉取請求等。
- 熟悉 Git 的基本命令,如
git add
、git merge
、git commit
和git push
。 - 對於高階 Git 任務,您需要能夠瀏覽終端。
有在團隊環境中使用 Git 的經驗會更有幫助,因為很多命令都會對共享程式碼庫產生重大影響。例如,您可能只在負責的崗位上使用其中的某些命令。這意味著你需要小心謹慎,並瞭解何時使用這些命令。
進階Git:你想知道的12個強大命令
本文接下來將介紹12個不同的高階Git命令,它們將帶你超越基礎,成為Git嚮導。讓我們從您可能使用較多的命令開始。
1. 重定向
首先,重定向(rebasing)是一個強大的 Git 命令,它可以替代拉取請求。它可以將分支分歧後的所有新提交拉入一個新分支,並將這些改動放在基本分支的頂端。如果出於某種原因,您想在不建立合併提交的情況下納入另一個分支的變更,這將非常有用。
重定向的一個常見用例是,當您在特性分支上工作時,希望在不建立合併提交的情況下納入來自主分支的變更。這有助於保持專案歷史的整潔,不過執行時間會更長,而且合併時可能會出現更多錯誤。
使用 git rebase
命令來重置分支。下面是一個例子,我們將一個分支重定向到另一個分支上:
git checkout foo-branch git rebase main
您還可以列出您將要釋出的提交,併為您提供事先編輯的機會。因此,你可以壓制提交、編輯提交資訊等等。你可以使用 --interactive
或 --i
標誌來執行 “interactive rebase”。
git rebase --interactive <other-branch-name>
說到這一點,將提交合併為一個提交來整理提交歷史是rebasing的一個常見用例。這可以讓你的提交歷史更容易閱讀和理解。
在rebase過程中,您可以在標記後加上您希望壓扁的提交次數,這樣就可以將提交合併為一個提交:
git rebase -i HEAD~3
這將開啟一個互動式的rebase視窗,就像提交視窗一樣,在這裡您可以選擇和編輯您想要刪除的提交:
在終端執行 git rebase。
螢幕上方是提交列表,下方是命令選項,以及一些其他相關資訊。預設選項是 pick
一個提交,將其作為您要使用的提交,不做任何改動。
不過,還有很多其他命令可以幫助你瀏覽rebase。例如,你可以重寫一個提交,或者將多個提交合並在一起。要進行修改和使用這些命令,你需要使用終端的編輯器。預設的編輯器通常是Vim,這意味著你需要熟悉該編輯器。
最後一步是儲存修改,然後推送到遠端分支。
2. 回退、重置和解除快取
Git在撤銷修改方面是出了名的。一般來說,這個過程很困難,而且容易出錯。不過,如果你想撤銷對工作目錄或暫存區域的改動,有一些 Git 命令可以幫到你。
事實上,Git會在執行 git status
時告訴您如何解除檔案快取:
Git 會在狀態輸出中告訴您如何解除檔案快取。
因此,您可以輕鬆地從當前分支移除提交,並將其傳送到其他分支:
git reset HEAD <commit>
這樣做的效果是將分支向後移動一個提交,就像移除最後一個已知提交一樣。您甚至可能需要將分支重置為原始狀態。在這種情況下,可以使用 git reset --hard origin/main
來重置遠端起源。不過請注意,這些改動將永遠消失。
雖然 git checkout
命令是您會經常用到的基本命令,但您也可以用它在提交前解除檔案的快取:
git checkout -- <filename>
注意破折號和檔名佔位符之間的空格。在這裡,命令將取消您指定的檔案並丟棄工作目錄中的更改。請注意,這將刪除您對檔案所做的任何本地更改。因此,請反覆確認您不需要這些未儲存的改動。
您也可以使用 git revert
來還原提交的改動。不過,這並不是回滾修改,而是在撤銷前一個提交的基礎上建立一個新的提交。
這裡的主要區別是,命令不會移動任何引用指標到新提交,但會保留舊提交。當你想在不從提交歷史中刪除改動的情況下撤銷改動時,這很有用。
該命令期望收到一個引用,並且可以直接還原最新的提交:
git revert HEAD
不過,您可以在更大的範圍內恢復、修改檔案和提交。本 Git 高階命令列表的下兩個條目將介紹它們。
3. 將檔案恢復到預設狀態
在 Git 中,你可以使用一條新命令: git restore
,輕鬆地將檔案恢復到預設狀態。事實上,在大多數情況下,您應該把它當作 git reset
的替代品,因為它提供了更強大的功能。例如,使用 git restore --staged <filename>
和使用 git reset HEAD
可以獲得相同的結果。
該命令還能做更多–您還能將檔案恢復到預設狀態。如果您也執行 git status
,就能看到如何做到這一點:
git restore <filename>
這將從工作目錄中移除修改,就像什麼都沒發生過一樣。和 git checkout -- <filename>
一樣,您需要確保您不需要任何本地變更,因為它們將永遠消失。
4. 修改提交
很多時候,當您推送了一個提交,卻發現忘了包含一些重要的內容。有了Git,你可以很容易地修改提交,把遺漏的改動包括進去。
這需要一個特定的過程:
- 首先,在專案需要的檔案中進行修改。
- 使用
git add
將它們作為典型的暫存檔案。 - 在暫存區域使用不同的命令重新提交這些改動:
git commit --amend
這將使用您的暫存區域用新提交修改原始提交。因此,請確保您不需要舊版本的提交,因為它將丟失。我們也建議您在本地提交時使用 --amend
標誌,而不是遠端提交,原因與我們在本篇文章中提到的類似。
您也可以使用 git commit --amend
只編輯提交資訊,命令如下:
git commit --amend -m "New commit message"
5. Git 日誌
使用 Git 的日誌可以幫助您瞭解倉庫的歷史。不過,我們不會把 git log
命令列為高階命令。相反,您可以使用各種選項來過濾輸出,以滿足您的需要:
git log git log --decorate git log --stat
例如,裝飾日誌條目會列印出所有顯示提交的 ref 名稱。 --stat
選項顯示一個提交的插入和刪除:
在終端執行 git log -stat 命令。
您還可以使用其他選項來定製日誌的輸出–稱為 “提交限制”。例如,使用以下命令
git log --author=<author-name> git log --grep=<pattern-string>
在這裡,您可以通過特定的作者姓名或文字模式過濾日誌。事實上,您可以結合多個選項和標誌來生成特定用途的日誌。例如
git log --oneline --author=<author-name> --since=<date> feature-temp
搜尋自指定日期以來,某個作者在 feature-temp 分支中的所有提交,然後用單行條目列印出來。注意 <date>
引數也可以是字串:
--since=”Two weeks ago”
此外,如果您想搜尋特定檔案而不是分支,可以執行以下命令:
git log --oneline --author=bartonfink --since=”5 days ago” -- readme.rm
這組示例只是略微介紹了您可以用日誌做的事情,但根據您的搜尋條件,您可以在日誌中找到精確的提交。
6. Git鉤子
您有時可能會使用巨集或其他自動化指令碼來幫助執行程式碼。Git也以鉤子的形式提供了此類功能。這些指令碼會在某些事件(如提交或推送)發生時自動執行。還有很多方法可以使用鉤子來強制程式碼格式化、執行測試等等。
鉤子有兩種型別:客戶端和伺服器端:
- 客戶端鉤子基於提交和合並等本地操作觸發。
- 伺服器端鉤子會根據網路操作觸發。例如,當倉庫收到推送的提交時。
Git 會在您執行 git init
時為您的 repo 新增幾個鉤子示例。不過,您需要移除 .sample 副檔名才能使用它們:
MacOS 中的一個資料夾,顯示 Git 在啟動時安裝的鉤子示例。
需要注意的是,一次只能執行一種鉤子型別,不過也可以同時使用多個腳本。因此,檔名應根據示例指令碼對應鉤子型別:預提交(pre-commit)、更新(update)等。
建立 Git 鉤子
要建立一個 Git 掛鉤,需要在 .git/hooks 子目錄下建立一個可執行指令碼(不帶副檔名)。只要把它新增到hooks資料夾,它就能執行。
您可以使用任何指令碼語言,只要它能作為可執行檔案執行即可。我們建議您使用Ruby或Python,但您也可以使用Bash、Perl等其他語言。你所需要做的就是改變你的直譯器的路徑,而不是預設的Bash:
#!/usr/bin/env python
在這裡,你可以像正常一樣編寫程式碼。例如,這裡是一個 Python 的 prepare-commit
指令碼,它提示使用者寫好提交資訊:
#!/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 加密雜湊值來識別提交。雖然也可以通過完整的雜湊值來引用提交,但這樣做既繁瑣又容易出錯:
bc7623b7a94ed3d8feaffaf7580df3eca4f5f5ca
Git 提供了幾種更簡短、更易記的提交名。例如,可以使用分支或標籤名。例如,我們可以使用一個名為 “develop” 的分支。下面是一個例子,我們引用這個分支上的最新提交:
git diff develop..HEAD
這顯示了 “develop” 分支上的最新提交( HEAD
)與當前提交之間的差異。
您也可以通過提交歷史中的相對位置來引用提交。例如,你可以用 HEAD~2
來表示當前提交之前的兩次提交:
git diff HEAD~2..HEAD
Git還提供了其他幾種引用提交的方式,比如用”@”符號引用當前分支,或者用”^”符號引用提交的父分支。通過使用這些速記符號,您可以在處理提交時節省時間並避免錯誤。
8. 儲存
在通常情況下,您會認為沒有辦法在不提交的情況下儲存您對檔案所做的更改。暫存就是臨時儲存的方法。當你需要切換分支或處理不同的任務,但又不想提交修改時,這種方法非常有用。
例如,如果你需要切換分支來處理流程中的某些事情,你可以把修改儲存在當前分支,然後簽出另一個分支。從那裡,您可以在另一個分支上工作,然後提交併推送這些變更。然後,您就可以在原始分支上籤出並檢索您的工作。
儲存變更有兩種方法:
git stash
這將把您的改動儲存到一個新的儲藏庫中,並把您的工作目錄還原到上一次 HEAD 提交的狀態(即您做新改動之前的狀態)。您可以用 git stash list
列出改動,並用 git stash show
檢視。後一個命令也可以接受任何 git diff
接受的格式。
在這裡,您可以切換分支或處理其他任務。當您想取回您的改動時,執行下面的命令:
git stash apply
這將把上次隱藏的更改應用到您的工作目錄中。不過要注意的是,如果您對檔案改動過大,仍然可能會遇到衝突。畢竟, git stash
只是暫時解決問題的辦法。
您也可以有多個儲藏庫,您可以使用下面的命令指定應用哪個儲藏庫:
git stash apply stash@{n}
佔位符 {n}
是一個整數, stash@{0}
代表最新的 stash。Git 官方文件中還有一些其他的 git stash
例子。
9. Bisecting
我們敢打賭,每個人都會遇到 bug 或問題,卻不知道從哪裡開始查詢。在這種情況下,”bisecting” 可以幫助你快速找出引入問題的提交。
簡而言之,該命令通過搜尋您的提交來找出bug。一旦找到問題提交,它就會返回給你。這個命令的強大之處在於它的子命令。
要使用bisecting,首先需要執行 git bisect start
命令。Git 會將您帶到專案歷史中的第一次提交。
從這裡開始,您需要使用相關命令指出該提交是好是壞:
git bisect good git bisect bad
然後,Git 會將您轉到下一個提交,以測試其 “質量”。注意,您也可以用 “舊的” 替換 “好的”,用 “新的 “替換 “壞的”,以符合您的特定用例(但不能混用術語)。
從這裡開始,您可以繼續將每個提交標記為 “好” 或 “壞”,直到找到引入錯誤的提交。不過,您不必遍查每個提交–您可以指定確切的識別符號來幫助縮小搜尋範圍並縮短搜尋時間:
git bisect bad feature-test
這裡使用的是分支名稱,但也可以是使用整數、雜湊引用等的具體修訂版本。無論如何,一旦您找到錯誤,您可以執行以下命令之一來返回最新程式碼:
git bisect reset
與本列表中的所有 Git 高階命令一樣,還有很多內容需要消化,Git 文件將是必不可少的讀物。
10. 比較分支
我們在 “提交引用” 條目中提到了使用 git diff
。現在,是時候詳細瞭解一下了。您經常會發現自己的多個分支包含了不同的改動。Git 允許您使用 git diff
命令比較兩個分支之間的差異。事實上,您可以通過多種方式使用它,通常與其他命令一起使用,來調查和分析一個 repo。
基本的 git diff
命令會輸出變化概覽。它看起來很像提交合並調查的輸出:
顯示 git diff 請求的輸出。
不過,您還可以深入到精確的分支、雜湊值等等。例如,要比較兩個分支,您可以執行 git diff branch1..branch2
,然後替換佔位符:
git diff feature-branch pre-prod
您還可以比較當前分支與其他分支之間的差異:
git diff HEAD..pre-prod
請注意,這裡使用兩個點將返回兩個分支頂端之間的差值。相比之下,三個點將返回兩個分支的共同祖先之間的差異,並以此進行測試。
和 git log
一樣,您也可以清理輸出並細化其返回的內容。例如,git diff --name-only branch1..branch2
將只檢查哪些檔案不同,而省略上下文:
在終端執行 git diff -name-only 命令。
您可能會發現輸出很難解析,尤其是當 “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
“。首先,簽出您的分支…
git checkout trunk
……然後選擇您的提交:
git cherry-pick xxxxxaaaaaa
在很多情況下,您的提交資訊可能會過時。為了解決這個問題,你可以在命令中加入 --edit
選項。這將讓你在剔除之前提供一個新的提交資訊。
12. 給 “git add” 加點料
最後一個高階Git命令是 git add
。不,這不是個錯別字–這個最基本的 Git 命令有著驚人的力量。
舉例來說,如果您發現自己在快取區新增單個檔案,您可以使用下面的命令:
git add -p
通過 -p
選項,您可以在互動的基礎上對修改進行分期。 你可以檢視你對每個檔案所做的修改,然後選擇哪些需要暫存。這可以節省你大量的時間,幫助你避免不需要的修改。
雖然您可能知道可以對單個檔案進行暫存,但您也可以指定一個目錄。例如,暫存 ” new-feature
“目錄下的所有檔案:
git add new-feature
您甚至可能想在不執行完整過程的情況下檢視 git add
的結果。您可以選擇
git add --dry-run git add -n
執行後,Git會顯示是新增還是忽略這些檔案。說到忽略的檔案,你也可以把它們新增到暫存區:
git add --force git add -f
向暫存區域新增檔案可能比簡單的二進位制 “新增或不新增” 更復雜。因此,Git最核心的命令之一可以涵蓋無數種可能的情況。
小結
一旦掌握了基本的 Git 命令,您就擁有了執行專案常規版本控制任務所需的 80%的知識。然而,最後的20%才是高階Git命令大顯身手的地方。
重新排序、分段、恢復檔案等命令和技術都能讓您快速擺脫困境。更重要的是,你可以為團隊和專案提供更大的價值,幫助簡化工作流程,提高工作效率,全面提升開發者的能力。
這些高階Git命令會成為你日常工作的一部分嗎?請在下面的評論區告訴我們!
評論留言