![](/img/trans.png)
[英]Rebasing everyone onto changed git history after filter-branch
[英]Will the history be gone after rebasing in git
假設我有3次提交的master分支
A--B----C
我創建一個新的分支dev
並在那里創建3個提交
A--B----C------C1------C2
\
E---F----G
現在我像這樣與師父合並
git merge dev --squash
現在我認為新圖就是這樣,但不確定
A--B----C------C1------C2--------M----
\ /
E---F----G-----------/
再一次,我需要與master合並dev
分支以獲取命令c1和c2
所以會是這樣
A--B----C------C1------C2--------M----
\ / \
E---F----G-----------/----m2 ---H--I
dev
和master
將並行
我想知道
我想知道如果我要使用rebase而不是merge時兩個分支應該並行的關系,那將是什么圖
如果第一個問題的答案是肯定的,那么如果我使用rebase命令,個人歷史記錄將消失
讓我用一些標簽重新繪制第二張圖:
A--B--C-----C1----C2 <-- master
\
E--F----G <-- dev
(我假設C1
和C2
僅代表將E
, F
和G
添加到dev
時在master
上發生的一些提交)。
如果您現在在master
並運行git merge dev --squash
(然后提交結果:-- --squash
取消最后的提交步驟),則會得到this ,它與您繪制的內容有很大不同:
A--B--C-----C1----C2---M <-- master
\
E--F----G <-- dev
如果在不使用 --squash
情況下運行git merge
您將獲得所得到的內容。 --squash
標志將引用文檔:
產生工作樹和索引狀態,就像發生真正的合並一樣(合並信息除外),但實際上不進行提交或移動HEAD, 也不記錄$ GIT_DIR / MERGE_HEAD導致下一個git commit命令創建合並承諾。
換句話說,壁球合並根本不是合並(這就是為什么我有git某些術語的“問題” :-)……有些結帳是結帳,而有些則不是。 有些合並是合並,有些則不是; 分支只是分支技巧,除非不是,等等!)。 “南瓜合並”確實會使用基礎合並代碼來確定下一次提交的內容,但是如果並且當您進行實際提交(上面標記為M
提交)時,它只是一個普通的非合並提交,它將工作(所做的更改)從E
提交到G
並將這些更改復制到C2
的最新版本中。 可以將其想象為“有人向您發送差異,將C
版本與G
版本進行比較,然后您將所有這些更改手動插入C2
版本中並提交(可能應稱為C3
但我們改名為M
)”。
如果要進行真正的合並,請在不使用 --squash
情況下進行合並。 實際上,這將為您提供您所繪制的內容,我將在此處重新繪制:
A--B--C-----C1----C2---M <-- master
\ /
E--F----G----/ <-- dev
(標簽dev
仍指向提交G
)
接下來,如果要提取C1
和C2
的更改並將其放在dev
,則可以執行以下兩項操作之一:
git checkout dev && git merge master
要么:
git checkout dev && git merge --no-ff master
此處的區別是您是否獲得了所繪制的提交m2
。 如果沒有--no-ff
,git會觀察到dev
和master
的合並會產生提交M
,並且只是將dev
標簽移動到M
:
A--B--C-----C1----C2---M <-- dev, master
\ /
E--F----G----/
但是,使用--no-ff
,合並必須產生一個新的,不同的合並提交(同一棵樹,但是仍然具有不同的提交,並且具有不同的父級年齡):
A--B--C-----C1----C2---M <-- master
\ X
E--F----G------m2 <-- dev
在這里,合並M
將C2
作為其第一父級,將G
作為其第二父級。 這表明它是G2
(“非第一”父代)到master
(第一父代)的合並。 另一方面,合並m2
將G
作為其第一父級,將C2
作為其第二父級。
換句話說,樹(工作目錄)是相同的,父級的集合 (忽略列表的順序)是相同的,甚至提交消息和時間戳也可以是相同的:但是父級的順序是不同的,僅此一項就足以保證這些將是不同的提交。
您的問題的標題是關於重新定級,而不是合並。 變基完全是另一種操作。 假設您正在使用分支dev
並運行git rebase master
。
為了做一個基准,git所做的就是(本質上是-應用了一些優化,還有一些帶有合並提交的極端情況)只是簡單地“櫻桃挑選”沿着某個分支的每個提交,並將那些“櫻桃”應用於其他分支。 讓我們回到第一個圖:
A--B--C--C1--C2 <-- master
\
E--F--G <-- dev
這里的想法是“選擇”提交E
,然后F
,然后G
並按順序應用它們。 讓我們開始將E
復制到E'
,將其復制到C2
之上:
E'
/
A--B--C--C1--C2 <-- master
\
E--F--G <-- dev
接下來我們像這樣將F
復制到F'
:
E'--F'
/
A--B--C--C1--C2 <-- master
\
E--F--G <-- dev
還有一個提交要復制, G
到G'
:
E'--F'--G'
/
A--B--C--C1--C2 <-- master
\
E--F--G <-- dev
除了一件事情,我們都完成了:我們需要新提交鏈的標簽。 我們稱之為dev
! 糟糕,等等,我們已經有了標簽dev
。 好吧,讓我們剝去舊的dev
標簽,然后將其粘貼到新的G'
:
E'--F'--G' <-- dev
/
A--B--C--C1--C2 <-- master
\
E--F--G
瞧, git rebase
已經完成。 這就是它的作用:將舊提交復制到新提交。
舊的會怎樣? 好吧,它們就是我所說的“被遺棄”。 它們仍然在您的存儲庫中,但是它們的唯一標簽僅存儲在“ reflogs”中。 reflog條目將使它們保留30天左右的默認到期超時。 (它是可配置的,實際上有兩個不同的超時,但是最好僅將其視為“一個月左右”。)因此,在大約一個月內,git會垃圾收集廢棄的提交。
有時,重新定基是“不好的”,因為它為共享git repo的其他人(直接或更有可能在您將工作推向某個中央存儲庫)創建了更多工作。 假設其他人通過E
提交了G
,並且他們做了更多的工作,例如在G
之上進行了H
提交。 然后,您去復制E
到G
,然后放棄原始的E
到G
您現在已經完成了他們的工作,提交H
,還需要更多工作:例如,他們可能必須將H
換成您的G'
。
如果沒有其他人擁有從E
到G
的提交,則可以確保沒有為不存在的其他人做任何額外的工作。 改頭換面只會影響您 ,因此大多數“不良”現象都會消失。
最后,對於重組與合並(如果合並,是否以及何時使用--no-ff
)與“壁球合並並放棄原始開發鏈”與其他任何問題都沒有唯一的答案-用。 在git中進行提交,並通過合並,精心挑選和重新定基等操作的整個想法是使維護工作變得更加容易。 除非使維護實際工作變得容易,否則所有對提交圖的擺弄都是毫無意義的。
好吧,我會盡力解釋...
當您將master重新建立在dev之上時:
A--B----C-----E---F----G-------------C1------C2
\ /
E---F----G-----------/
在此之后,您可以從master
轉到開發級而不會發生沖突
當您將開發基於基礎之上時:
A--B----C------C1------C2----
\
----C1------C2------E---F----G-----------
在此之后,您可以從dev
輕松掌握而無沖突
當您重新設置dev
分支而不是更改master
時,確保第二個變體會更好...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.