gitmergesquash

Squash a merge commit with a previous commit


I have three branches:

The main and dev branches have some changes in conflict. I created the topic branch off main to work through the merge and resolve conflicts before merging to main.

* commit 81c8a07d2026acfe7e26ae9a5a54a0c65f800a4d (dev)
| Author: Jason <red@ct.ed>
| Date:   Tue Dec 24 14:26:02 2024 -0600
| 
|     conflicting change on dev
|   
| * commit 2b973eacc6c0e58abeeff6a5d057fab684803baa (HEAD -> main, topic)
|/  Author: Jason <red@ct.ed>
|   Date:   Tue Dec 24 14:25:12 2024 -0600
|   
|       change on main
| 
* commit 92f448fa59fb1d5c1098d31c5ea7c291632e4a44
  Author: Jason <red@ct.ed>
  Date:   Tue Dec 24 14:24:51 2024 -0600
  
      merge base

Both main and topic point to the same commit.

I wanted to merge dev into topic.

While on main (mistakenly), I started a git merge dev and worked through 50 files of merge conflicts. All conflicts were resolved and staged.

Immediately before I completed the merge, I realized that I was on the main branch when I wanted to be merging to the topic branch, so I did git checkout topic (while the changes were staged to be merged). Then I completed the merge.

What I ended up with was this:

* commit 8dc19c8bcf6a9c4ba3f25399bb05bd42381e1702 (HEAD -> topic)
| Author: Jason <red@ct.ed>
| Date:   Tue Dec 24 14:28:29 2024 -0600
| 
|     resolved conflicts merging dev into main
| 
* commit 2b973eacc6c0e58abeeff6a5d057fab684803baa (main)
| Author: Jason <red@ct.ed>
| Date:   Tue Dec 24 14:25:12 2024 -0600
| 
|     change on main
|   
| * commit 81c8a07d2026acfe7e26ae9a5a54a0c65f800a4d (dev)
|/  Author: Jason <red@ct.ed>
|   Date:   Tue Dec 24 14:26:02 2024 -0600
|   
|       conflicting change on dev
| 
* commit 92f448fa59fb1d5c1098d31c5ea7c291632e4a44
  Author: Jason <red@ct.ed>
  Date:   Tue Dec 24 14:24:51 2024 -0600

      merge base

What I wanted was a merge commit. What I got looks like a "squash" commit. Basically, git forgot I was doing a merge when I checked out topic.

To fix this, I want to make 8dc19c8b into a merge commit pointing to main and dev.

I do not want to rewrite history and repeat the merge because I already worked through all of the merge conflicts.

I thought to perform another merge from dev to topic, and use the ours strategy to use what I already resolved in topic. So what I have now is this, with no differences between HEAD and 8dc19c8b:

*   commit 4ccc77ebef6113c64f83d44d06f773a7b83f807e (HEAD -> topic)
|\  Merge: 8dc19c8 81c8a07
| | Author: Jason <red@ct.ed>
| | Date:   Tue Dec 24 14:30:34 2024 -0600
| | 
| |     Merge branch 'dev' into topic
| | 
| * commit 81c8a07d2026acfe7e26ae9a5a54a0c65f800a4d (dev)
| | Author: Jason <red@ct.ed>
| | Date:   Tue Dec 24 14:26:02 2024 -0600
| | 
| |     conflicting change on dev
| | 
* | commit 8dc19c8bcf6a9c4ba3f25399bb05bd42381e1702
| | Author: Jason <red@ct.ed>
| | Date:   Tue Dec 24 14:28:29 2024 -0600
| | 
| |     resolved conflicts merging dev into main
| | 
* | commit 2b973eacc6c0e58abeeff6a5d057fab684803baa (main)
|/  Author: Jason <red@ct.ed>
|   Date:   Tue Dec 24 14:25:12 2024 -0600
|   
|       change on main
| 
* commit 92f448fa59fb1d5c1098d31c5ea7c291632e4a44
  Author: Jason <red@ct.ed>
  Date:   Tue Dec 24 14:24:51 2024 -0600
  
      merge base

How can I squash 4ccc77eb and 8dc19c8b into a single merge commit?


Solution

  • You can rewrite the parents of the current commit (not the "extra merge" commit with no changes) with

    git branch tmp
    git reset $(git commit-tree HEAD: -p topic -p dev <<<"temp")
    git commit --amend -C tmp
    git branch -D tmp
    

    It's easier to create the temporary tmp branch than to write the command to perfectly collect the existing commit message and date.