Immae
Immae

Reputation: 333

correctly rebase a merge

Another git question... I am in the following situation:

A1 ---- B1 ---- C1
                   \
                    > D ---- E ---- F
                   /
A2 ---- B2 ---- C2

Where {A1,B1,C1} and {A2,B2,C2} have no files in common (it's the consequence of merging two different repositories, so I have currently two roots)

I would like the history to look like this

A1 ---- B1 ---- C1 ---- A2 ---- B2 ---- C2 ---- D ---- E --- F

But I cannot figure out how to do that with git-rebase, any idea?

Bonus: If I can keep the tags (which I have on all three branches) without having to do it manually...

Upvotes: 3

Views: 111

Answers (2)

Julien Oster
Julien Oster

Reputation: 2322

I managed to do it with the following two commands, in sequence:

git filter-branch -f --parent-filter 'test $GIT_COMMIT = <a2> && echo "-p <c1>" || cat'
git filter-branch -f --parent-filter 'test $GIT_COMMIT = <new head> && echo "-p <c2>" || cat'

Of course, you have to replace <a2>, <c1>, <new head> etc. by the corresponding commit hashes. Note that the head's hash changes after the first command, which is why I called it <new head> instead of just <d>.

It's actually pretty straightforward: the first command sets C1 as A2's parent. The second command fixes the graph by setting C2 as D's only parent.

Upvotes: 3

Immae
Immae

Reputation: 333

Ok I figured out a way to do that. Since it gives a big up in the understanding of the internals of git, I give a detailed answer here:

First, you have to give to A2 a new parent, since it didn't have before:

git cat-file commit A2

produces a summary where no "parent appear". So create the line, and create a new hash:

git cat-file commit A2 | sed -e '2aparent C1' | git hash-object -t commit -w --stdin

This will give a hash {H1} as an output, that we use to replace A2 by this new hash:

git replace A2 H1

And voila, the A2 has now C1 as parent. But now the history looks like that:

A1 ---- B1 ---- C1 --------------------- D ----- E ----- F
                  \                     /
                     A2 ---- B2 ---- C2

So do the same to D, which has two parents (C1 and C2):

git cat-file commit D

Remove the "parent" line corresponding to C1, and hash, and replace:

H2=`git cat-file commit D | sed -e '/parent C1/d' | git hash-object -t commit -w --stdin`
git replace D H2

It looks like it worked for me. If I understand well what I did, this worked well because I had different files on both repositories. I think things could get wrong if I had files common in both repositories that were merged in a way in D.

Upvotes: 1

Related Questions