1. 程式人生 > >git rebase VS git merge? 更優雅的 git 合併方式值得擁有

git rebase VS git merge? 更優雅的 git 合併方式值得擁有

寫在前面

如果你不能很好的應用 Git,那麼這裡為你提供一個非常棒的 Git 線上練習工具 Git Online(回覆公眾號「工具」,獲取更多內容) ,你可以更直觀的看到你所使用的命令會產生什麼效果

另外,你在使用 Git 合併分支時只會使用 git merge 嗎?有時使用 git rebase 可以比 git merge 做出更優雅的操作
- - - - -

Merge 與 Rebase

不知怎麼,git rebase 命令被賦予了一個神奇的汙毒聲譽,初學者應該遠離它,但它實際上可以讓開發團隊在使用時更加輕鬆。

你可以將它理解成「七傷拳」,「七傷拳」並不是不能練,只是練「七傷拳」有一個先訣條件,那就是內功境界一定要非常高,即你要充分理解 git rebase

命令

在本文中,我們將 git rebasegit merge 命令進行比較。在 Git 工作流中,說明所有可以使用 rebase 的場景

概念概述

關於 git rebase ,首先要理解的是它解決了和 git merge 同樣的問題。這兩個命令都旨在將更改從一個分支合併到另一個分支,但二者的合併方式卻有很大的不同。

當你在專用分支上開發新 feature 時,然後另一個團隊成員在 master 分支提交了新的 commits,這會發生什麼?這會導致分叉的歷史記錄,對於這個問題,使用 Git 作為協作工具的任何人來說都應該很熟悉。

現在,假設在 master 分支上的新提交與你正在開發的 feature 相關。需要將新提交合併到你的 feature

分支中,你可以有兩個選擇:merge 或者 rebase。

Merge 方式

最簡單的方式是通過以下命令將 master 分支合併到 feature 分支中:

git checkout feature
git merge master

或者,你可以將其濃縮為一行命令:

git merge feature master

這會在 feature 分支中建立一個新的 merge commit,它將兩個分支的歷史聯絡在一起,請看如下所示的分支結構:

使用 merge 是很好的方式,因為它是一種 非破壞性的 操作。現有分支不會以任何方式被更改。這避免了 rebase 操作所產生的潛在缺陷(下面討論)。

另一方面,這也意味著 feature 分支每次需要合併上游更改時,它都將產生一個額外的合併提交。如果master 提交非常活躍,這可能會嚴重汙染你的 feature 分支歷史記錄。儘管可以使用高階選項 git log 緩解此問題,但它可能使其他開發人員難以理解專案的歷史記錄

Rebase 方式

作為 merge 的替代方法,你可以使用以下命令將 master 分支合併到 feature分支上:

git checkout feature
git rebase master

這會將整個 feature 分支移動到 master 分支的頂端,從而有效地整合了所有 master 分支上的提交。但是,與 merge 提交方式不同,rebase 通過為原始分支中的每個提交建立全新的 commits 來 重寫 專案歷史記錄。

rebase 的主要好處是可以獲得更清晰的專案歷史。首先,它消除了 git merge 所需的不必要的合併提交;其次,正如你在上圖中所看到的,rebase 會產生完美線性的專案歷史記錄,你可以在 feature分支上沒有任何分叉的情況下一直追尋到專案的初始提交。這樣可以通過命令 git loggit bisectgitk 更容易導航檢視專案。

但是,針對這樣的提交歷史我們需要權衡其「安全性」和「可追溯性」。如果你不遵循 Rebase 的黃金法則,重寫專案歷史記錄可能會對你的協作工作流程造成災難性後果。而且,rebase 會丟失合併提交的上下文, 你也就無法看到上游更改是何時合併到 feature 中的。

互動式 Rebase

互動式 rebase 使你有機會在將 commits 移動到新分支時更改這些 commits。這比自動 rebase 更強大,因為它提供了對分支提交歷史的完全控制。通常,這用於在合併 feature 分支到 master 之前清理其雜亂的歷史記錄。

要使用互動式 rebase,需要使用 git rebase-i 選項:

git checkout feature
git rebase -i master

這將開啟一個文字編輯器,列出即將移動的所有提交:

pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

此列表準確定義了執行 rebase 後分支的外觀。通過更改 pick 命令或重新排序條目,你可以使分支的歷史記錄看起來像你想要的任何內容。例如,如果第二次提交 fix 了第一次提交中的一個小問題,您可以使用以下 fixup 命令將它們濃縮為一個提交:

pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

儲存並關閉檔案時,Git將根據您的指示執行 rebase,從而產生如下所示的專案歷史記錄:

消除這種無意義的提交使你的功能歷史更容易理解。這是 git merge 根本無法做到的事情。至於 commits 條目前的 pickfixupsquash 等命令,在 git 目錄執行 git rebase -i 即可檢視到,大家按需重排或合併提交即可,註釋說明非常清晰,在此不做過多說明:

Rebase 的黃金法則

一旦你理解了什麼是 rebase,最重要的是要學習什麼時候不能使用它。git rebase 的黃金法則是永遠不要在公共分支上使用它。

例如,想想如果你 rebase master 分支到 feature 分支之上會發生什麼:

rebase 將所有 master 分支上的提交移動 feature 分支的頂端。問題是這隻發生在 你自己 的儲存庫中。所有其他開發人員仍在使用原始版本的 master。由於 rebase 導致全新 commit,Git 會認為你的 master 分支歷史與其他人的歷史不同。

此時,同步兩個 master 分支的唯一方法是將它們合併在一起,但是這樣會產生額外的合併提交和兩組包含相同更改的提交(原始提交和通過 rebase 更改的分支提交)。不用說,這是一個令人非常困惑的情況。

因此,在你執行 git rebase 命令之前,總是問自己,還有其他人在用這個分支嗎? 如果答案是肯定的,那就把你的手從鍵盤上移開,開始考慮採用非破壞性的方式進行改變(例如,git revert 命令)。否則,你可以隨心所欲地重寫歷史記錄。

Force Push

如果你嘗試將 rebase 了的 master 分支推送回 remote repository,Git 將阻止你這樣做,因為它會與遠端master 分支衝突。但是,你可以通過傳遞 --force 標誌來強制推送,如下所示:

# Be very careful with this command!
git push --force

這樣你自己 repository 的內容將覆蓋遠端 master分支的內容,但這會使團隊的其他成員感到困惑。因此,只有在確切知道自己在做什麼時才要非常小心地使用此命令。

如果沒有人在 feature branch 上作出更改,你可以使用 force push 將本地內容推送到 remote repository 做清理工作

工作流程演練

rebase 可以根據你所在團隊的需要方便的整合到現有的 Git 工作流程中。在本節中,我們將瞭解 rebase 在功能開發的各個階段可以提供的好處。

在任何工作流程中,利用 git rebase 是為每個功能建立專用分支。這為你提供了必要的分支,以安全地利用 rebase:

本地清理

將 rebase 納入工作流程的最佳方法之一是清理本地正在進行的功能。通過定期執行互動式 rebase,你可以確保功能中的每個提交都具有針對性和意義。這可以使你在編寫程式碼時無需擔心將其分解為隔離的提交(多個提交),你可以在事後修復整合它。

使用 git rebase 時,有兩種情況:feature 父分支(例如 master )的提交,或在 feature 中的早期提交。我們在 互動式 Rebase 部分已經介紹了第一種情況的示例。我們來看後一種情況,當你只需要修復最後幾次提交時,以下命令僅做最後 3 次提交的互動式 rebase。

git checkout feature
git rebase -i HEAD~3

通過指定 HEAD~3 ,你實際上並沒有移動分支,你只是互動式地重寫其後的3個提交。請注意,這不會將上游更改合併到 feature 分支中。

如果要使用此方法重寫整個功能,git merge-base 命令可用於查詢 feature 分支的原始 base。以下內容返回原始 base 的提交ID,然後你可以將其傳遞給 git rebase

git merge-base feature master

互動式 rebase 的使用是引入git rebase 工作流的好方法,因為它隻影響本地分支。其他開發人員唯一能看到的就是你提交的最終版,這應該是一個簡潔易懂易跟蹤的分支歷史記錄。

但同樣,這僅適用於 私有 feature分支。如果你通過相同的功能分支(公共分支)與其他開發人員協作,那麼你是 不被允許 重寫其歷史記錄的。

將上游更改合併到功能分支中

在 概念概述 部分中,我們瞭解了 feature 分支可以使用 git mergegit rebase 合併 master 分支的上游更改 。merge 是一個安全的方式,可以保留存 git repository 的整個歷史記錄,而 rebase 則是通過將 feature 分支移動到 master 頂端來建立線性歷史記錄。

這種使用 git rebase 類似於本地清理,但在此過程中它包含了那些來自 master 上游提交。

請記住,將當前提交 rebase 到遠端 branch(非 master 分支)一樣是合法的。當與另一個開發人員協作使用相同的功能並且你需要將他們的更改合併到你的 repository 時,就會發生這種情況。

例如,如果你和另一個名為 John 的開發人員添加了對 feature 分支的提交,在你 fetch (注意 fetch 並不會自動 merge )來自 John 的遠端 feature分支後,你的 repository 可能如下所示:

你可以整合上來自上游的分叉:要麼用 john/feature merge 本地 feature ,要麼 rebase 本地featurejohn/feature 的頂部。

請注意,此 rebase 不違反 Rebase 黃金規則,因為只有你的本地 feature 提交被移動, 之前的所有內容都不會受到影響。這就像是說 "將我的更改新增到 John 已經完成的工作中"。在大多數情況下,這比通過合併提交與遠端分支同步更直觀。

預設情況下,使用 git pull 命令執行合併,但你可以通過向其傳遞 --rebase 選項來強制它將遠端分支 以 rebase 方式整合。

git pull --rebase

使用 Pull 請求 Review Feature

如果你在程式碼審查過程中使用 pull 請求,在使用了 pull 請求之後你應該避免使用 git rebase 。一旦你發出 pull 請求,其他開發人員就會檢視你的提交,這意味著它是一個 公共 分支。重寫其歷史記錄將使 Git 和你的隊友無法跟蹤新增到該功能的任何後續提交。

其他開發人員的任何更改都需要合併 git merge 而不是 git rebase

因此,在提交拉取請求之前,通常使用互動式 rebase 清理程式碼通常是個好的辦法。注意使用順序

整合已批准的功能

在你的團隊批准某項 feature 後,你可以選擇將該功能 rebase 到 master 分支的頂端,然後git merge再將該功能整合到主程式碼庫中。

這與將上游更改合併到 feature 分支中的情況類似,但由於你不允許在 master 分支中重寫提交,因此你必須最終使用 git merge 該功能進行整合。但是,通過在 merge 之前執行 rebase,你可以確保會以 fast-forward 方式 merge,從而產生完美的線性歷史記錄。

如果您不熟悉 git rebase,可以隨時在臨時分支中執行 rebase。這樣,如果你不小心弄亂了功能的歷史記錄,可以檢視原始分支,然後重試。例如:

git checkout feature
git checkout -b temporary-branch
git rebase -i master
# [Clean up the history]
git checkout master
git merge temporary-branch

總結

如果你更喜歡沒有不必要的乾淨的合併提交,線性歷史記錄,你就需要開始瞭解使用 rebase 功能。同時你應該會使用 git rebase 而不是 git merge 整合來自另一個分支的更改。

另一方面,如果你想保留專案的完整歷史記錄並避免重寫公共提交的風險,你可以堅持下去git merge。這兩種選擇都是完全有效的,但至少現在你可以選擇利用 git rebase 的好處 。

靈魂追問

  1. 你有使用過 git rebase 嗎?這樣清晰的線形歷史是不是可以嘗試一下呢?
  2. 互動式 rebase 提交條目前的命令 fixup 等你能靈活使用嗎
  3. 在 feature 分支上開發時,試試 git pull -rebase?

帶著疑問去思考,然後串聯,進而歸納總結,不斷追問自己,進行自我辯證,像偵查嫌疑案件一樣看待技術問題,漆黑的街道,你我一起尋找線索,你就是技術界大偵探福爾摩斯


提高效率工具


推薦閱讀

  • 面試還不知道 BeanFactory 和 ApplicationContext 的區別?
  • Spring Bean 生命週期之"我從哪裡來?",懂得這個很重要
  • 雙親委派模型,大廠高頻面試題,你值得擁有
  • 如何設計好的RESTful API
  • 輕鬆高效玩轉DTO(Data Transfer Object)

歡迎持續關注公眾號:「日拱一兵」

  • 前沿 Java 技術乾貨分享
  • 高效工具彙總
  • 面試問題分析與解答
  • 技術資料領取

持續關注,帶你像讀偵探小說一樣輕鬆趣味學習 Java 技術棧相關知識

相關推薦

git rebase VS git merge優雅git 合併方式值得擁有

寫在前面 如果你不能很好的應用 Git,那麼這裡為你提供一個非常棒的 Git 線上練習工具 Git Online(回覆公眾號「工具」,獲取更多內容) ,你可以更直觀的看到你所使用的命令會產生什麼效果 另外,你在使用 Git 合併分支時只會使用 git merge 嗎?有時使用 git rebase 可以比

Getting solid at Git rebase vs. merge

TL;DRA git merge should only be used for incorporating the entire feature set of branch into another one, in order to preserve a useful, semantically corre

詳解git rebase,讓你走上git大神之路

在之前的文章當中我們介紹了git merge的用法,明白了通過git merge我們可以合併兩個分支的改動。這樣我們就可以很方便地進行協同開發了,每個人都在自己的分支下開發程式碼,開發完畢之後再一起合併到master分支。通過這種方式可以保證大家的程式碼不會陷入混亂,但是這樣有一個隱含的缺陷。 缺陷就是我們之

VS配色方案 以及KEIL配色方案你值得擁有

以下是KEIL的配色方案: 長這樣 下面是VS的配色方案(有一個我好喜歡的,嗯,但是我忘了是哪一個,自己試試吧): 連結:https://pan.baidu.com/s/1OBaW__wBOt6pynMGmRKqZQ 密碼:smh1 如下:

優雅的使用Git

JavaScript之禪已經發過兩篇 Git 相關的文章了。一篇文章,教你學會Git :淺顯易懂,如果你還不會 Git 可以先去看看、Git的奇技淫巧 :介紹了一些實用的操作。今天為大家帶來第三篇,如何更優雅的使用 Git 寫好 commit message Git 每次提交程式碼,都要寫 Commit

git rebasegit merge 的區別

git rebase 和 git merge 的區別  AlvinStar 關注 2016.07.31 17:32* 字數 760 閱讀 14895評論 6喜歡 28讚賞 1 Description git rebase 和 git merge

git mergegit rebase 區別

git merge是用來合併兩個分支的。 git merge b       # 將b分支合併到當前分支 同樣 git rebase b,也是把 b分支合併到當前分支 ----------------------------------- 他們的 原理 如下:

git mergegit rebase的區別

err .com 圖片 master 工具 技術分享 根據 git fetch net 前言其實這個問題困擾我有一段時間,相信也有人和我一樣有這個困擾,網上已有很多這種解釋了,但是要麽就是無圖,要麽就是解釋的很亂,沒太看懂,經過自己對git的使用,加上向同事請教,算是理解了

git rebasegit merge區別

使用下面的關係區別這兩個操作: git pull = git fetch + git merge git pull --rebase = git fetch + git rebase 現在來看看git merge和git rebase的區別。 假設有3次提交A,B,C。 在遠端分支

git mergegit rebase 小結

git merge是用來合併兩個分支的。 git merge b       # 將b分支合併到當前分支 同樣 git rebase b,也是把 b分支合併到當前分支 -------------

Git詳解——不喜歡 merge 的分叉?用 rebase

有些人不喜歡 merge ,因為在 merge 之後, commit 歷史就會出現分叉,這種分叉再匯合的結構會 讓有些人覺得混亂而難以管理。如果你不希望 commit 歷史出現分叉,可以用 rebase 來代替 merge 。   rebase——在新位置重新提交 rebase ,又是一箇中國

同樣是合併git mergegit rebase有什麼區別?

參考部落格 [1]https://www.cnblogs.com/marblemm/p/7161614.html [2]https://blog.csdn.net/liuxiaoheng1992/article/details/79108233 [3]https://blog.csd

git rebase & merge 將其他分支的修改合併到當前分支

例如現在有兩個分支 master 和 feature, 你在 feature 分支上進行了實驗,這時候有個另外的人在 master 分支上進行了新的提交。那麼你需要將 master上別人的修改應用到 feature 分支上。 方法1: merge git c

git 常用命令(git rebasegit merge 什麼時候使用)

更新所有遠端分支git remote update origin --prune或者git fetch賦值程式碼到本地git clone [email protected]:wild46cat/test.gitgit rebase 過程git rebase orig

git mergegit rebase的區別(轉)

Description git rebase 和 git merge 一樣都是用於從一個分支獲取並且合併到當前分支,但是他們採取不同的工作方式,以下面的一個工作場景說明其區別 場景: 如圖所示:你在一個feature分支進行新特性的開發,與此同時,ma

git rebasemerge 的那些事兒~(詳細圖解,通俗易懂)

什麼是 rebase? git rebase 你其實可以把它理解成是“重新設定基線”,將你的當前分支重新設定開始點。這個時候才能知道你當前分支於你需要比較的分支之間的差異。 原理很簡單:rebase 需要基於一個分支來設定你當前的分支的基線,這基線就是當前分支的開始時間軸向後移動到最新的跟蹤分支的最後面,這

Windows下快速安裝Xgboost(無需Git或者VS

nor port 最終 比賽 http 無需 windows git 到你 xgboost的全稱是eXtreme Gradient Boosting,現在已經風靡Kaggle、天池、DataCastle、Kesci等國內外數據競賽平臺,是比賽奪冠的必備大殺器!如果

git常用命令2--- git rebase

過程 checkout nbsp 常用 check mit 另一個 ups pst git rebase:簡單而言就是把某個分支上的提交commit嫁接到另一個commit的後面,在這個過程中這些commit的base相對就改變了,也就叫變基。 git rebase <

git rebase

ror mes staging eba 表示 clas his top rop 1 noop 2 3 # Rebase 3bb2bfb..3bb2bfb onto 3bb2bfb (1 command) 4 # 5 # Commands:

git rebase 的使用

還需 覆蓋 分支 .com 重新 客戶端 dia 從服務器 你們 rebase 在 Git 中整合來自不同分支的修改主要有兩種方法:merge 以及 rebase。 在本節中我們將學習什麽是“rebase”,怎樣使用“rebase”,並將展示該操作的驚艷之處,以及指出在