2014-03-31 323 views
1

我讀這篇文章http://supercollider.github.io/development/git-cheat-sheet.html,其中提出以下工作流程:Git合併後git rebase?

git checkout master 
git pull --rebase # update local from remote 
git rebase master chgs 
git checkout master 
git merge chgs 
git push 

我敢肯定,我不明白這是如何工作以及爲什麼它是有用的。

沒有第三行,git rebase master somechanges,把從chgs提交後最後從master,但沒有將它們合併提交,並留下HEAD指向最新從chgs犯,像這樣:

(master-commit-n-1)<--(master-commit-n)<--(chgs-commit-k-1)<--(chgs-commit-k)<--HEAD 

不那離開我chgs簽出?這就是爲什麼我需要再次檢查master

爲什麼我們需要將更改合併到主?這不是一個這樣的圖表:

(master-commit-n-1)<--(master-commit-n)<--(chgs-commit-k-1)<--(chgs-commit-k) 
             \.(master-with-merged-chgs-commit-k)<--HEAD 

我不明白爲什麼頂叉是有用的。

回答

2

爲了:

不第三行,git rebase master somechanges,把後終於從chgs承諾從master,但沒有將它們合併犯...

是,假設somechangeschgs的錯字(參考頁面使用更多拼寫)。

和葉HEAD指向最新從chgs

是承諾,但只是間接的:HEAD字面上包含ref: refs/heads/chgs,即,如果只剩下分支chgs簽出。這是chgs本身,指向最新的提交。

這是否使我離開chgs簽出?

是的。

具體來說,「當前分支」,在一個打印爲on branch ...當您使用git status,只是無論refs/heads/branch是文件HEAD中,當HEAD包含refs: refs/heads/branch。首先運行git checkout branch確保可以更新工作樹,然後通過重寫HEAD來完成此操作並將其置於該分支上。

在內部,git rebase upstream branch調用git checkout branch,所以整個過程開始讓你在分支上。

爲什麼我們需要將更改合併到主?這不是像[剪輯]一樣的圖表嗎?

你需要的merge移動的標籤。

我更喜歡用字母或有時候只是一點一點地繪製提交圖表,用它們之間的單個破折號或短箭頭表示父母關係。並且,從git log --graph --oneline --decorate中偷取(但修改)一片葉子,我用更長的箭頭在右側添加分支名稱。如果HEAD命名分支,我在前面添加HEAD=

你有什麼之後作爲底墊由此可以得出:

... - E - F    <-- master 
      \ 
       G - H - I <-- HEAD=chgs 

這裏提交標記F是分支master的頂端,所以masterF(和F點回E等上)。分支chgs的提示是提交I; I積分返回H; H積分返回G;並且G指向F。當然HEAD=chgs所以你在那個分支。

一旦你git checkout master,像往常一樣更新你的工作樹,並使HEAD指向master指向F。然後,如果你運行git merge chgs,Git會查找,看是否有可能做一個「快進」合併:

... - E - F    <-- HEAD=master 
      \ 
       G - H - I <-- chgs 

一個快進合併有可能在當前提交(F,在這種情況下)已經是一個祖先的目標提交(I)。如果是這樣,分支標籤揭下當前提交和簡單粘貼到目標承諾:

... - E - F 
      \ 
       G - H - I <-- chgs, HEAD=master 

(現在,已經沒有任何ASCII藝術-理由將扭結在繪圖[從F下和但是我保持它的視覺對稱。)

作爲Cupcake noted in his faster answer,您可以強制與--no-ff真正合並。我會得出這樣的:

... - E - F ------------- M <-- HEAD=master 
      \   /
       G - H - I  <-- chgs 

在這兩種情況下(快進,或「真正合並」),一旦做到這一點,你可以安全地刪除分支標籤chgs,其所有提交的被發現可以從master開始並向後工作(如果是「真正的合併」,則沿着兩個分支)。或者,如果您願意,您可以保留它並添加更多提交。

這裏一個有趣的注意的是,在這種特殊情況下與相關的產生工作樹提交M是完全一樣的一個提交I。關鍵的區別是,這會創建一個實際的合併提交(與多個父代一起提交)。第一個父節點是之前在分支上的任何提交 - 在這種情況下,提交F - 並且剩餘的提交(這裏是一個提交I)是要合併的分支。(你可以覆蓋這個 - 工作樹是相同的,我的意思是 - 有更多的合併標誌,但在這種情況下,你不會想要這樣的事情,重寫工作樹,主要是意味着「殺死」的一個分支,同時保留了歷史:排序的「看,我們嘗試這樣做,也沒有工作」的消息給某人明年看代碼)


。或者不需要,如果你不想移動標籤。但是,如果您打算將push工作返回給某人,或者讓他們從您那裏獲得,他們會查看您的標籤。如果你爲他們安排好標籤,這對他們很好。但這總是取決於你。

3

#1

沒有第三行,git rebase master somechanges,把從chgs 提交後最後從master,但沒有將它們合併提交,並留下HEAD 指向最新從chgs犯,像此:

(master-n-1) <- (master-n) <- (chgs-k-1) <- (chgs-k) <- HEAD 

衍合chgs到0123的作用相當於將master合併爲chgs,因爲上次提交時您的代碼的狀態將等於merge之後的狀態。

#2

,這是否給我chgs簽出?這就是爲什麼我需要再次檢查 master

是的。

#3

,爲什麼我們需要合併變爲主人?不使圖形 這樣的:

(master-n-1) <- (master-n) <- (chgs-k-1) <- (chgs-k) 
          \ 
          (master-with-merged-chgs-k) <- HEAD 

號因爲你的master頂部重建基礎chgs,git會認識到,最後一次提交的chgs有效地代表master「+」 chgs狀態,所以它只是「快進」的master分支的chgs尖端而不進行合併提交:

(n-1) <- (n) <- (k-1) <- (k) <- HEAD/master/chgs 

如果你想混帳做,而不是合併提交,你可以通過--no-ff標誌merge

git merge --no-ff chgs 

# Results in this 

(n-1) <- (n) <- (k-1) <- (k) <- chgs 
      \    \ 
       --------------(merge) <- HEAD/master 

#4

我不明白爲什麼上叉是非常有用的。

這對更新功能分支的上游更改從master更新很有用,不會在功能分支中創建一堆冗餘合併提交。最終的結果是,您的開發歷史變得更簡單,更容易處理,而不是包含一些您並不真正需要的額外合併提交,而這些合併提交只會使歷史更加複雜且難以操作。

1

下面更詳細地解釋這些命令中的每一個在做什麼。

GIT中結帳主

切換到master分支。

假設本地,我們有這個(其中*表示當前分支):

M1 -- M2 = master* 
     \__ C1 = chgs 

混帳拉--rebase

從遠程分支更新本地master分支,重定義對master分支所做的任何本地更改,以便它們在遠程更改之後發生。

假設這給了我們一個新的M3變化:

M1 -- M2 -- M3 = master* 
     \__ C1 = chgs 

git的重訂主CHGS

底墊從本地chgs分支的變化,使他們從本地遵循master分支(但留在他們自己的分支)。也更改爲chgs分支。

M1 -- M2 -- M3 = master 
      \__ C1' = chgs* 

GIT中結帳主

切換回所述master分支。

M1 -- M2 -- M3 = master* 
      \__ C1' = chgs 

混帳合併CHGS

梅傑斯chgsmaster

M1 -- M2 -- M3 ------- M4 = master* 
      \__ C1' __/ = chgs 

混帳推

推這些變化原點。