2014-02-19 125 views
3

我有一個類似於下面的歷史記錄(但更復雜的幾個合併):衍合合並樹的Git

 F - G - H - K - L - … 
    /  /
    /  I - J - M - … 
    / /
A - B - C - D - E - … 

A′- B′- C′- D′- E′ 

A和A'是具有不同的歷史相同的樹。

我要變基所有分支提交對主要分支相當於提交,(通過手動指定相當於提交都在重建基礎樹在哈希大概)保留合併。我如何告訴K′它需要從H′J′合併?或者我必須手動重新創建這些合併提交?

如果我做git rebase -p --onto B′ B L它無法乾淨地應用。我可以將H重新分配到B′MD′,然後重新創建合併K我自己,然後將L重新分配到K′(對於其他分支/合併等未顯示),但這將是一個公平的工作。

我看過severalotherquestions但他們都沒有合併。

+0

您的回購是私密的,還是可以在GitHub上公開訪問?如果它是公開的,人們可以直接看一看。 – 2014-02-19 19:50:37

+0

如果這是一個私人回購,那麼你應該可以用'git filter-branch --parent-filter ... --all'來完成這個工作,其中父過濾器的腳本標識爲'B'並且聲明它是新的父母應該是'A''而不是'A'。您可能會想要添加一個'--tag-name-filter cat'來保留您正在重寫的部分中的任何標籤。但如果是公共回購,這可能是不明智的。看起來你也可以使用'--commit-filter',但它更通用... – twalberg

回答

3

假設這不是公共存儲庫,或者存儲庫的任何其他用戶都可以進行重大重寫,最有效的方法是使用git filter-branch。其中一個可能的過濾器是--parent-filter,它允許您更改特定提交的血統,有點類似於移植或重新綁定樹的一部分,但由於您也可以通過--all選項,因此您可以在多個分支中完成一次調用。這也可以通過--commit-filter來完成;但這是一個更通用的解決方案,旨在改變個人承諾的其他方面 - 而不僅僅是父母。您可能還想使用--tag-name-filter cat移動正在重寫的樹部分中的任何標記。

所以最後的命令將類似於:

git filter-branch --parent-filter <somescript> --tag-name-filter cat -- --all 

其中<somescript>要麼適當引用/逃脫bash代碼A'更換AB提交(細節上的信息究竟是如何提供給腳本以及腳本的結果應該在git help filter-branch中找到),或者實現相同腳本的實際shell腳本的名稱。

之後還有一些清理工作要做 - filter-branch將您的原有分支留在原地,但使用新名稱(refs/original/...),因此如果某些東西看起來不正確,您可以恢復。當你滿意filter-branch做了你想要的並且重新打包你的存儲庫以恢復存儲空間時,如何清除死分支有很多信息,所以我不會在這裏複製它...

+0

因爲該標誌被髮送到子命令,所以我在'--all'標誌前需要一個雙破折號:'git filter- branch -f --parent-filter'test $ GIT_COMMIT = HASH_OF_B && echo「-p HASH_OF_A_PRIME」||貓' - - 都',但否則它的工作。謝謝。 –

+0

啊,是的,忘了那部分 - 爲後代編輯它.... – twalberg

1

您是否嘗試過使用交互式重新綁定?基本上,做git rebase -i A,git會在列出A後提交你的文本編輯器。然後,您可以將提交和壓縮轉移到對方的內容中。