2016-11-15 77 views
3

在這個例子中,git並不認爲它需要重定位,但很明顯。爲什麼這個git rebase認爲沒有什麼可做的?

下面是一個簡單的腳本在這之後運行,以創建一個小型測試git倉庫

#!/bin/bash 
rm -rf testgit 
mkdir testgit 
cd testgit 
git init 
echo -e "a\nb\nc" > file 
git add file 
git commit -am 'first' 

git checkout -b lineA 
echo -e "A\nb\nc" > file 
git commit -am 'A' 

git checkout -b lineB 
echo -e "a\nB\nc" > file 
git commit -am 'B' 

git checkout -b lineC 
echo -e "a\nb\nC" > file 
git commit -am 'C' 

,這裏是file看起來像每個分支

master | lineA | lineB | lineC 
------------------------------ 

a  A  a  a 
b  b  B  b 
c  c  c  C 

現在,讓我們所有的分支機構合併成高手,之後file中的每個字母應該大寫

$ git checkout master 
$ git merge lineA 

好的。

$ git checkout lineB 
$ git rebase master 
Current branch lineB is up to date. 

什麼?不,主人改變了。

$ git checkout master 
$ cat file 
A 
b 
c 

$ git checkout lineB 
$ cat file 
a 
B 
c 

在我看來,分支lineB需要重新綁定,以將合併lineA所做的更改合併到master中。

爲什麼不git認爲這需要做?

此外,如果你這樣做

$ git checkout master 
$ git merge lineA 
Already up-to-date. 
$ git merge lineB 
... 
1 file changed, 2 insertions(+), 2 deletions(-) 
$ cat file 
a 
B 
c 
$ git merge lineC 
... 
1 file changed, 2 insertions(+), 2 deletions(-) 
$ cat file 
a 
b 
C 

這裏的合併應該發生衝突,但Git是悄悄重挫他們。我不知道這是否相關,但似乎很奇怪。

回答

2

的第一個命令

我們的腳本後的結果(縮寫支線的名字......):

master lA lB lC 
    ↓  ↓ ↓ ↓ 
first----A----B----C 

這些命令:

$ git checkout master 
$ git merge lineA 

結果一個快進合併,它只是將master指向與lineA相同的提交。

,並提供:

 master 
     lA lB lC 
     ↓ ↓ ↓ 
first----A----B----C 

沒有工作的底墊

因此命令序列:

$ git checkout lineB 
$ git rebase master 

是說移動lineB分支上的master頂部。

...但它已經在master之上。

master在其歷史記錄中必須有一些提交lineB沒有讓rebase命令有任何工作要做。

沒有合併衝突

當Git會創建一個合併提交它認爲正在進入合併父母的歷史。在這種情況下,兩個分支都指向提交一個公共鏈上的提交。 Git可以看到A提交發生在C提交之前的B提交之前。因爲Git認爲後面的承諾是在早期承諾之上增加的,所以它們不會發生衝突。

相反,如果你有一個像史:

 master 
     ↓ 
     ---A 
    /
    | lB 
    | ↓ 
first----B 

然後混帳會看到他們作爲發展的平行線。在這種情況下,合併lBmaster或反之亦然會發生衝突。這是因爲B不是歷史上的A的頂部的附加項,因此Git需要用戶輸入以瞭解要保留哪些更改。

+0

我想也一樣。使用git擴展來查看你的分支樹形狀。對於我來說,所有你創建的分支都有他們的主人,所以git以它的方式告訴你,不需要rebase。在這一點上,你只需要合併 –

1

我認爲你的困惑之處還在後面。當您執行

git commit -am 'first' 
git checkout -b lineA 

你沒有創建一個名爲lineA新的分支,但分叉點被提交你只是做了(「first」)。正如Git所說的,first是兩個分支歷史的一部分,並且在您的腳本中,這也是兩個分支中最近的提交。 Git的日誌有一些選項顯示兩個分支名稱指向第一個承諾,在本例中是提交ID 58b7dcf:

git log --graph --oneline --decorate 
* 58b7dcf (HEAD, master, lineA) first 

繼續:

echo -e "A\nb\nc" > file 
git commit -am 'A' 
git log --graph --oneline --decorate 
* ed40ed2 (HEAD, lineA) A 
* 58b7dcf (master) first 

日誌命令顯示提交A(ed40ed2 )現在是lineA上的最新提交,它的父提交是first,它仍然是master上的最新提交。如果您現在將lineA合併回master這將是一個快進(微不足道)合併,因爲沒有對master進行提交,因爲從lineA分支出來。同樣,重訂lineAmaster什麼都不做,除了報告

Current branch lineA is up to date. 

因爲最近提交的分支master(主分支的末端)仍然是分支lineA的歷史的一部分。持續:

git checkout -b lineB 
echo -e "a\nB\nc" > file 
git commit -am 'B' 
git checkout -b lineC 
echo -e "a\nb\nC" > file 
git commit -am 'C' 
git log --graph --oneline --decorate 
* 4033067 (HEAD, lineC) C 
* f742aed (lineB) B 
* ed40ed2 (lineA) A 
* 58b7dcf (master) first 

每個新分支都建立在最近一次提交的上一個分支上,沒有進行並行開發。繼續:

git checkout master 
git merge lineA 
Updating 58b7dcf..ed40ed2 
Fast-forward 

請注意這是一個快進合併,所以它所作的只是移動master到ed40ed2:

git log --graph --oneline --decorate 
* ed40ed2 (HEAD, master, lineA) A 
* 58b7dcf first 

最後:

git checkout lineB 
git rebase master 
Current branch lineB is up to date. 
git log --graph --oneline --decorate 
* f742aed (HEAD, lineB) B 
* ed40ed2 (master, lineA) A 
* 58b7dcf first 

您寫道:

什麼?不,主人改變了。

是,master改變了,但在某種程度上影響了lineBlineC歷史。 master快速提交ed40ed2,它已經是lineB的父項。確切地說,它是f742aed的父級,它是我爲提交B獲得的提交ID。

對於習慣於其他版本控制系統的人來說,混淆是Git爲提交記錄記錄了一個樹狀數據結構(技術上說是DAG),而不是分支名稱。分支是短暫的;它們只是標籤,就像可移動的版本標籤。提交之間的父子關係是您在和其他可視化工具中看到的內容。