2015-10-05 85 views
3

在移動到使用git的過程中,我們採取瞭解決方案的生產版本,並將其承諾爲主人如何將孤兒分支附加到主人「原樣」?

然後我們進行了一個開發版本,並提出所謂孤兒分支發展


(背景:爲什麼我們變得有點這裏糾纏不清的是,有沒有從開發版本到生產版本的全新進化再加上有一個複雜裝配解決方案參與,使我們。要避免報廢回購,並再次試圖在最後,我們只是想獲得這些版本爲混帳和內混帳開始清理)


所以 - 。現在,我們認爲這將有更好地分支開發版本n從而不是保留它作爲孤兒分支。

怎麼能我們基本上採取承諾,並使其成爲家長給發展提交但沒有任何合併發生?不改變第一個文件內容develop commit?

那就是 - 只是嫁接發展到它在某種程度上,原樣,如果讓任何意義嗎?

+0

'git rebase --onto master develop'? – siride

+0

在經歷了一些早期的混戰之後,我有了一種印象總是試圖融合的印象,我錯了嗎? 「 - 」停止了? –

+0

重新合併本身並不合併。但是,如果重新分配的分支中的提交引入了與已重新分配的分支中已經發生的更改相沖突的更改,那麼您將遇到合併衝突。從最初的原則來看這是不可避免的。我可以爲你的情況說的是嘗試它,並希望你沒有衝突。 – siride

回答

1

這聽起來像你想修改你的提交圖而不修改任何附加到這些提交的

如果您瞭解git如何在內部工作,此聲明將更有意義。這裏的關鍵項目有:

  1. 所有的提交是永久不變的,因爲一個承諾(或實際上Git的四個內部對象的話)「真名」是其內容的SHA-1 crypographic校驗。這意味着如果你試圖改變任何東西(或者一個失敗的磁盤驅動器改變了某些東西),git會抱怨錯誤的校驗和,因爲你在每個對象中看到的東西不再與它的「真實名稱」相匹配。

  2. 每個提交攜帶一個「樹」對象的SHA-1 ID,充當與該提交一起提交的源的完整快照。 (該樹給出文件名和SHA-1「真實名稱」,每個文件或目錄的子目錄由另一棵樹代表),

  3. 每個提交也列出其父母的「真實姓名」SHA-1 ID。因此,考慮到develop的提示,git可以讀取該提交併找到它的直接父代。讀這個父母(或那些父母),git會找到下一個ID,它爲父母讀取,等等。該過程在閱讀「根」提交時停止,該提交是沒有父母的提交。做一個--orphan簽出,然後進行提交會產生一個新的根提交,這無疑是你如何創建分支的。

這些家長和樹的ID,存儲在任何給定的承諾,被說成「點」的git倉庫中的其他對象。 (回購中只有四種類型的對象,我們已經提到過「commit」和「tree」,另外兩個是「blob」 - 這是git如何保存文件 - 和「標籤」。樹指向blob和sub - 樹和「標籤」對象用於註釋標記。)


因此,你想要做的是改變根提交您develop分支,以便它現在已有了一個父提交,特別是一些可從master分支的當前提示中獲得的提交。 (也許你想要提示本身,也許你想要的東西像master~100:這個細節只有當你去做改變時才重要。)

壞消息是因爲項目#1,你不能這樣做。

好消息是,你可以用這種方式使用三種替代方法中的任何一種(然後如果需要和期望使移植物永久化)。

首先,git有一個叫做「嫁接」的東西。他們工作得不是太好,所以git有一個更好的東西叫做「替代品」。根據你的git vintage,你應該至少有一個,幾乎肯定都是。

這些都使用相同的總體思路。由於git正在做它的圖遍歷,從提交到父進程,你希望在某個時候能夠讓git改變它的遍歷。使用git移植,你只需指定當對象的ID爲<X>它應該遍歷到父<Y>。這使您可以在當前的develop上找到根提交併將其直接移植到master中的某個提交中。

這些移植不會被git clone複製,並引入其他問題,所以現在git有git replace。這會在存儲庫中創建一個實際對象,並允許您檢查提交圖是否有替換。爲了在這種情況下使用它,你可以爲你的根提交做一個替換提交,這與現有的根提交完全一樣,除了它有你想要的父代。


如果你想改寫歷史完全,很容易使一個痛苦的一步改寫後的所有用戶,你可以建立一個移植物,然後用git filter-branch複製和替換移植。或者,也許稍微簡單些,指定一個父過濾器(並且沒有其他過濾器)。詳情請參閱the git filter-branch documentation;它就是這種情況的一個例子。 (該文件表明,創造了移植比較簡單,我想用--parent-filter是簡單的;但無論哪種方式,有一個簡便的事例)

注意,濾波器的分支副本每一個「過濾」承諾,與一些變化(通過(虛擬)檢查該提交,然後應用篩選器,然後從結果中創建一個新的提交。在這種情況下,第一個更改是將父ID添加到根提交。第二個更改是一個過濾器分支會自動執行:使提交跟隨將不再更孤立的根複製點指向根副本。第三個變化是相同的,第二,等等:

 A--B--C  <-- develop (before filtering) 

...--o--o--... <-- master 
     \ 
     A'-B'-C' <-- develop (after filtering) 

這裏,提交A'酷似提交A不同之處在於它有一個父ID; B'B完全相同,區別在於其父項爲A'而不是A;等等。 (請注意,順便提一下,這裏的父箭頭都指向左側,但filter-branch是從左到右工作的,它通過枚舉所有提交首先進行過濾,從右到左獲取它們的ID時尚,BU然後做左到右的過濾。)

This existing SO Q-and-A has a lot more on using grafts or replace.

我沒有提到上述的第三種方法。只有當develop沒有現有的合併提交時,此工作纔有效。然後,您可以簡單地將develop中的每個提交重新分配到您的目標提交中,如siride suggested in a comment。您需要運行--root的rebase命令,以便從獨立的develop分支的根目錄中複製每個提交。

這是可行的,因爲git rebase只是複製提交,與git filter-branch的方式大致相同。從某種意義上說,更多的工作是因爲方式 rebase複製提交是通過應用差異(或多或少地使用重複的git cherry-pick s)而不是簡單地保留每個複製提交的現有「樹」對象,但它的工作要容易得多git filter-branch。這裏的缺點是,rebase根本不處理合並提交(當然,除非你使用--preserve-merges,它使用交互式rebase代碼)。

+0

感謝您的幫助。嘗試了git rebase,但它與合併衝突回來了。可能你的--parent-filter方法會起作用。但是,如果你跟隨其他SO問題的鏈接,我發現這個「git reparent」腳本 - 看起來應該是我們想要的:https://github.com/MarkLodato/ git-reparent/tree/e886dc7e970f8c05ee7b82a6f8d855ffb7cc4d88 –

+0

根據文檔,該腳本只複製'HEAD'提交(這很容易,但如果您想要複製整個提交鏈,將無濟於事)。 – torek