How do I compress multiple merges into a single merge?

浪子不回头ぞ 提交于 2019-12-08 02:03:40

问题


I have a topic branch that looks like this. (the branch topic currently points at 'a0a0')

  • a0a0 Merge branch 'Master' into topic
  • b1b1 Merge Branch 'Master' into topic
  • c2c2 Merge commit 'something from master' into topic
  • d3d3 Merge Branch 'Master' into topic
  • e4e4 Merge Branch 'Master' into topic
  • f5f5 Merge Branch 'Master' into topic
  • 6666 an actual commit
  • [lots of history on the topic branch]
  • 9999 original divergence point

How do I turn a0-f5 into a single merge commit?

I've tried: git rebase -i f5f5 with the intention of telling it to squash those 5 commits, but instead it just gave every commit on the master branch between f5f5 and a0a0. So I turned all but the first and last from pick into squash, but that went crazy and rebased every single commit from master into a giant commit in place of all the merges, losing the fact that it was a 'merge'. That isn't what I expected!

I can do:

  $ git reset 6666
  $ git merge Master

but that requires me to re-do any merge commits.

So how do I compress those different merges into a single merge commit, that knows it's a merge, and also retains all the merge-conflict stuff?


回答1:


This will do it:

git reset --hard $(git commit-tree -p f5f5 -p Master -m "Merge hurricane" a0a0:)

To understand how it works, first remember that there is absolutely nothing magical about a merge commit. It can be hard to create, but once created, it's embarrassingly easy to recreate exactly. This is because git doesn't record changesets, it records entire trees. Tools like git show display commits as diffs, and merge commits as very fancy diffs, but in reality a commit is the pointer to a full-fledged tree. Squashing some commits is a simple matter of recreating a new commit that contains the same tree, giving it a different parent and commit message.

The plumbing command git commit-tree does this last part. Given a parent commit (f5f5), a commit message, and a tree ID (easily referenced with COMMIT:), it creates a new commit that contains the specified tree. If the commit has a single parent, it will be a regular commit. If it has multiple parents, it will be a merge commit. Once the squashed merge commit is created, what remains is to point the current branch to the new commit with git reset --hard.




回答2:


Try this:

git checkout 6666 -b master_squashed
git merge --squash master
git commit -m 'My new feature'
git checkout master
git merge master_squashed



回答3:


A late answer:

git diff 6666 f5f5 > patch-f5f5.patch
git checkout 6666
git apply patch-f5f5.patch

As you prefer, you may also use git apply --cached or git apply --index which allow you to make further modification before commit.



来源:https://stackoverflow.com/questions/13029516/how-do-i-compress-multiple-merges-into-a-single-merge

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!