git rebase 使用詳解

背景

在你看這篇文章之前,我假設你已經至少會git的一些基本指令,能進行簡單的 git repo 的操作。比如:pull, add, commit, merge, push 等幾個基礎命令至少會用。而我們剛開始接觸 git 的時候,會這些簡單的指令能滿足基本的 git 代碼的開發與提交。

但是當你把 git 作爲一個常用的工具之後,還是需要了解一些相對進階的常用指令。而這篇文章我們來講講進階命令git rebase

理解 Rebase 命令

git rebase 命令的文檔描述是:

Reapply commits on top of another base tip

從字面上理解是在另一個基端之上重新應用提交,這個定義聽起來有點抽象,換個角度可以理解爲將分支的基礎從一個提交改成另一個提交,使其看起來就像是從另一個提交中創建了分支一樣

下面我來詳細講解一下git rebase命令最常用的兩個用法,讓大家更深入的理解 在另一個基端之上重新應用提交 的概念。

Rebase 常用的兩個使用場景是:

• 合併 commit 記錄 • 合併分支(重寫提交歷史)

一、合併 commit 記錄

有時候開發一個 feature 的時候,在自己的 feature 分支有過多次修改記錄,多的時候有好幾十次。每次都進行了一些小的修改。這麼多 commit 看起來很不舒服,而且如果合併到 master,導入了過多的 commit,導致充滿了很多無用的 commit 記錄,如果有一天線上出現問題需要回滾代碼,大量的 commit 記錄會讓你爆炸。

我這裏實際的演示,我在我的開發分支 feature1 開發了一個功能,有多條 commit 記錄,我想要合併成一條,然後提交 MR 到 master(main)

Note: github 叫 Pull Request, gitlab 叫 Merge Request,只是叫法不一樣。

這個時候就需要用到git rebase了。這個命令並不難,對於 git 命令的新手來說不熟悉的情況下可能不太敢使用,你可以在用之前先備份你的分支,避免操作失誤又不會還原。

1. 合併最近的三條提交記錄

執行:

git rebase -i HEAD~3

或者

git rebase -i commit_id

這裏的 commit_id 是你要合併的第一條 commit 的前一條。可以通過 git log查看 commmit id。

會自動進入 vi 編輯模式。

這裏可以看到我們有三次提交記錄:

pick 3ae8e31 fix 1
pick c2828fb fix 2
pick 6077ab1 fix 3
# Rebase c0933b9..6077ab1 onto c0933b9 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')

這裏有一些Commands,每個有不同的作用,上面都有詳細的解釋。

我們暫時只需要關注兩個,一個是 p(pick), 一個是 s(squash)

•p, 保留該 commit•s, 將該 commit 和前一個 commit 合併

把第一個 commit 使用 p,後面的所有 commit 都使用 s

2、把除第一條 commit 外都改成 squash

pick 3ae8e31 fix 1
s c2828fb fix 2
s 6077ab1 fix 3

像以上這樣,把除了第一條提交之外的所有提交的 pick 改成 s(squash)。然後使用 :wq 退出編輯。

3、修改 commit 信息(可選)

如果你覺得第一條的 commit 不太好,想改成一個比較可讀性的 commit 記錄,可以直接修改。

這裏我把

fix 1

直接編輯 修改爲

feature 1 development

然後 :wq 退出。

4、 git log 查看 commit 記錄。

這個時候會發現 git log 裏面關於你的 feature 只有一條 commit 記錄了,就是 rebase 成功了。

5、git push -f

最後一步就是執行 git push -f 強制 push 到遠端。一定要加 -f 或者 --force。不然無法 push 成功。因爲你當前的本地分支已經回到了之前的提交點。

這個時候刷新一下你的 MR 的頁面。就會發現:

你的 commit 已經合併了。這個時候你在 Merge 到 master 分支,就只有這一條 commit 記錄了。是不是非常乾淨了。

注意:

• 如果你的分支裏面有來自其他分支的Merge Request,比如你的開發週期比較久,在你開發的幾次提交中間,不停的git merge master,導致你的分支裏面有了 master 最新的修改。也就是MR的記錄,慎用rebase,這個時候我一般會用git reset。只有當你的分支裏面全部是你的 commit 記錄的時候,用git rebase

二、合併分支

rebase 的第二大作用就是合併分支了。

rebase 通常用於重寫提交歷史。下面的使用場景在大多數 Git 工作流中是十分常見的:

• 我們從 master 分支拉取了一條 feature1 分支在本地進行功能開發 • 遠程的 master 分支在之後又合併了一些新的提交 • 我們想在 feature1 分支集成 master 的最新更改

下面用具體的例子來描述

1、我們先從 master 分支切出一個 feature1 分支,進行開發:

git:(master) git checkout -b feature1

2、這個時候你的同事可能開發了 feature2 併合併到了 master,此時 master 已經領先於你的 feature1 分支了。

3、之後我們需要同步 master 的改動。

最常用的做法就是,在你的feature1分支執行:

git merge master

使用過 git 命令的人都瞭解這個命令。合併之後查看一下 log。執行:

git log

就會發現多了一些 merge 的 commit 信息。如果你的 feature 的開發週期很長,經常需要定期 merge master,就會發現多了很多的 commit 信息。想要保持一份乾淨的 commit, 這個時候 git rebase 就派上用場了。

4、使用 git rebase master 代替 git merge master

在你自己的feature1分支上執行:

git rebase master

這裏 git rebase 的原理是什麼呢?

1.git 會把 feature1 分支裏面的每個 commit 取消掉;2. 把上面的操作臨時保存成 patch 文件,存在 .git/rebase 目錄下;3. 把 feature1 分支更新到最新的 master 分支;4. 把上面保存的 patch 文件應用到 feature1 分支上;

從 commit 記錄我們可以看出來,feature1 分支是基於 feature2 合併後的 master,就像把一個並行的流程變成一個串行的流程。就沒有了 merge 的 commit 記錄,看起來會清晰多了。

Note:
在 rebase 的過程中,也許會出現衝突 conflict。在這種情況,git 會停止 rebase 並會讓你去解決衝突。在解決完衝突後,用 git add 命令去更新這些內容。

git rebase --continue

在任何時候,我們都可以用 --abort 參數來終止 rebase 的行動,並且分支會回到 rebase 開始前的狀態。

git rebase —abort

總結:

• 當我們在一個過時的分支上面開發時,執行 git rebase 來同步 master 分支的最新改動 • 相比較merge來說會減少分支合併的記錄

注意:

• 不要在公共分支使用rebase,rebase 會改變 commit 歷史,其他依賴此分支的人可能會丟失記錄。

總結

通過 rebase 策略執行 git pull Git 在最近的某個版本起,直接運行 git pull 會有如下提示消息:

warning: 不建議在沒有爲偏離分支指定合併策略時執行 pull 操作。 您可以在執行下一次 pull 操作之前執行下面一條命令來抑制本消息:
  git config pull.rebase false  # 合併(缺省策略)
  git config pull.rebase true   # 變基
  git config pull.ff only       # 僅快進

原來 git pull 時也可以通過 rebase 來進行合併,這是因爲 git pull 實際上等於 git fetch + git merge ,我們可以修改 git 配置直接使用 git rebase 替換 git merge 來合併 fetch 取得的變更,作用同樣是避免額外的 merge 提交以保持線性的提交歷史。

具體的使用方式有多種:

• 每次執行 pull 命令時添加特定選項: git pull --rebase。• 爲當前倉庫設定配置項: git config pull.rebase true,在 git config 後添加 --global 選項可以使該配置項對所有倉庫生效。

結論

git-rebase 存在的價值是:對一個分支做「變基」操作。

  1. 當我們某一個分支有過多的 commit 記錄需要整合,執行 rebase 來合併提交。2. 當我們在一個過時的分支上面開發的時候,執行 rebase 以此同步 master 分支最新變動;3. 假如我們要啓動一個放置了很久的並行工作,現在有時間來繼續這件事情,很顯然這個分支已經落後了。這時候需要在最新的基準上面開始工作,所以 rebase 是最合適的選擇。

碼農在新加坡 Leftpocket 是一名後端程序員,擅長 C++, Golang, 網絡編程, Redis, MySQL, TiDB 等技術棧。有多年高併發開發和麪試官經驗,在這裏分享各種後端技術與面試等專業知識。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/tJ-0F1qYHr80458F0JlHtg