git rebase的兩個使用技巧

前言

本文會從git中最重要的分支概念入手,幫助你們更好的理解git分支的本質,從而對操做分支時對其原理了然於心,最後順便分享在團隊內工做流常用的git rebase的兩個小技巧。git

目錄bash

  • git簡介
  • 分支
  • rebase的兩個用法

git簡介

git是個分佈式和漸進式的版本管理工具。分佈式是指代碼能夠克隆不少份,不像svn(集中式版本管理工具)集中對一份代碼進行版本管理,而git容許你將項目fork成本身一份。而漸進式是指git會智能的diff代碼的改動狀況,但不是記錄文件的具體變化,而是保存一系列不一樣時刻的文件快照。分佈式

具體參考廖雪峯老師的git教程git官網svn

分支

爲了更好的使用git去解決一些複雜的版本衝突問題,有必要先理解git的分支。工具

快照gitlab

其實要理解git的分支,首先要了解git是如何保存文件的
git以文件快照的方式保存文件的更改狀況,而不是cope每一份代碼
那麼如何理解文件快照的?ui

快照,咱們能夠把它抽象爲照片,能夠想象一下用相機拍下桌子上物體,照片記錄着每一個時刻物體的位置和狀態,git就是把這每一個照片保存起來,等須要的時候指定一張照片來把物體擺設成這個樣子spa

暫存3d

在暫存時,git把每一個文件當作一個blob對象,把快照保存進blob對象裏面,而後就加進暫存區域等待提交指針

提交

commit的時候,git會生成一個數對象來記錄這個目錄結構(包括子目錄)和blob對象的索引,還會生成一個commit對象來保存一個指向這個樹對象的指針和其餘一些提交信息(msg,time,author,email)
有了這個指針,就能夠方便追溯到此次commit的文件快照,來重現這個時刻的文件狀態

首次提交簡介圖

以上的是首次提交的狀況,在第二次提交時
在原有的狀況下,git再生成一個指針去指向上一次的commit對象,咱們稱之爲父對象

再次提交簡介圖
如今狀況就明瞭了,git是以單鏈表結構來追溯文件狀態的

分支指針

既然git是經過指針去追溯文件快照的,那麼是否是能夠建立多幾個指針去多拿幾張照片,進而多重現幾個狀態呢?
因此分支就是所謂的指針,那麼git又是怎麼知道我在哪一個分支上呢?
沒錯,再建立一個指針去指向這個分支指針,來表示我當前所在的分支。

分支簡介圖
全部的提交都是以單鏈表結構鏈接起來的,經過這個指針來追溯到所需的commit對象

可是衝突是如何產生的呢?
看個圖就明白了

分支簡介圖
其實就是多個commit對象中指向父對象的指針指向了同一個父對象。而兩個照片中物體在同一個時刻有兩個狀態,因此就產生了衝突。

使用命令查看分支的指向狀況,或者說項目的分叉狀況

git log --oneline --decorate --graph --all  
複製代碼

rebase的兩種用法

1. 合併commit

你確定也試過這樣的場景,leader交給你一個小需求,一個小時不到就解決了,提交一個commit,但過了一會,以爲代碼還有能夠改進的地方,做爲一個努力上進的人,你確定不會只求完成需求這麼簡單,因此再提了一版...

但這個幾個commit都是爲了同一個需求開發的,leader去review代碼的時候,幾個commit還好,但實際開發中有時是十幾個commit,這樣對於review代碼和追蹤版本時,就顯的尤其困難了

因此須要將爲同一個需求開發的這些commit合併成一個

git rebase -i HAED~n
複製代碼

上面的n代指數字,表示包括當前之前的幾個commit

這是會出現一個編輯界面

pick 5e187c7dbe8    add center style indent  
pick 6d577eb3440    add center style  
pick f9b9508a3ab    add center style  
pick 111ab9cc261    update templates  
# Rebase 150a643..2fad1ae onto 150a643 
# 
# Commands: 
# p, pick = use commit 
# r, reword = use commit, but edit the commit message 
# e, edit = use commit, but stop for amending 
# s, squash = use commit, but meld into previous commit 
複製代碼

把第二到四行的pick更改成s,就會使用這個commit,而且合併前個commit

若出現衝突,解決衝突,應用最新的版本,使用

git add . //提交索引
git rebase --continue //繼續rebase操做
複製代碼

若在合併commit的過程當中想放棄,可使用命令

git rebase --abort
複製代碼

此時會出現一個編輯窗口,保存退出就行

最後把本地推上遠程

git push -f //必須帶上-f,以本地覆蓋遠程
或者指定遠程和分支
git push (origin master) -f
複製代碼

由於本地的幾個commit已經合併成了一個,而若遠程還有這幾個commit,須要以本地覆蓋遠程

2. 合併分支

有以下分支圖

step_1
在master上合併dev咱們通常用

git merge dev
複製代碼

此時分支圖就變爲

step_2
這樣分支圖就顯的很亂,使用rebase可以讓合併後的分支圖變得簡潔
在最新的分支dev上

git rebase master
複製代碼

step_3
dev上的C4會被cope成'C4'而且dev指向'C4',保存在rebase文件夾,而後'C4'指向C3,最後C4會當成垃圾清除,最後分支圖就變爲了
step_4
如有衝突,解決後

git add .
git rebase --continue
複製代碼

隨時放棄

git rebase --abort
複製代碼

在拉去遠程更新時也可使用rebase

git pull --rebase
或者指定遠程和分支
git pull upstream master --rebase
複製代碼

ps:
假若經過git pull --rebase致使在gitlab上發merge request時,出現了其餘人的本已經提交了的commit信息,不妨用使用

git reset --soft <commitID> //保留更改回退
複製代碼

再次commit,在gitlab再發merge request,應該就乾淨了(只是本身的提交信息)

回到最初

解決git複雜問題的前提仍是得先看的明白git的分支圖,清晰每條命令對git分支的影響。

相關文章
相關標籤/搜索