- 原文地址:Don’t Fear The Rebase
- 原文做者:本文已獲原做者 Jared Ready 受權,轉載請註明出處。
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:根號三
- 校對者:Tina92、Starrier
Git 的 rebase
命令是 Git 用戶感到懼怕和迷惑的一個常見緣由,特別是那些來自可能更集中的版本控制系統的用戶。這很正常。Rebase 是一個難以想象又充滿魔力的怪獸,一上來無論三七二十一就改變歷史。前端
Rebase 有點像指針。它是這樣一個使人困惑的結構:每一個人都在談論它,可是你並不清楚爲何會有人使用它,而後忽然一切都「啪嗒」一下,整個想法都變得顯而易見和難以置信的簡單。android
在這篇文章中我會迫使你「啪嗒」一下,這樣你就能夠回到工做中並傳播 git rebase
的神奇。ios
Git Rebase 是一個很簡單的工具,用來取出一些在某個地方建立的提交,並僞裝它們一直是在另外一個地方建立的。git
好的,我知道了。但是這意味着什麼呢?github
讓咱們來看一個例子。咱們在這個倉庫中有兩個分支:master
和 feature/foo
。feature/foo
是基於 master
分離出去的分支,而且在 feature/foo
分支上產生了一些提交。master
也發生了移動,就像世界不會由於少了你的關注而停滯不前。後端
這是目前的狀態工具
咱們想將一些更改從 master
整合進 feature/foo
中,可是咱們不想每次執行這個整合時都處理一次使人討厭的合併提交。區塊鏈
Rebase 就是一個讓你有能力整合發生在源分支上的更改而不須要執行合併(merge)從而不會產生合併提交的工具。人工智能
這是 rebase 以後的狀況。(fast-forward 版本)翻譯
D 和 F 兩個提交已經被從新放在了 master
的頂部,即當前指向的 G 提交。你可能會注意到這兩個提交實際上已經被重命名爲了 D* 和 *F
,而且提交的 SHA-1 值也不同。這是爲何呢?
一個提交具備一些與之相關的屬性:一個父提交、一個時間戳、提交時倉庫的快照(提交不只僅是變動集)。這些值是 Git 在計算標識一個提交的 SHA-1 時所用到的。
因爲提交是不可變的,而且一個 SHA-1 應該惟一標識一個提交,所以 Git 須要建立一個新的提交來包含原始提交中相同的倉庫快照,可是每一個提交都有一個不一樣的父提交和時間戳。
這致使新的提交看起來與原始提交相同,可是具備不一樣的 SHA-1。
當咱們從 feature/foo
分支上運行 git rebase master
時,Git 怎麼知道哪些提交須要移動呢?
讓咱們先看看每一個分支上的提交的文氏圖(Venn diagram)。
從上圖中咱們能夠看到每個分支都有 A、B 和 C 這幾個提交。master
分支還擁有 E 和 G 提交可是 feature/foo
分支沒有。feature/foo
擁有 F 和 D 提交可是 master
分支沒有。
Git 會作一個減法:{commits on feature/foo} — {commits on master}
,來找出正確的提交。這個結果就是 D 和 F。
固然,一個簡單方式是使用 git log
來看咱們從這組減法中獲得的確切提交。
git log master..feature/foo
會 向咱們展現 bc1f36b
和 640e713
提交。
若是你在 .. 後省略了一個分支,那麼會默認爲是當前分支。
看起來不錯。讓咱們來看看更普遍的視角以確保我不是在糊弄。
這些 sha-1 看起來很熟悉。
這裏並無 76f5fd1 和 22033eb,由於咱們是從 master 分支的 7559a0b 提交開始分離的。
若是咱們如今執行一個 rebase
到 master
,咱們會當即看到 76f5fd1
和 22033eb
出如今咱們在 feature/foo
分支上建立出的提交的前面。
Git 正在像咱們指望中的那樣從新應用提交。
看起來熟悉嗎?
咱們以前見過這個了。
咱們如今有一個很好的線性歷史。你應該可以想到在此刻 fast-forward 的合併會如何發生。
rebase 策略還有一個已知的額外好處,就是若是你的 CI 管道(CI pipeline)在功能分支上經過了,那麼在合併後的主分支上它也會經過。若是是一個非線性的合併策略,你就不能保證這一點。
若是 feature/foo
分支已經被推送過(push),而且在 rebase 以後嘗試進行另外一個推送,Git 會很委婉地拒絕推送。這是爲何呢?
Git 會盡其所能來防止意外覆蓋歷史,這是一件好事。
咱們來看一下 Git 所認爲的 feature/foo
分支在遠程倉庫中是什麼樣的?
如今咱們來看一下咱們告訴 Git 要作的事情。
從 Git 的角度來看,提交 D 和 F 即將丟棄。Git 會給你這樣一行友好的信息:Updates were rejected because the tip of your current branch is behind
。
你或許會說,「可是我能夠在你這個很棒的圖片中清晰地看到,feature/foo
分支比以前更進一步了啊。」 這是一個很好的觀察結果,可是 Git 只會看到遠程倉庫中的 feature/foo
包含 bc1f36b
和 640e713
,可是你本地的 feature/foo
不包含這些提交。所以爲了避免丟失這些提交,Git 會委婉地拒絕一個正常的 git push
,並要求你執行 git push --force
。
若是你從這篇文章中帶走一件東西,那麼請記住,rebase 只是簡單的查找出在某個分支上建立的提交,而後使用相同的內容可是新的父提交或基礎提交(base commit)來建立新的提交。
若是你喜歡個人文章,請爲我點贊。
關注 Hackernoon 和 Jared Ready 來獲取更多高質量的軟件工程相關的內容吧。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。