8

My git branches look like this:

master-*-*-*-*-*-*-implement_x
 \                    \-*-further_foo_fixes_that_depend_on_x
  \                    \-*-*-further_bar_fixes_that_depend_on_x
   \
    \-implement_x_rebased

It ended this way, because I thought my branch implement_x would be merged upstream as it is, but I was asked to squash it to a single commit, thus implement_x_rebased. However, I already started several branches for further fixing and developing that depend on my work, while waiting for the implement_x to get merged.

Now I'd like to rebase the further work on implement_x_rebased. I thought this was a no-op, since implement_x and implement_x_rebased were in the exactly same state - there would be no merge conflicts, just applying the changes between implement_x and further_foo_fixes_that_depend_on_x etc. on top of implement_x_rebased. However, it seems that git isn't that smart, and it tries to rebase all the way from the base - introducing needless merge conflicts.

I thought that the easy way out is rebase&squash the further fixes on implement_x and then stash them, and apply the stashes to implement_x_rebased, but I'm curious whether there is any proper way to make git realise that implement_x and implement_x_rebased are actually in the same state?

GolDDranks
  • 3,272
  • 4
  • 22
  • 30
  • I don't know perfect answer for this question but cherry-pick is also one of options. – shirakia Dec 12 '14 at 14:43
  • Ah. Cherry-picking is definitely easier and better than manually applying some diffs. I'm still waiting for answers that directly answer my question, but if there isn't any for I while, I'll accept that if you post it. – GolDDranks Dec 12 '14 at 14:48
  • Please check `git rev-parse implement_x^{tree} implement_x_rebased^{tree}` to see whether the two commits really are of identical content. – jthill Dec 12 '14 at 16:49

2 Answers2

11

This seems to be a task for the --onto option of git rebase.

git rebase --onto implement_x_rebased implement_x further_bar_fixes_that_depend_on_x

You may want to have look at the --onto example in the git rebase manual.

Michał Politowski
  • 4,288
  • 3
  • 30
  • 41
  • Indeed, exactly this type of situation is one of the examples (`git rebase --onto master next topic`) in `git help rebase`, except for the fact that the target of the rebase isn't just a single-commit branch in that example, but that's not really important to the example. – twalberg Dec 12 '14 at 18:19
  • Great solution but for clarity it would be very helpful to have an example with branches named `A---B---C---D` – Vedran Sep 24 '18 at 12:13
-1

One way to approach this would be to make implement_x and implement_x_rebased the same first, e.g.:

git checkout implement_x_rebased
git merge implement_x

then merge in your further fixes in the normal way.

The merge of implement_x should be a NOOP from a code point of view (check that git diff implement_x implement_x_rebased actually produces nothing), but you are recording the fact the two are merged, which will allow you to pull over everything else easily.

If they aren't quite the same, you may need the -s ours option. This records that a merge has been done without merging the code. USE WITH EXTREME CAUTION.

Failing that, you can simply use git rebase to rebase the later branches onto implement_x_rebased.

This is better than cherry-picking as a) you don't need to cherry pick each individual commit, remember to get the order right etc. b) semantically, your git tree makes more sense afterwards

abligh
  • 24,573
  • 4
  • 47
  • 84