優秀 !華爲是這樣使用Git rebase的

世界上最快的捷徑,就是腳踏實地,本文已收錄【 架構技術專欄】關注這個喜歡分享的地方。

引言

使用git參與多人之間的合做開發大概有三年的時間,大多數場景下使用的git命令一隻手多一點就能數的過來git

  • git add
  • git commit
  • git push
  • git merge
  • git pull
  • git log

理論上來講,只要能合理管理項目分支,這幾個命令已經足以應付全部的平常開發工做。可是若是咱們偶爾看一下本身的git graph,個人天吶,爲何會這麼亂。vim

鑑於分支管理的混亂(或者根本就沒有進行過度支管理),咱們常常遇到一些意想不到的問題,所以須要使用不少面生的git命令來解決咱們的問題,好比說本文講到的git rebase。架構

git rebase 和 git merge 區別

Git rebase 的中文名是變基,就是改變一次提交記錄的base。在這一環節,咱們不妨帶着這樣一個假設:git rebase ≈ git merge,並用兩種命令實現同一工做流來對比他們之間的異同。fetch

回想咱們平常的工做流,假設a和b兩人合做開發,三個分支:develop, develop_a, develop_b。兩我的分別在develop_a和develop_b分支上進行平常開發,階段性地合入到develop。ui

那麼從a的角度來看,可能的工做流是這樣的:spa

(1)我的在develop_a分支上開發本身的功能code

(2)在這期間其餘人可能不斷向develop合入新特性blog

(3)我的功能開發完畢後經過merge 的方式合入別人開發的功能開發

git merge

<img src="https://imgkr2.cn-bj.ufileos.com/8cc6cb08-2204-41f3-81fd-7ed6fdfe93c4.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=m4aOEBDAYY81ui7sIjaOojyXJro%253D&Expires=1604394415" alt="img" style="zoom:50%;" />rem

上圖爲平常merge 工做流,對應的git操做命令以下:

git checkout develop_a

// 本地功能開發...

git pull origin develop = git fetch origin develop + git merge develop複製代碼
git rebase

一樣走完這樣一個工做流若是咱們使用git rebase來實現,結果以下:

git rebase 以前,如圖:

<img src="https://imgkr2.cn-bj.ufileos.com/b91971db-ef92-42b1-98d9-c06bd36bc3c6.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=JwrW9r03NwUSfrGx1COB7atRCqI%253D&Expires=1604394434" alt="img" style="zoom:50%;" />

git rebase 之中,如圖:

<img src="https://imgkr2.cn-bj.ufileos.com/cb7eb279-95f0-4218-8e15-0ece04b1613f.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=nQx3CttQG6lmgb6qDWdNfRslDxc%253D&Expires=1604394450" alt="img" style="zoom:50%;" />

git rebase 以後,如圖:

<img src="https://imgkr2.cn-bj.ufileos.com/59051a0d-342d-4822-bac3-47ebb2e68705.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=w1hLSzuKVFjY71xauONfva%252F4qDg%253D&Expires=1604394465" alt="img" style="zoom:50%;" />

git rebase 操做對應命令以下:

git checkout develop_a

// 本地功能開發...

git fetch origin develop

git rebase develop

git checkout develop

git merge develop_a

git br -d develop_a 複製代碼

因而可知,git rebase 和git merge的異同之處以下:

(1)二者均可以用於本地代碼合併

(2)git merge 保留真實的用戶提交記錄,且在merge時會生成一個新的提交

(3)git rebase 會改寫歷史提交記錄,這裏的改寫不只限於樹的結構,樹上的節點的commit id也會別改寫,所以圖3和圖4用e'表明圖2的e',收益是能夠保證提交記錄很是清爽

如何使用git rebase -i 修改歷史提交記錄

git rebase -i,中文名叫交互式變基。意思就是在變基的過程當中是能夠摻入用戶交互的,經過交互過程咱們能夠主動改寫歷史提交記錄,包括修改、合併和刪除等。咱們以上面使用rebase後獲得的提交記錄爲例,來進行歷史提交記錄的修改,在修改以前,提交記錄是這個樣子的。

img

使用git rebase -i 修改歷史提交的過程主要包含三步:

(1)列出一個提交記錄的範圍,並指出你在這個範圍內須要對哪些記錄進行什麼樣的修改

(2)以次執行上述的修改,若是遇到衝突須要解決

(3)完成rebase 操做

以上面截圖中的提交記錄爲例,來對歷史提交的commit msg進行修改,操做步驟以下:

// 查看最近6次提交記錄,選擇對哪一條記錄進行修改

git rebase -i HEAD~6複製代碼

img

執行完上述命令後,會以vim的方式打開一個文件,文件中顯示了最近6次的提交信息,從上到下,由遠到近。

從下面的註釋能夠看到,咱們分別把每一行前面的pick修改爲r, s, d的方式就能夠實現對歷史記錄的修改,合併和刪除。

首先咱們嘗試修改提交信息,把第二行前面的pick改爲r,保存退出。當前頁面關閉的同時會打開一個新的頁面,讓你對選中的提交信息進行編輯。

img

編輯完信息以後保存退出,就完成了對歷史提交記錄的修改。經過觀察下圖能夠發現,develop_a的提交記錄中的commit msg 仍然是feat_c,可是develop 分支中對應的提交記錄,commit msg 已經變成了feat: c-update.。

這裏須要留意到的一個現象是develop 和develop_a 分支上相同提交的commit id 已經發生了變化,這個在後面會再次提到。

img

除了修改提交的commit msg 以外,咱們也能夠經過把pick 改成e,結合git reset --soft HEAD^ 的方式對檔次提交的改動內容進行修改。

合併與刪除歷史提交的操做步驟與編輯相似,只須要把pick分別改成s 和d 便可,各位看官能夠自行嘗試。若是在rebase的過程當中遇到了衝突,須要手工解決,而後使用git rebase --continue 完成rebase 操做。

git rebase 的提示仍是很是友好的,它會告訴你須要進行哪些操做解決當前的問題。

img

使用git rebase -i 必須遵循的規則是什麼?

從修改歷史提交記錄這個功能來看,交互式變基是一個很是強大的功能。可是使用這個功能必需要遵循一個鐵則:不要對線上分支的提交記錄進行變基!

引用git 官方指導文檔的話來講大概是這樣:

若是你遵循這條金科玉律,就不會出差錯。 不然,人民羣衆會仇恨你,你的朋友和家人也會嘲笑你,唾棄你。

在說爲何不能對線上提交執行交互式變基以前,先說一下若是要對線上功能執行這個操做要怎麼作。

首先,你須要在本身本地變基成功,而後使用git push -f 強行push 並覆蓋遠程對應分支,之因此須要執行覆蓋式push 是由於若是你不覆蓋,當前變基事後產生的新提交會與遠程合併,致使你在本地的變基行爲失去意義。

由於咱們上面提到過,從變基那個節點開始日後的全部節點的commit id 都會發生變化。

一樣的緣由,即便你使用git push -f 使遠程分支發生了變基,若是你的同事的開發分支中還存在你執行變基操做(不管是修改、合併仍是刪除)時針對的那些分支,那麼當你的同事merge 你的提交以後,你全部想使用變基改變的東西都回來了!

若是打破了git rebase -i 的使用規則應該如何補救

此處咱們嘗試經過要點描述的方式,說明線上提交執行變基會致使什麼結果以及如何避免這個結果:

(1)你在本地對部分線上提交進行了變基,這部分提交咱們稱之爲a,a在變基以後commit id 發生了變化

(2)你在本地改變的這些提交有可能存在於你的同事的開發分支中,咱們稱之爲b,他們與a的內容相同,commit id 不一樣

(3)若是你把變基結果強行push 到遠程倉庫後,你的同事在本地執行git pull 的時候會致使a 和b 發生融合,且都出如今了歷史提交中,致使你的變基行爲無效

(4)咱們想要的是你的同事拉取線上代碼時跳過對a 和b 的合併,只是把他本地分支上新增的修改合併進來

講了這麼多,最終的結論就是,使用變基解決變基帶來的問題。即你的同事使用git rebase 的方式把他本地的修改rebase 到遠程你執行過rebase 的分支上。

簡言之,就是你的同事使用git pull --rebase 而不是git pull 來拉取遠程分支。在這個操做的過程當中,git 會對咱們上面提到幾個要點的信息進行檢查並把真正屬於同事本地的修改合入遠程分支的最後。

文字描述可能有些乏力,更多詳細信息能夠參考這裏:git-scm.com/book/zh/v2/…

因此咱們應該如何使用git rebase

鑑於上面描述的git rebase 可能帶來的問題,最後要回答的一個問題是咱們應該如何在平常工做中使用git rebase,一樣借用git 官方文檔中的一句話:

總的原則是,只對還沒有推送或分享給別人的本地修改執行變基操做清理歷史, 從不對已推送至別處的提交執行變基操做,這樣,你才能享受到兩種方式(rebase 和merge)帶來的便利。

原文地址:https://www.mdeditor.tw/pl/pMHD

做者:DevUI 華爲團隊

相關文章
相關標籤/搜索