Git知識總覽(五) Git中的merge、rebase、cherry-pick以及互動式rebase
上篇部落格聊了《git分支管理之rebase 以及 cherry-pick相關操作》本篇部落格我們就以Learning Git中的關卡進行展開。下方列舉了LearningGit中的 merge、rebase、reset、revert、cherry-pick 以及互動式rebase相關關卡的操作以及對應的解析。後邊在聊互動式rebase操作是,不單單給出了LearningGit中的內容,而且給出了真正的Git分支在互動式rebase操作時的具體案例。
learngitbranching的地址為:https://learngitbranching.js.org/
一、程式碼合併
在下方示例中所有目標的初始化狀態是下方這樣的,然後我們要按照目最終目標,使用相關的git命令來達到相關的目標。
1、git merge
下方就是我們要達到的目標,下方是我們達到下方目標所要做的事情:
-
首先需要做的就是建立一個新的分支bugFix, 並切換到該分支上,然後進行一次C2的提交。
-
然後再切回到master分支上,進行一次新的提交(C3)。
-
最後要做的就是在master分支上執行一次合併操作,將bugFix分支上的提交合併到master分支上,C4就是合併後的節點。
下方對應的就是我們實現上述目標所對應的命令操作,具體如下所示:
-
首先使用git checkout -b bugFix, 新建並切換到bugFix分支上,並且使用git commit命令進行一次提交生成C2節點。
-
然後使用git checkout master命令切換到master分支上,並且使用 git commit 命令進行一次提交生成C3節點。
-
最後的話,就是在 master 分支上執行git merge bugFix命令,將bugFix分支合併到master分支上,合併後會生成一個新的C4節點。具體如下所示:
2、git rebase
闖完git merge的關,我們來看一下git rebase的關。下方就是我們最終要實現的目標。實現下方目標和上面的merge操作差不多,只不過最後一步不是使用合併操作,而是在bugFix上執行變基操作,具體分析如下:
-
首先需要做的就是建立一個新的分支bugFix, 並切換到該分支上,然後進行一次C2的提交。
-
然後再切回到master分支上,進行一次新的提交(C3)。
-
然後在切換到 bugFix 分支上,執行變基操作,將bugFix的父節點變成master分支,之前的C2節點就被新的提交C2`所替代了。
下方是我們的具體命令操作:
-
首先使用git checkout -b bugFix, 新建並切換到bugFix分支上,並且使用 git commit 命令進行一次提交生成C2節點。
-
然後使用git checkout master命令切換到master分支上,並且使用 git commit 命令進行一次提交生成C3節點。
-
然後再使用git checkout bugFix命令切回到 bugFix 分支上。
-
最後在bugFix分支上執行git rebase master命令,經其父類變成master。執行變基後,C2會和C3節點的內容進行合併生成新的節點C2`,而bugFix分支的指標也會從C2節點移動到C2`上,移動後bugFix之前的分支就會被廢棄掉,取而代之的是從master延續下來的新分支。
二、分離HEAD
1、移動HEAD指標
HEAD指標是指向當前所在的操作分支,比如我們現在是在master分支,那麼HEAD就指向master分支,然後master分支指向的是我們的commit號。分離的 HEAD 就是讓其指向了某個具體的提交記錄而不是分支名。下方左邊的圖就是我們要完成的目標,右邊是我們分支的初始化狀態。
實現上述目標一行命令足矣,可以使用 git checkout C3 命令就可以將HEAD命令指向C3提交上。git checkout HEAD^命令可以將HEAD指標向上移動一個距離,git checkout HEAD~3 則可以將HEAD向上移動三個距離。具體操作如下所示:
2、在提交樹上移動分支
下方要完成的不單單是HEAD指標的移動,而是分支指標的移動,在Git上可以移動你所建立分支的指向,使其指向任意提交過的分支上。下方就來看一下如何在git上移動分支指標,下方左邊是我們要完成的目標,右邊是分支的初始化狀態。需要做的事情如下:
-
將 bugFix 分支移動到C0上。
-
然後將master分支移動到C6上。
-
最後將HEAD分支上移。
需要操作的命令如下所示:
-
首先使用git branch -f bugFix C0命令將bugFix指向C0節點。(C0表示的是相關提交的雜湊值)。
-
然後使用git branch -f master C6命令將master分支指向C6節點。
-
最後使用git checkout HEAD^命令將分離的HEAD指標進行上移。
3、撤銷操作
接下來我們來看一下撤銷操作,同樣左邊是我們要完成的目標,右邊是初始狀態。從下方的目標中我們可以看出 local 分支的撤銷操作是使用的 git reset 操作的, 因為是在本地來向上移動的,進行reset後是不可以push到遠端的。而push分支使用的是revert操作,撤銷了C2的提交後,再C2的基礎上又生成了一個新的提交。reset 操作是不可以被push到遠端的,而revert則可以,稍後會進行實驗。下方會有具體的操作。
下方就是我們為了完成目標而又的具體的操作:
-
首先在 local 分支上執行git reset HEAD^1或者git reset HEAD C1操作來撤銷本地的C3操作。
-
然後我們再通過git checkout pushed操作切換到 pushed 分支上,然後執行git revert HEAD^1操作,撤銷C2的提交。
如果你reset某個提交,想在將分支號移動到之前的提交上,可以使用上面的 git branch -f 操作,將相應的分支移到相應的提交上。下方是將 local 分支又移動回了C3, 如下所示。
接下來我來看一下對 reset 後的分支進行push, 以及對 revert 分支後進行push。
-
首先在local分支上執行reset操作,然後進行push會提示本地倉庫和遠端倉庫產生了分歧,先git pull 或者git pull --rebase。
-
而在pushed分支上的revert操作就不會有這樣的提示,因為revert是在原來的分支下方產生了一個新的提交,和正常提交一樣對待,所以是可以push的。
下方我們再做個嘗試,在一個分支上進行了reset , 然後在reset後的分支上做了一些提交。最後我們將這些提交進行push,然後看一下具體的效果。
-
首先我們對clone到本地的local分支進行了reset操作,操作後在新的分支上進行兩次commit。
-
然後我們進行push , 會提示先pull或者pull --rebase, 然後在進行push.
-
下方先執行了 git pull 操作,執行pull操作後,就是將 o/local 分支和 local分支進行合併,合併後就可以進行push了。這樣一來,我們之前reset操作就不起什麼作用了。因為 pull 操作後進行了merge, 就等效於在C3上直接進行commit。
-
然後我們進行回退,又試了一下git pull --rebase操作,其實該操作就是將merge操作改成了變基操作。將我們後來的C4, C5兩個提交變基到C3上,從效果上看,就和沒有執行reset操作一樣。具體如下所示:
三、cherry-pick和互動式rebase
之所以將這兩個放在一塊,是因為使用兩者都可以達到相同的目標,只是操作不同。下方會分別介紹。
1. cherry-pick
下方我們來看一下cherry-pick這一關,下方我們需要將 bugFix 分支上的C3 、side分支上的 C4 以及another分支上的C7通過cherry-pick的形式拿到 master分支上。
下方主要還是使用了cherry-pick來達到我們的目標的,主要還是一個命令的使用 , 在 master 分支上執行 git cherry-pick C3 C4 C7, 可以將C3 C4 C7這三個提交摘到master分支上了。具體如下所示:
2、互動式rebase
解析我們來使用互動式rebase來做節點的遷移,當然下方的操作也是可以使用cherry-pick來完成的。左邊是我們要完成的目標,右邊則是初始化狀態。我們需要將C2 C3 C4 C5的提交順序轉換成C3, C5, C4的順序。
下方就是我們互動式rebase操作的具體步驟,本質上就一個命令 git rebase -i HEAD~4, 然後操作相關的節點即可。
3、互動式rebase實踐
接下來我們來看一下在真正的git分支上是如何使用互動式rebase操作的。下方是做互動式rebase操作之前的分支關係。目前所在的分支是bugFix, 其中有4個提交。
現在要做的是在bugFix上進行互動式rebase, 在終端中輸入 git rebase -i master, 目的是將 bugFix 分支上的提交通過互動式rebase的方式將其變基到master分支上。下方是輸入git rebase -i maste命令後所出現的介面,我們可以通過vim編輯器編輯將要執行的變基操作。下方是對應的幾種互動式命令
-
pick 應用相關提交。
-
reword 修改commit資訊。
-
edit 對提交進行編輯,然後使用git commit -amend進行提交。
-
squash 是把多個提交合併成一個提交
-
fixup 與squash差不多,不過會拋棄掉本次提交的log資訊
-
exec 執行shell命令
-
drop 刪除提交
下方我們對相關操作執行的互動式的操作:
-
首先使用 reword 來操作下方截圖中的第一條操作,用來修改message。
-
然後交換了第二行和第三行的pick的位置
-
然後對第四行的提交執行edit命令對其進行修改
-
然後刪除 編號為04的提交
點選回車鍵的話會彈出下方的vim編輯器來讓你修改 f53560c 這個操作的commit message,修改完畢後進行儲存即可。
下方是在rebase合併時產生了衝突,我們需要對衝突進行解決。解決完畢後,執行 git add 將衝突檔案進行儲存,並且執行git rebase --continue 來繼續我們的rebase操作。
經過一系列解決衝突的操作,最終我們的rebase操作是成功的,會提示下方的 Successfully。
互動式rebase操作成功後,接下來我們來看一下當前分支的情況,,從結果中我們不難看出:
-
bugFix 分支上的提交已經變基到了master分支上。
-
“change aa.text 04”的提交已經被移除了。
-
“change aa.text 01” 和“change aa.text 02” 的提交順序進行了交換。
-
並且 "create aa.text" 的log變成了 "create aa.text reword"
4、互動式rebase的squash操作
接下來我們來看一下squash的操作,下方我們會在當前所在分支和上次提交上執行squash操作,其對應的命令的為:git rebase -i HEAD~1,如下所示:
我們對該操作執行squash命令,如下所示,編輯完進行儲存即可。
儲存後會出現下方的操作,目的是用來編輯兩次提交合並後的commit message 的。
編輯完儲存即可,下方就是我們進行上述操作後所對應的相關資訊。
5、互動式rebase的另一個示例
接下來我們來看一下另一個互動式rebase的示例,完成下方的目標,我們需要做下方几步:
-
首先我們通過互動式rebase將caption變基到master分支上,在變基操作時交換 C2 和 C3的位置。
-
然後通過git commit --amend往 C2 上追加提交內容。
-
最後再通過 git rebase -i 操作將C2和C3進行交換。
下方就是對應的具體命令操作:
-
首先在caption分支上執行git rebase -i master, 將caption分支通過互動式rebase的方式變基到master分支。
-
在互動式變基時,修改了C2和C3的提交順序。
-
然後在通過git commit -amend 操作往C2上追加了一些修改。
-
然後再通過git rebase -i master , 將C2和C3進行交換回來。
-
最後將master使用git rebase 操作進行快速移動到caption上。
今天部落格就先到這兒吧,下篇部落格繼續聊git相關的內容。