Kuba Szymanowski
Kuba Szymanowski

Reputation: 1350

Rebase two branches onto another branch

Given the following git history:

enter image description here

What would be the simplest way to rebase branches feature/1 and feature/2 onto master to achieve the following history:

enter image description here

So far I have come up with the following:

  1. Checkout feature/2(head of the commit chain I want to rebase)
  2. Rebase the branch onto master: git rebase master
  3. Change the head of the feature/1 branch: git branch -f feature/1 <hash>

Where <hash> is the hash of the duplicated Feature 1 commit created by the rebase command.

It works fine but seems too complicated to me.

Upvotes: 4

Views: 2879

Answers (2)

Mark Adelsberger
Mark Adelsberger

Reputation: 45659

The simplest and quickest solution is the one you've already worked out. You can combine steps 1 and 2

git rebase master feature/2

and you might find it easier to avoid dealing with commit ID's, in cases (like your example) where it's easy to calculate an expression for the target commit

git branch -f feature/1 feature/2^

You could, as others mention, use two rebases. However, this is not simpler. That is to say, whether the sophistication of the commands is simpler is a matter of opinion; but what you're telling git to do is objectively more complicated. And as a consequence of that, there is more opportunity for things to go wrong. The specific technique of rebasing feature/1 first, and then rebasing feature/2 over feature/1, for example, relies on detection of duplicate patch ID's during the 2nd rebase, which will fail in unfortunate ways if any conflict resolution occurred during the 1st rebase. If you really want to use a 2-rebase approach, I would recommend the 2nd rebase be done as

git rebase --onto feature/1 feature/1@{1} feature/2

as this avoids even considering re-rewriting the feature/1 commits. (The feature/1@{1} is a reflog entry that points to feature/1 before it was rebased.) But then you're using less-common rebase syntax, which as far as I can tell is at least as "not simple" as what you were doing in the first place.

Alternately you can use --fork-point to tell git to automatically interpret the reflog and try to figure out which commits would be dups.

git rebase --fork-point feature/1 feature/2

As long as you're doing both rebases at nearly the same time on the same clone, this will work most of the time. But it is adding more complexity (in the form of "magic" that git does under the hood), so you'd need to understand that it can go wrong, and if it does either (a) know enough about what it tried to do to diagnose the issue, or (b) back out and use one of the other methods.

Upvotes: 6

jthill
jthill

Reputation: 60245

Tell git what you're doing and the sequence is:

git rebase master feature/1
git rebase feature/1 feature/2

like so, you can c&p this:

git init test; cd $_
doit() { eval echo \>$*; git add $1; git commit -m "$2"; }
doit master "Initial commit"
git checkout -tb feature/1
doit file1 "Feature 1"
git checkout -tb feature/2
doit file2 "Feature 2"
git checkout master
doit master "New commit on master"

producing your graph exactly:

$ git log --graph --decorate --oneline --all
* 35cfad5 (feature/2) Feature 2
* 46b79ae (feature/1) Feature 1
| * ae89e31 (HEAD -> master) New commit on master
|/  
* f1138eb Initial commit
$

and now, since you told git your branch structure,

$ git rebase master feature/1
First, rewinding head to replay your work on top of it...
Applying: Feature 1
$ git rebase feature/1 feature/2
First, rewinding head to replay your work on top of it...
Applying: Feature 2
$ 

Upvotes: -3

Related Questions