Sopsop
Sopsop

Reputation: 367

How to make two git branches (with common history) coherent with each other after rebasing one of them?

I think that my title is not clear enough, so I will describe the problem:

In my git project, I have 3 branches: master, b1, and b2. Here is the history tree:

 A---B---C  master
          \
           D---E---F  b1
                    \
                     G---H---I  b2

Suppose I want to rebase the b1 branch and edit the E commit. After rebasing, commits E and F will be replaced by new commits E' and F' which have different commit SHAs. Therefore, the history in b1 will be different from history in b2:

 A---B---C  master
           \
             D---E'---F'  b1
                     
 A---B---C---D---E---F---G---H---I  b2

So my question is: how to make sure that b2 follows b1 (automatically gets the same new commits as b1) after rebasing b1 so that their respective histories stay coherent.

Upvotes: 0

Views: 114

Answers (3)

Han-Kwang Nienhuys
Han-Kwang Nienhuys

Reputation: 3274

After your first rebase, it's not this:

 A---B---C  master
           \
             D---E'---F'  b1
                     
 A---B---C---D---E---F---G---H---I  b2

but rather this:

A---B---C  master
         \
          D---Ea---F'  b1
           \      
            E---F---G---H---I  b2

Here, Ea means the amended E commit. And you want this, if I understand correctly:

A---B---C  master
         \
          D---Ea---F'  b1
                    \      
                     G'---H'---I'  b2

You can achieve this using an interactive rebase:

git checkout b2
git rebase -i b1

In the rebase edit you comment out the lines for commit E:

# pick df8efe6 E
pick a7fcbed G
pick 936b51a H
pick c77ca69 I

# ...
# Commands:
# p, pick = use commit
# ...
# If you remove a line here THAT COMMIT WILL BE LOST.

Responding to your comment, if you want to go all the way from the starting position (ABCDEFGHI) to the desired end positon:

git checkout b2
git rebase -i master

In the editor:

pick 1234567 D
edit a7fcbed E
pick 936b51a F
pick c77ca69 G
pick 1e8d614 H
pick 8daafa7 I

# ...
# p, pick = use commit
# e, edit = use commit, but stop for amending
# ...

When done, correct the b1 branch:

git checkout b1
git reset --hard 936b51a

You can also look at the other answers for inspiration. I'm not sure why you want to achieve all of this in a single command; you still have to amend commit E somewhere in the process. It saves you one interactive rebase to do it this way.

Upvotes: 1

jthill
jthill

Reputation: 60605

So my question is: how to make sure that b2 follows b1 (automatically gets the same new commits as b1).

You need to rewrite b2's history too, you're rebasing all of the master..b2 commits and rehanging the b1 and b2 labels.

Interactive rebase lets you execute arbitrary commands, notably including git branch, after each step. So do

git rebase -i master b2

and in the pick list after the current b1 commit say exec git branch -f b1.

You could automate this, pipe the picklist buffer through

while read command commit rest; do case $command in 
*) printf %s\\n "$command${commit:+ $commit${rest:+ $rest}}" ;;&
pick) git for-each-ref refs/heads --points-at $commit \
        --format='exec git branch -f %(refname:short)' ;;
esac; done

and it'll add the exec git branch -f's after every pick for a branch tip. I've just built and tried this. Season to taste, of course.

If you're rebasing deep into a branched history, it's probably better to just construct the exact cherry-pick and branch sequence you want; rebase is a convenience command meant to ease a common task. Like all good tools it can be pushed a little farther than you might expect, but it's got its limits.

Upvotes: 0

LeGEC
LeGEC

Reputation: 52216

If you only have two branches, with a linear history as in your diagram :

I would rebase b2 instead of b1 :

 A---B---C  master
          \
           D---E'---F'
                     \
                      G'---H'---I'  b2

and then update b1 :

git branch -f b1 F'

@Han-KwangNienhuys answer is perfectly valid, and you can apply it if you need to update b2 when b1 has already been rewritten.

Upvotes: 1

Related Questions