Back

Explore Courses Blog Tutorials Interview Questions
+1 vote
2 views
in DevOps and Agile by (19.4k points)

I have a classic situation: I merged a dev branch into master, then realized I made a mistake and reverted the merge. Then added a fix into dev and want to merge it again. Of course, I cannot merge it directly, since, from git's point of view, it was already merged.

Classic solution

Revert the revert commit, apply your fix. Move on.

Pros: simple.

Cons: history is spoiled. It is very hard to blame deeper than this revert of the revert.

What I want

I want to rebuild the dev branch from scratch and merge it again. Should be easily done with git rebase --force-rebase, according to the books. But the branch history was not so simple and contained a number of merges, including merges from master. I want to respect these.

Let's have an example already:

                                     master|

                                           v

-*------------X-----Y---------*-----*----M-W

  \          /       \         \   /    /

   \        /         \         -*-    /

    \      /  -D-      G--H--         /

     \    /  /   \    /      \       /

      A--B--C-----E--F--------I-----J

                                    ^

                                    |dev

The faulty merge is M. Its revert is W. I assume that commits on dev up to B are ok, since B was merged into master as X. I want to rebuild the branch starting from B with exactly the same topology. See the tree below. New commits are marked with the prime. You can see how commits C..J were rebased to C'..J'. Correspondingly, dev is rebased to dev'. Other commits did not change.

                                dev'|

                                    v

            C'----E'-F'-------I'----J'

           / \   /    \      /        

          |   -D'      G'-H'-           

          |           /                    |master

          |          /                     v

-*--------+---X-----Y---------*-----*----M-W

  \       |  /       \         \   /    /

   \      | /         \         -*-    /

    \     |/  -D-      G--H--         /

     \    /  /   \    /      \       /

      A--B--C-----E--F--------I-----J

                                    ^

                                    |dev

Then I'll apply my fix K and merge this new branch to master:

                                dev'|

                                    v

            C'----E'-F'-------I'----J'--K

           / \   /    \      /           \

          |   -D'      G'-H'-             \

          |           /                    \ |master

          |          /                      \v

-*--------+---X-----Y---------*-----*----M-W-M2

  \       |  /       \         \   /    /

   \      | /         \         -*-    /

    \     |/  -D-      G--H--         /

     \    /  /   \    /      \       /

      A--B--C-----E--F--------I-----J

                                    ^

                                    |dev

Pros: good history.

Cons: I don't know how to do this.

Ok, seems like rebase has an option for this, and it is called --rebase-merges. But it does not do what I want. It rebases all commits, that are ancestors of dev and descendants of B. Which includes commits X and Y. Which are on master already, why would I want them? (Actually, it also brings some other commits from the more ancient history, and I don't understand why yet, but it's not the point here).

Instead, I want to bring commits, that are ancestors of dev but not master (considering master before the faulty merge of course). Sounds really easy to me. Yet I don't understand how to do it, except by manually constructing this difference of commits and somehow cherry-picking them by hand, carefully preserving parents.

So, how do I rebuild my branch, containing only work done on my branch and respecting merge commits?

P.S.: We cannot simply reset master to M^, that would be too easy.

1 Answer

0 votes
by (27.5k points)

The following commands worked for me: 

git rebase --interactive --rebase-merges B dev

reword C

Browse Categories

...