天天看點

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

想象一下你正在開發一個激進的新功能。這将是很燦爛的但它需要一段時間。您這幾天也許是幾個星期一直在做這個。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

你的功能分支已經超前master有6個送出了。你是一個優秀的開發人員并做了有意義的語義送出。但有一件事情:你開始慢慢意識到,這個瘋狂的東西仍需要更多的時間才能真的做好準備被合并回主分支。

m1-m2-m3-m4 (master)

\

f1-f2-f3-f4-f5-f6(feature)

你也知道的是,一些地方實際上是交叉不大的新功能。它們可以更早地合并到主分支。不幸的是,你想将部分合并到主分支的内容存在于你六個送出中的某個地方。更糟糕的是,它也包含了依賴于你的功能分支的之前的送出。有人可能會說,你應該在第一處地方做兩次送出,但沒有人是完美的。

^

|

mixed commit

在你準備送出的時間,你沒有預見到,你可能要逐漸把該功能合并入主分支。哎呀!你不會想到這件事會有這麼久。

你需要的是一種方法可以回溯曆史,把它并分成兩次送出,這樣就可以把代碼都安全地分離出來,并可以移植到master分支。

用圖說話,就是我們需要這樣。

f1-f2-f3a-f3b-f4-f5-f6(feature)

在将工作分成兩個送出後,我們就可以cherry-pick出前面的部分到主分支了。

原來git自帶了一個功能強大的指令git rebase -i ,它可以讓我們這樣做。它可以讓我們改變曆史。改變曆史可能會産生問題,作為一個經驗,應盡快避免曆史與他人共享。不過在我們的例子中,我們隻是改變我們的本地功能分支的曆史。沒有人會受到傷害。就這麼做了!

好吧,讓我們來仔細看看f3送出究竟修改了什麼。原來我們共修改了兩個檔案:userservice.js和wishlistservice.js。比方說,userservice.js的更改可以直接合入主分支而wishlistservice.js不能。因為wishlistservice.js甚至不存在在主分支裡面。它是f1送出中引入的。

專家提示:即使是在一個檔案中更改,git也可以搞定。但這篇部落格中我們先簡化情況。
Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

現在,我們要做的第一件事就是使用git的checkout功能checkout出我們的功能分支。用git rebase -i master開始做rebase。

現在接下來git會用所配置的編輯器打開(預設為vim)一個臨時檔案。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

該檔案為您提供一些rebase選擇,它帶有一個提示(藍色文字)。對于每一個送出,我們可以選擇的動作有pick、rwork、edit、squash、fixup和exec。每一個動作也可以通過它的縮寫形式p、r、e、s、f和e引用。描述每一個選項超出了本文範疇,是以讓我們專注于我們的具體任務。

我們要為f3送出選擇edit選項,是以我們把内容改變成這樣。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

現在我們儲存檔案(在vim中是按下後輸入:wq,最後是按下回車)。接下來我們注意到git在編輯選項中選擇的送出處停止了rebase。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

這意味這git開始将f1、f2、f3生效仿佛它就是正常的rebase,但是在f3生效之後停止。事實上,我們可以看一眼停止的地方的日志就可以證明這一點。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

要将f3分成兩個送出,我們所要做的是重置git的指針到先前的送出(f2)而保持工作目錄和現在一樣。這就是git reset在混合模式在做的。由于混合模式是git reset的預設模式,我們可以直接用git reset head~1。就這麼做并在運作後用git status看下發生了什麼。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

git status告訴我們userservice.js和wishlistservice.js被修改了。如果我們運作 git diff 我們就可以看見在f3裡面确切地做了哪些更改。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

如果我們看一眼日志我們會發現f3已經消失了。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

現在我們有了準備送出的先前的f3送出,而原先的f3送出已經消失了。記住雖然我們仍舊在rebase的中間過程。我們的f4、f5、f6送出還沒有缺失,它們會在接下來回來。

讓我們建立兩個新的送出:首先讓我們為可以送出到主分支的userservice.js建立一個送出。運作git add userservice.js 接着運作 git commit -m "f3a: add updateuser method"。

太棒了!讓我們為wishlistservice.js的改變建立另外一個送出。運作git add wishlistservice.js,接着運作git commit -m "f3b: add additems method".

讓我們在看一眼日志。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

這就是我們想要的,除了f4、f5、f6仍舊缺失。這是因為我們仍在rebase互動的中間,我們需要告訴git繼續rebase。用下面的指令繼續:git rebase --continue。

讓我們再次檢查一下日志。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

就是這樣。我們現在已經得到我們想要的曆史了。先前的f3送出現在已經被分割成兩個送出f3a和f3b。剩下的最後一件事是cherry-pick出f3a送出到主分支上。

為了完成最後一步,我們首先切換到主分支。我們用git checkout master。現在我們就可以用cherry-pick指令來拾取f3a commit了。本例中我們可以用它的sha值bd47ee1來引用它。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

現在f3a這個送出就在主分支的最上面了。這就是我們需要的!

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

這篇文章的長度看起來需要花費很大的功夫,但實際上對于一個git進階使用者而言這隻是一會會。

Git Rebase教程: 用Git Rebase讓時光倒流Git Rebase教程: 用Git Rebase讓時光倒流

原文釋出時間:2014-10-20

本文來自雲栖合作夥伴“linux中國”

繼續閱讀