gitrebasegit-rebasegit-rewrite-historygit-branch-sculpting

How to avoid rebase hell when merge commits are in the way?


I've got the following situation in my git tree:

1 -- 2 -- 3 -- 4 <-- master
      \         \
       5 -- 6 -- 7 -- 8 -- 9 <-- feature

I want to rebase and squash everything from feature so that I can advance master with a single commit of the feature being added.

Being that commit 7 is already a merge that solves all the conflicts, I tried the following:

git rebase -i -p master

The only options that were given me here were commits 7, 8 and 9. "Makes sense", I thought, "since the merge already includes 5 and 6, they can just be discarded". I proceeded to squash 7, 8 and 9 in a single commit we'll call "789". (I know, I'm the creative type.)

After this my tree looked like this:

1 -- 2 -- 3 -- 4 <-- master
                \
                 5 -- 6 -- 789 <-- feature

The presence of 5 and 6 in the same branch confused me, but again, since they were already included in 7 (which is now in 789), I could just discard them.

So I git rebase -i master again and this time I discarded 5 and 6.

However, conflicts arose here and there, so I aborted the whole thing.

I am currently at that stage but my remote branch hasn't been updated, so I may as well do a reset to the original state.

Which are the right steps that will land me where I want to without having to manually resolve all merge conflicts?


Solution

  • I want to rebase and squash everything from feature so that I can advance master with a single commit of the feature being added.

    This is exactly what the --squash option for git merge does. From the docs for git merge:

    --squash

    Produce the working tree and index state as if a real merge happened (except for the merge information), but do not actually make a commit or move the HEAD, nor record $GIT_DIR/MERGE_HEAD to cause the next git commit command to create a merge commit. This allows you to create a single commit on top of the current branch whose effect is the same as merging another branch (or more in case of an octopus).

    (Emphasis mine)

    Usage example:

    git checkout master
    git merge feature --squash
    git commit