[英]How to “squash” subsequent merge commits
在我的項目中,我有這樣的歷史:
b --- c --- g
/ \ \
a f --- h --- j
\ / /
d --- e --- i ----
我想刪除中間合並提交,並且只有一個具有相同內容的合並提交,例如:
b --- c --- g
/ \
a j'
\ /
d --- e --- i
一種方法是從頭開始重做所有事情,但f
有 ca。 600 個沖突文件, g
實際上又是 200 個新提交,我不想再花一周時間解決沖突。 我如何實現這一目標?
如果我知道分支結構,我也許可以更清楚地解釋這個過程,但通常你會這樣做:
你真的只需要在g
和i
之間創建一個新的合並,因為當你繪制它時,你想要刪除的合並都不在g
或i
的歷史記錄中,並且所有相關更改都在任何一個的歷史記錄中g
或i
(即被刪除的部分只是合並提交[1])。
你不想重做所有的沖突解決,但這沒關系,因為你已經知道合並的期望結果。 因此,您需要制作父母為g
和i
的j
的副本。 至少有兩種方法可以做到這一點。
最直接的方法是使用管道命令,因此它可能看起來不太熟悉。
git checkout $( git commit-tree j^{tree} -p g -p i -m "merge message here" )
git branch -f my_branch
其中my_branch
是您當前在j
處擁有的分支,而j
g
和i
是解析到圖表中相應提交的表達式。 (這可能是提交 iD (SHA) 值、當前指向這些提交的 refs 等)
請記住,提交的父項是有序的——第二個-p
選項標識了似乎已經“合並”到第一個-p
選項的提交中的提交。
另一種方法是檢查g
(假設g
應該是第一次提交;否則在此過程中交換g
和i
),並且
git merge --no-commit i
git rm -rf :/:
git checkout j -- :/:
git commit -m "merge message here"
在這種方法中,您將啟動新的合並,清除工作樹和索引,從先前的合並結果加載提交樹和索引,然后完成與該內容的合並。
我發現這涉及更多一點,它包含一個rm
命令,如果您對正在發生的事情沒有信心,它可能會引發危險信號,但它具有堅持使用針對最終用戶的命令的優勢。
[1] 我有點假設合並沒有引入新的變化(除了沖突解決)。 如果他們這樣做了,他們就是有時被稱為“邪惡合並”的東西; 實際上,上面的過程仍然有效,但它會導致您的新合並也成為“邪惡合並”。
我能想到的能夠一次性完成的唯一方法是使用git commit-tree
。 首先,使用 git cat-file 獲取 J 版本的樹的 ID:
git cat-file -p j
復制樹 object 的 id。
然后運行 git 提交樹,您可以使用 -p 提供 2 個父修訂,使用 -m 提供注釋,並且您從之前的 git 命令獲得的樹 id 將用作調用的最后一個參數。
git commit-tree -m 'Here's the comment" -p g -p i tree-object-of-j
當您運行該命令時,git 將打印出創建的新修訂版 object 的 id。 您可以將分支指向它,或者如果您已經檢查過版本是否只是您想要的,則移動 j 指針:
git branch -f j new-revision-of #move j branch to the new revision id
您將成為修訂的作者....如果您想更改日期或作者,您可以通過設置環境變量來實現。 檢查git help commit-tree
。
這是執行此操作的一種方法:
git reset --hard g //reset branch to g commit (use 'i' and merge 'g' if the branch originally came from i)
git merge i --no-commit
git reset j :/: //resolve all conflicts by replacing the staging area with all file versions from original commit j
git commit
optional: git reset --hard //if you want the work tree to reflect the new merge commit
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.