Git 互動式變基指南,附實用範例

版本控制使用Git已成為現代開發者工具箱中的標配。像commitpushpull這樣的命令已經深入我們的肌肉記憶。但相對較少的開發者了解Git中的“更進階”功能——以及它們能帶來的巨大價值!在本文中,我們將探討“交互式變基”,這是Git中最強大的工具之一。

為何交互式變基應成為每位開發者的必備技能

簡而言之,毫不誇張地說,交互式變基能幫助你成為更好的開發者,通過允許你在項目中建立一個乾淨且結構良好的提交歷史。

為什麼結構良好的提交歷史很重要?試想一下相反的情況:一個難以閱讀的提交歷史,你無法得知同事實際上對他們最近的更改做了什麼。這樣的項目中會出現越來越多的“暗角”,你只能理解你自己工作的那一小部分。

對比之下,一個乾淨且結構良好的提交歷史:它有助於使項目的代碼庫更易讀更易理解。這是維持一個健康、長壽項目的關鍵要素!

交互式變基能為你做什麼

交互式變基幫助你優化和清理提交歷史。它涵蓋了多種不同的使用場景,其中一些允許你執行以下操作:

  • 編輯舊的提交信息
  • 刪除一個提交
  • 壓縮/合併多個提交
  • 重新排序提交
  • 修正舊有提交
  • 分割/重新開啟舊有提交以進行編輯

何時使用互動式變基(以及何時避免!)

與其他幾個Git工具類似,互動式變基會“重寫歷史”。這意味著,當你使用互動式變基操作一系列提交時,這部分的提交歷史將被重寫:提交的SHA-1雜湊值將會變更。可以說,它們是完全新的提交物件。

這一事實引出了一個簡單但重要的原則:不要對已經與遠端倉庫中的同事共享的提交使用互動式變基(或其他重寫歷史的工具)。相反,應該用它來清理你自己的本地提交——例如在你自己的功能分支中——在將它們合併到團隊分支之前。

互動式變基操作的基本機制

雖然互動式變基可以用於許多不同的目的,但基本工作流程始終相同。一旦你牢固掌握了這一基本機制,互動式變基將不再顯得“複雜神秘”,而會成為你工具箱中的一件寶貴且易於使用的工具。

步驟1:你應該從哪裡開始會話?

首先你需要回答的問題是:“我想要操作我的提交歷史的哪一部分?”這將告訴你應該從哪裡開始你的互動式變基會話。讓我們舉一個實際的例子,假設我們想要編輯一個舊的提交訊息(這正是我們接下來實際要做的)。

我們的起始情況如下圖所示,正在透過互動式變基修改一個舊的提交訊息。

為了能夠更改C2中的提交訊息,我們必須從其父提交(或更早之前,如果你願意)開始我們的互動式變基會話。在此範例中,我們將使用C1作為互動式變基會話的起始點。

步驟2:啟動實際會話!

啟動實際會話相當簡單:

$ git rebase -i HEAD~3

我們使用git rebase命令加上-i旗標(以表明我們確實希望它是“互動式”的),並提供基礎提交(即我們在第一步中確定的提交)。在此範例中,我使用了HEAD~3來指定“距離HEAD提交3個提交”的那個提交。或者,我也可以提供一個特定的SHA-1雜湊值。

步驟3:告訴Git你想做什麼

啟動互動式變基會話後,你將看到一個編輯器視窗,其中Git列出了一系列提交——從最新的提交一直到(但不包括)你在第一步中選擇的基礎提交。

在此步驟中有兩個重要事項需記住:

  1. 提交以反向順序列出!最新提交,我們預期會出現在頂部,將出現在列表的底部。別擔心:你的Git儲存庫狀態良好!🥳請記住,我們正在進行互動式變基操作,這要求Git在操作結束時從最舊到最新重新應用提交。
  2. 請勿在此編輯器視窗中進行實際更改! 儘管你可能急於直接在這個編輯器視窗中更改提交訊息(畢竟,那正是我們真正想要做的…),你必須展現一些耐心。在此,我們僅是告訴Git 我們想要做什麼 —— 但不是進行實際的更改。我很快就會在實踐中展示這一點!

在理論概述結束後,讓我們一起深入探討一些實際案例!

編輯舊提交訊息

互動式變基的一個非常受歡迎的使用案例是,你可以在事後編輯舊的提交訊息。你可能已經知道git commit --amend也允許你更改提交的訊息 —— 但僅限於最新的提交。對於任何比那更舊的提交,我們必須使用互動式變基!

讓我們來看一個具體的場景。下面是一張需要更正的糟糕提交訊息的圖片。

注意:為了更好的概覽和更清晰的視覺化,我在一些截圖中使用了Tower Git桌面客戶端。你不需要Tower來跟隨本教程。

在我們的例子中,假設我們想要編輯目前標題為“優化索引中的標記結構…”的提交訊息。

我們的第一步是確定此次互動式變基會話的起始基準提交。由於我們至少需要回溯到我們的“不良提交”的父提交,因此我們從HEAD~3(即HEAD提交往前數第三個提交,該提交標題為“更改標題…”)開始我們的會話:

$ git rebase -i HEAD~3

執行此命令後,您喜愛的編輯器將會開啟並展示您剛剛選擇的提交列表(透過提供基準提交)。

提醒一下:儘管您可能會想這麼做,但在這裡我們修改提交訊息。我們僅標記相應行並添加一個“操作關鍵字”。以我們的情況,我們想要reword該提交(意味著我們希望更改提交訊息,但保持提交的其他部分不變)。

非常實用地,所有可用的操作關鍵字都記錄在此視窗底部——因此無需死記硬背任何東西!

一旦您將標準的pick關鍵字(意為“按原樣接受提交”)替換為您偏好的操作關鍵字後,您只需保存並關閉視窗即可。

完成後,將會開啟一個新的編輯器視窗,其中包含當前的提交訊息。最終,我們得以進行最初設定的操作:編輯這個舊提交的訊息!

在做出更改並保存及關閉編輯器視窗後,互動式變基會話即告完成——而我們的提交訊息也已更新!🎉

刪除不需要的提交

互動式 rebase 還允許您刪除不再需要(或不想要)的舊提交。試想一下,如果您不小心在最近的提交中包含了個人密碼:像這樣的敏感資訊,在大多數情況下,不應該包含在代碼庫中。

還要記住,僅僅刪除資訊並再次提交並不能真正解決您的問題:這意味著密碼仍然以舊提交的形式保存在倉庫中。您真正想要的是徹底且乾淨地刪除這部分數據!

首先,我們需要確定互動式 rebase 會話的基礎提交。由於我們至少需要從錯誤提交的父提交開始,我們使用“優化標記結構…”提交作為基礎:

$ git rebase -i 6bcf266b

注意,這次我在git rebase -i命令中使用了具體的 SHA-1 雜湊。當然,我也可以使用HEAD~2來指向那個提交。

執行此命令後,我們再次看到一個提交列表。

這次,我們使用drop操作關鍵字來擺脫不需要的提交。或者,在這種特殊情況下,我們也可以直接從編輯器中刪除整行。如果在保存並關閉窗口時某行(代表一個提交)不再存在,Git 將刪除相應的提交。

無論您選擇哪種方式,在您保存並關閉編輯器窗口後,該提交將從您的倉庫歷史中刪除!

將多個提交合併為一個

另一個使用互動式rebase的情境是,當你想要合併多個獨立的提交成為單一提交時。在深入探討如何操作之前,讓我們先花點時間討論何時為何這樣做可能具有價值。

一般來說,透過合併多個提交來「放大」提交,在大多數情況下並不是一個好策略。通常的經驗法則是盡可能保持提交的小巧,因為「小」意味著「更容易閱讀和理解」。但在某些情況下,這樣做仍然有其意義。以下是兩個例子:

  • 想像你發現了一個較舊提交中的問題。你可能會繼續創建一個新的提交來修復這個問題。在這種情況下,能夠將這些提交合併成單一提交非常有意義:畢竟,新的提交只是一個「創可貼」,用來修復原本不應存在的問題。通過合併這些提交,看起來問題從未存在過!

  • 另一個例子是,當你注意到你的提交過於。雖然小提交很好,但如果將提交歷史充斥著大量不必要的小提交,則意味著過度細分。

兩個例子背後的邏輯相同:通過合併兩個(或多個)原本應該是單一提交的提交,你正在創建一個更乾淨、更易讀的提交歷史!

讓我們一起通過一個實際的例子來了解,以下圖所示的情況作為我們的起始情況。

假設從語義上來看,將這兩個提交合併為一個更為合理。利用互動式變基的squash工具,我們確實可以將它們結合起來:

$ git rebase -i HEAD~3

到目前為止,你應該已經習慣接下來會發生的事情:一個編輯器視窗打開,顯示一系列提交。

I already mentioned that we’re going to use the squash action keyword in this case. There’s an important thing to know about how squash works: the line you mark up with the keyword will be combined with the line directly above! This explains why I marked line 2 with the squash keyword in our example.

保存並關閉此視窗後,另一個視窗將會打開。這是因為,當我們合併多個提交時,自然會創建一個新的提交。而這個新提交也需要一條提交訊息,就像其他任何提交一樣!

在上面的截圖中,Git為我們準備了以下內容:它將原始提交的提交訊息合併在一起,並附帶了一些註釋。你可以自由刪除舊訊息並重新開始,或者保留它們並添加更多資訊。

保存並關閉此編輯器視窗後,我們可以自豪地宣稱:原本的兩個獨立提交現已合併為一個!

掌握互動式變基的力量

I hope you agree that Git’s interactive rebase tools can be very valuable! As developers, it’s important for us to strive for a clean and clear commit history. It’s a crucial ingredient in keeping a codebase healthy and easy to understand (both for your teammates, and yourself, after some time has passed).

如果你想了解更多,我強烈推薦“Git急救包”。這是一系列免費的短視頻,展示如何清理Git中的錯誤並撤銷操作。

玩得開心!

關於Git互動式變基的常見問題(FAQs)

Git Rebase和Git Merge之間有何區別?

Git Rebase 與 Git Merge 是將一個分支的變更整合到另一個分支的兩種不同方式。Git Merge 是一種直接的方式來合併來自兩個不同分支的程式碼。它在歷史記錄中創建一個新提交,保留提交的時間順序。另一方面,Git Rebase 是一種移動或合併一系列提交到新的基礎提交的方法。這就像說“我想基於大家已經完成的內容來進行我的更改。”換句話說,它允許你將當前分支的更改放置在另一個分支之上。

如何撤銷 Git Rebase?

如果你想撤銷 Git Rebase,可以使用命令 git reflog 找到你想要返回的提交,然後使用命令 git reset --hard HEAD@{number}git reflog 命令顯示對 HEAD 進行的每一個更改的列表,而 git reset 命令允許你將當前 HEAD 設置為指定的狀態。

Git Interactive Rebase 的目的是什麼?

Git Interactive Rebase 允許你以多種方式更改提交,如編輯、刪除和壓縮。你不僅可以更改提交信息,還可以更改實際的程式碼,如果你犯了錯誤。它是一個強大的工具,給你對項目提交歷史的完全控制。

如何使用 Git Interactive Rebase 壓縮提交?

壓縮是將多個提交合併為一個的行為。在Git中,您可以使用git rebase -i命令後跟您想要壓縮的提交哈希來壓縮提交。在打開的文本編輯器中,您可以通過將pick替換為squashs來標記您想要壓縮的每個提交。

使用Git互動式變基有哪些風險?

儘管Git互動式變基是一個強大的工具,但如果使用不當,它可能會很危險。它重寫提交歷史,如果您正在處理其他人也在工作的公共分支,這可能會引起問題。建議在尚未推送的本地分支上使用它。

在Git變基期間如何解決衝突?

在變基過程中,可能會發生衝突。Git將暫停並允許您在繼續之前解決這些衝突。您可以通過編輯文件來修復衝突的更改,然後使用git add添加已解決的文件。在解決所有衝突後,您可以使用git rebase --continue繼續變基。

我可以用Git互動式變基來分割提交嗎?

是的,您可以使用Git互動式變基將一個提交分割成更小的提交。如果您在一個提交中進行了多個更改,但後來決定它們應該是單獨的提交,這可能會很有用。

如何使用Git互動式變基編輯提交消息?

在進行互動式變基時,您可以編輯提交訊息。在提交列表中,將您想要編輯的提交旁邊的 `pick` 替換為 `reword` 或 `r`。當您繼續時,Git 將為每個標記為 `reword` 的提交打開一個文字編輯器,允許您更改提交訊息。

Git Rebase 和 Git Pull 之間有何區別?

Git Pull 是一個命令,它從遠端倉庫獲取更改並將其合併到您當前的分支中。另一方面,Git Rebase 是一個命令,它將一系列提交移動或合併到一個新的基礎提交。雖然這兩個命令都用於整合更改,但它們以不同的方式進行。

我能否使用 Git 互動式變基來更改提交的順序?

是的,您可以使用 Git 互動式變基來更改提交的順序。在提交列表中,您只需更改行的順序即可更改提交的順序。如果您希望使提交歷史更具邏輯性或清晰,這可能會很有用。

Source:
https://www.sitepoint.com/git-interactive-rebase-guide/