gitgit-mergegit-rebasegit-merge-conflict

Git Rebase Dilemma: Sort out the tangled feature branches


I had a feature branch which was based off of develop, let's call it feature-1. At the same point in time I also took another feature branch feature-2.

feature-1 was a real feature branch that I've had some serious changes going on there. feature-2 was a simple branch for some github workflows breaking up.

I've made one workflow change onto feature-2 and pushed to the remote repository (feature-2 on remote); this change also merged back into develop. I took another feature branch (out of blue moon for reasons I couldn't even remotely recollect), feature-3, for some more github workflows changes...

At the same point in time, as I was taking branch feature-3, I merged the latest develop change (one commit from feature-2) into feature-1. feature-3 has made 6 commits since then. I had to admit that I forgot there were 6 commits on the remote develop, which I thought I had already pulled into local develop. These 6 commits were merged into develop from feature-3.

Above is the relatively untangled part of the graph. During the process (I couldn't figure out exact point in time, I think I need some help here), I did a rebase from feature-1, onto develop; this however caused some conflicts, resulting in duplicate set of merges from feature-1 (typical commit message would be, "merged feature-1 from origin into feature-1"). IIRC, I did rebase twice.

Off the top of my head, I'm thinking I'll merge the half-done feature-1 into develop first, and take a fresh branch from merged develop for a new start; or I could take a branch right away from develop, then cherry-pick commits from feature-1, and leave the messed-up feature-1 behind for my peace of mind.

Is there, another way to tackle this? Let me be naive but for example gracefully untangle the twins in the graph, or make the tangled threads disappeared somehow?

The best practice, as I vaguely recall, was to only rebase my local branch which contains local commits only onto a shared main branch; if I have pushed my changes to a remote repository(say my remote equivalent of the local branch), I should not use rebase. It is true, in my mind, that only if I had shared this branch with other co-workers. In my case they were all just my branches so I carelessly pushed changes to remote repository before I did one of the rebase (more importantly the first rebase).

Here's my try at replicating the graph, I've marked with letters the duplicated commits. In the graph you'll see that the rebase seemed to have happened on feature-1 only, i.e., feature-1 rebased onto feature-1. This is also something that baffles me.

*---------*----------------------------* [develop]
|        /|                           /
|-------a |-----------*--*--*--*--*--* [feature-2(merged), feature-3(merged)]
|         |
|-----*---|-----------------------------a--b--c--d--e----c--d--e--f [feature-1]
|     |    \                                         \           /
|-----|-----b--c--d--e--------------------------------f----------   [feature-1,duplicate]


Solution

  • If feature_1 was not pushed, or if you are the only one working on it, do not hesitate to rebase it first locally, before merging it to develop.

    In your case, the key command is git rebase --onto <newbase> parent-commit end-commit: it allows you to move a range of commits (the ones after parent-commit all the way to end-commit included)

    At any point (provided your current status is clean), you can do:

    git switch develop
    git pull
    git rebase --onto develop a~ feature-1
    # resolve potential merge conflicts
    

    That will give you:

                                             ---a--b--c--d--e----c--d--e--f [feature-1]
                                            /
    *---------*----------------------------* [develop]
    |        /|                           /
    |-------a |-----------*--*--*--*--*--* [feature-2(merged), feature-3(merged)]
    
    

    Then you can merge (git merge --no-ff if you want a merge commit) to develop.
    And then push.