9

I made a merge of a long lived branch and it took me time to complete the merge because of the conflicts resolution.

I found out that I cannot publish my work with git-svn: git svn rebase will rebase all the commits of the merged branch instead of submitting one single merge commit. I discovered git merge --squash a bit too late...

Is it possible to change (rebase interractive ?) the merge commit into a "squash merge" commit without loosing all the conflicts resolution work already done (i.e. without triggering a new merge as I had not enabled the rerere tool) ?

Marc
  • 599
  • 4
  • 9
  • 2
    I'd try to fork a temporary branch off the first parent of your merge commit and then `git cherry-pick -m 1 ` the merge commit onto it. If all would look OK, just reset the original branch to the result. – kostix Oct 04 '13 at 11:42
  • See [this](http://stackoverflow.com/a/9229393/720999) for more info on `-m 1` in the proposed `git cherry-pick` call. – kostix Oct 04 '13 at 11:43
  • possible duplicate of [What exactly does git's "rebase --preserve-merges" do (and why?)](http://stackoverflow.com/questions/15915430/what-exactly-does-gits-rebase-preserve-merges-do-and-why) – artless noise Sep 17 '14 at 21:26
  • The `git cherry-pick -m 1 ` solution as suggested by @kostix is the most robust solution here since it also preserves commit information. I have added it as an answer below. – SteveMellross Apr 04 '20 at 13:51

3 Answers3

7

Maybe git rebase --preserve-merges works for you.

Here a detailed answer of what is going on when doing that:

What exactly does git's “rebase --preserve-merges” do (and why?)

Please apologize that I don't like to copy&paste from there.

Community
  • 1
  • 1
villekulla
  • 959
  • 4
  • 14
  • This is deprecated. `--rebase-merges` is now preferred. https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---rebase-mergesrebase-cousinsno-rebase-cousins – Osama Arshad Dar Feb 24 '21 at 14:11
6

If you have merged and with git merge (--no-ff) and want to turn it into the equivalent of a git merge --squash, you can use the following process (assuming the merge commit is the most recent commit on the branch):

  • Ensure you have the affected branch checked out.
  • git reset --hard HEAD~1 (Resets the branch to the commit before the merge. Don't worry, it's not lost!)
  • git cherry-pick -m 1 HEAD@{1} (Cherry-picks the merge commit you just removed as a normal commit, based on the diff between it and this branch)

In addition to preserving any conflict resolution done during the merge, it will also preserve the original merge commit information (message, author, date, etc), making it very useful for fixing incorrect merges from tools like BitBucket that generate consistent commit messages.

We have a squash-commit only policy so I end up using this occasionally whenever someone accidentally selects the normal merge option from a BitBucket PR. Or clicks the frustratingly tempting "Merge" button on the Slack BitBucket bot that does not give you a choice of merge strategies...

SteveMellross
  • 2,969
  • 2
  • 18
  • 17
1

I was in a similar issue and was able to create a squashed commit by simply resetting and recommitting the change.

Starting layout:

*   06074985 (HEAD -> test1) Merge branch 'test2' into test1
|\
| * eb2aa088 (test2) test2 commit
* | c83180c8 test1 commit
|/
* b6628265 (master) base commit

git commands: git branch temp (so I don't loose the merge commit) git reset HEAD~1 git add . git commit -m "Squash commit" git diff temp (just to make sure nothing changed)

Ending layout:

* 5e229615 (HEAD -> test1) squash commit
| *   06074985 (temp) Merge branch 'test2' into test1
| |\
|/ /
| * eb2aa088 (test2) test2 commit
* | c83180c8 test1 commit
|/
* b6628265 (master) base commit
Cemafor
  • 1,611
  • 12
  • 27