Jani
Jani

Reputation: 557

Git master rebase master with branches

I have the following git structure.

            G - H - I <-feature-branch 1
          /
- A - B - C <-master
           \       
             X - Y <-feature-branch 2

My problem is that initially I have been committing to my master branch instead of either of my feature branches. Now, both of my features are ready to be merged, but my master is not tracking the upstream, so merging is very tricky and in the current state, either of the features must be merged in order to easily merge the other one. I would like to reset my master to be identical with upstream and push all the changes to either of the feature branches. The other feature should be derived from master as well. So, in graphical terms, I would like to have this:

    G - H - I <-feature-branch 1
   /
- A <-master
   \       
    B - C - X - Y <-feature-branch 2

Thank you!

Upvotes: 1

Views: 222

Answers (3)

Mark Adelsberger
Mark Adelsberger

Reputation: 45819

Existing answers may get you to your desired state; but you went to the trouble of spelling out your reasoning, so I think it's worth a second to first check assumptions.

You say that in your current state, merging both branches is tricky... but really, it's not. Starting from

            G - H - I <-feature-branch 1
          /
- A - B - C <-master
           \       
             X - Y <-feature-branch 2

merging the features to master is easy. The first merge could (and by default would) be done as a fast-forward; even if you force it to be a true merge instead of a fast-forward, it would still be trivial; and then (either way) the second merge is straightforward. (The only possible complication is if the branches are in significant conflict, in which case this approach still allows for the minimum amount of effort to resolve such conflict.)

That may or may not result in the desired commit topology; but you haven't really explained what you want that to look like after the merges (or why); you've only described an intermediate state that you think you need to get to first.

my master is not tracking the upstream

It's not clear what you mean by this. Do you just mean that the local master is ahead of the upstream? Since you'll ultimately move both the local and remote master branches forward to the merges you create, that makes basically no difference.

either of the features must be merged in order to easily merge the other one

What makes you think that? The first merge of either one to master, from the state you describe, will be very easy.

You say you want to get to a state like

        G - H - I <-feature-branch 1
       /
... - A <-master
       \       
        B - C - X - Y <-feature-branch 2

That actually is impossible; Gs parent is C, and you can't "change" it to make its parent A. Instead you would replace it (and the commits derived from it) so you'd get

        G' - H' - I' <-feature-branch 1
       /
... - A <-master
       \       
        B - C - X - Y <-feature-branch 2

That may be important, because it means you'd be editing the history of feature-branch-1. (History editing is a perfectly useful tool in git, but it does have costs you need to understand if you're going to use it, especially if others share the upstream repo with you.)

But the real question is, what does removing B and C from feature-branch-1's history actually gain you? In the event changes from G, H, or I overlap with changes from B or C, you will get conflicts as you try to do this; and to resolve those conflicts, you'll make new changes that will create additional conflicts when you merge everything back together at the end. Even if those changes don't overlap/conflict, if anything in feature-branch-1 depends (intentionally or otherwise) on anything in A or B, then your branch will be composed of broken commits, which could hinder bug-hunting in the future.

There may be other considerations in what you want the final history to look like, but given only the reasoning you've outlined, what I would do is simply

git checkout master
git merge feature-branch-1

which would work automatically and would result in

... - A - B - C - G - H - I <-(feature-branch 1)(master)
               \       
                 X - Y <-feature-branch 2

and then

git merge feature-branch-2

giving you

... - A - B - C - G - H - I - M <-(feature-branch 1)(master)
               \             /
                 X -------- Y <-feature-branch 2

Since all operations resulted in branches moving forward only, pushing would then update the remote cleanly.

Upvotes: 0

xyzale
xyzale

Reputation: 795

So first you have to reset your master to A:

git checkout master
git reset A --hard

where obviously A is the commit hash you want to reset to.

At this point the branch-2 is in the exact state you want. The branch-1 history still contains the commits B and C though.

In order to rewrite the history you have to rebase interactively on top of master:

git checkout branch-1
git rebase -i master

You will be prompted the list of commits between your branch and the master with your default git editor (usually vim or nano).

Just delete the rows B and C, save and quit.

Now you'll have the result you designed.

I hope this helps.

Upvotes: 1

Alim &#214;zdemir
Alim &#214;zdemir

Reputation: 2634

Since your feature branches have the same starting point, and 'either of the features must be merged in order to easily merge the other one' i.e. both have things needed from each other why not:

  1. merge feature branch 1 with 2 (X for reference)
  2. rebase X on master
  3. merge X to master

and have after 2.

- A - B - C <-master
           \       
             G - H - X - I - Y - I <-feature-branch X

and after 3.

- A - B - C - G - H - X - I - Y - I <-master

Upvotes: 0

Related Questions