threads / discuss / 27638

rewrite history

Subject: rewrite history

## tl;dr

9 messages between Jun 16, 2011 and Jun 16, 2011.

replies: 8people: 4as markdown or json

Ilya Basin· Jun 16, 2011, 19:17 UTC · lore

Hi list. There were 2 branches. One's HEAD was modified to match a specific commit at another branch. Now, how to merge them according to this scheme?

A---B---X---E---F
                     =>  C---D---X---E---F
C---D---X'

X and X' have no difference. I tried to write a script to cherry-pick E and F, but some of commits are merges and cherry-pick fails.

Jeff King· Jun 16, 2011, 19:26 UTC · re: Ilya Basin · lore

Re: rewrite history

On Thu, Jun 16, 2011 at 11:17:58PM +0400, Ilya Basin wrote:
Show 10 quoted lines
> Hi list. There were 2 branches. One's HEAD was modified to match a
> specific commit at another branch. Now, how to merge them according to
> this scheme?
> 
> A---B---X---E---F
>                      =>  C---D---X---E---F
> C---D---X'
> 
> X and X' have no difference. I tried to write a script to cherry-pick
> E and F, but some of commits are merges and cherry-pick fails.

I think you just want to rebase using the "-p" option to preserve merges. Something like:

  $ git checkout -b rebased-branch F
  $ git rebase -p --onto D B

that will pick X, E, and F, and replay them on top of D, resulting in the graph you showed above. You could also do:

  $ git rebase -p --onto X' X
if you wanted to keep X' instead of X.

The new history will be stored on "rebased-branch". You can make sure it looks good to you, and then:

  $ git branch -f my_original_branch rebased-branch

to move the state over to your original branch. You could also just do the rebase directly on the original A-B-X-E-F branch.

-Peff
Junio C Hamano· Jun 16, 2011, 19:43 UTC · re: Jeff King · lore

Re: rewrite history

Jeff King <peff@peff.net> writes:
Show 21 quoted lines
> On Thu, Jun 16, 2011 at 11:17:58PM +0400, Ilya Basin wrote:
>
>> Hi list. There were 2 branches. One's HEAD was modified to match a
>> specific commit at another branch. Now, how to merge them according to
>> this scheme?
>> 
>> A---B---X---E---F
>>                      =>  C---D---X---E---F
>> C---D---X'
>> 
>> X and X' have no difference. I tried to write a script to cherry-pick
>> E and F, but some of commits are merges and cherry-pick fails.
>
> I think you just want to rebase using the "-p" option to preserve
> merges. Something like:
>
>   $ git checkout -b rebased-branch F
>   $ git rebase -p --onto D B
>
> that will pick X, E, and F, and replay them on top of D, resulting in
> the graph you showed above.

Eh, careful. Nobody said the change between B and X is any similar to the change between D and X'. Replaying the changes E and F introduce on top of X' to arrive at C--D--X'-E--F is the best you could do, i.e.

>   $ git rebase -p --onto X' X
>
> if you wanted to keep X' instead of X.
is more like "even if you wanted to keep X instead of X'".

If you prefer commit message of X over X', you can rebase -i it after you are done the first round to get rid of A and B, though.

But wouldn't filter-branch a better tool for this? Graft to pretend that the parent of X is D instead of B, and filter the branch with F at its tip, that is.

Jeff King· Jun 16, 2011, 19:49 UTC · re: Junio C Hamano · lore

Re: rewrite history

On Thu, Jun 16, 2011 at 12:43:00PM -0700, Junio C Hamano wrote:
Show 23 quoted lines
> >> Hi list. There were 2 branches. One's HEAD was modified to match a
> >> specific commit at another branch. Now, how to merge them according to
> >> this scheme?
> >> 
> >> A---B---X---E---F
> >>                      =>  C---D---X---E---F
> >> C---D---X'
> >> 
> >> X and X' have no difference. I tried to write a script to cherry-pick
> >> E and F, but some of commits are merges and cherry-pick fails.
> >
> > I think you just want to rebase using the "-p" option to preserve
> > merges. Something like:
> >
> >   $ git checkout -b rebased-branch F
> >   $ git rebase -p --onto D B
> >
> > that will pick X, E, and F, and replay them on top of D, resulting in
> > the graph you showed above.
> 
> Eh, careful. Nobody said the change between B and X is any similar to the
> change between D and X'. Replaying the changes E and F introduce on top of
> X' to arrive at C--D--X'-E--F is the best you could do, i.e.

I thought that was exactly what Ilya said with "X and X' have no difference". I assumed that meant "they are semantically similar commits on different bases" (i.e., a cherry-pick) and not "they have the exact same tree state" (i.e., "git diff X X'" is empty).

> But wouldn't filter-branch a better tool for this?  Graft to pretend that
> the parent of X is D instead of B, and filter the branch with F at its
> tip, that is.

If my assumption on the meanings is reversed (i.e., X and X' really are the same tree state, not introducing equivalent commits), then yeah, that would be better.

-Peff
Ilya Basin· Jun 16, 2011, 20:06 UTC · re: Jeff King · lore

Re[2]: rewrite history

JK> On Thu, Jun 16, 2011 at 12:43:00PM -0700, Junio C Hamano wrote:
Show 23 quoted lines
>> >> Hi list. There were 2 branches. One's HEAD was modified to match a
>> >> specific commit at another branch. Now, how to merge them according to
>> >> this scheme?
>> >> 
>> >> A---B---X---E---F
>> >>                      =>  C---D---X---E---F
>> >> C---D---X'
>> >> 
>> >> X and X' have no difference. I tried to write a script to cherry-pick
>> >> E and F, but some of commits are merges and cherry-pick fails.
>> >
>> > I think you just want to rebase using the "-p" option to preserve
>> > merges. Something like:
>> >
>> >   $ git checkout -b rebased-branch F
>> >   $ git rebase -p --onto D B
>> >
>> > that will pick X, E, and F, and replay them on top of D, resulting in
>> > the graph you showed above.
>> 
>> Eh, careful. Nobody said the change between B and X is any similar to the
>> change between D and X'. Replaying the changes E and F introduce on top of
>> X' to arrive at C--D--X'-E--F is the best you could do, i.e.

JK> I thought that was exactly what Ilya said with "X and X' have no JK> difference". I assumed that meant "they are semantically similar commits JK> on different bases" (i.e., a cherry-pick) and not "they have the exact JK> same tree state" (i.e., "git diff X X'" is empty).

>> But wouldn't filter-branch a better tool for this?  Graft to pretend that
>> the parent of X is D instead of B, and filter the branch with F at its
>> tip, that is.

JK> If my assumption on the meanings is reversed (i.e., X and X' really are JK> the same tree state, not introducing equivalent commits), then yeah, JK> that would be better.

JK> -Peff

sorry, git diff X X' is empty

Jeff King· Jun 16, 2011, 20:13 UTC · re: Ilya Basin · lore

Re: rewrite history

On Fri, Jun 17, 2011 at 12:06:44AM +0400, Ilya Basin wrote:
Show 7 quoted lines
> JK> I thought that was exactly what Ilya said with "X and X' have no
> JK> difference". I assumed that meant "they are semantically similar commits
> JK> on different bases" (i.e., a cherry-pick) and not "they have the exact
> JK> same tree state" (i.e., "git diff X X'" is empty).
> [...]
> sorry,
> git diff X X' is empty
Oh, then ignore everything I said. :)
I think you want to graft and filter-branch as Junio mentioned.
-Peff
Ilya Basin· Jun 16, 2011, 21:55 UTC · re: Jeff King · lore

Re[2]: rewrite history

>> sorry,
>> git diff X X' is empty
JK> Oh, then ignore everything I said. :)
JK> I think you want to graft and filter-branch as Junio mentioned.
JK> -Peff

I'm puzzled. How to undo an unfortunate attempt of filter-branch? git log origin/master returns irrelevant info, although I didn't push it to origin and I also tried git branch -D master, -rD master and git fetch -f

Ilya Basin· Jun 16, 2011, 22:18 UTC · re: Ilya Basin · lore

Re[3]: rewrite history

>>> sorry,
>>> git diff X X' is empty
JK>> Oh, then ignore everything I said. :)
JK>> I think you want to graft and filter-branch as Junio mentioned.
JK>> -Peff

IB> I'm puzzled. How to undo an unfortunate attempt of filter-branch? IB> git log origin/master returns irrelevant info, although I didn't push IB> it to origin and I also tried git branch -D master, -rD master and git IB> fetch -f Nevermind, forgot to rm .git/info/grafts

Marc Branchaud· Jun 16, 2011, 21:33 UTC · re: Ilya Basin · lore

Re: rewrite history

On 11-06-16 03:17 PM, Ilya Basin wrote:
Show 14 quoted lines
> Hi list. There were 2 branches. One's HEAD was modified to match a
> specific commit at another branch. Now, how to merge them according to
> this scheme?
> 
> A---B---X---E---F
>                      =>  C---D---X---E---F
> C---D---X'
> 
> X and X' have no difference. I tried to write a script to cherry-pick
> E and F, but some of commits are merges and cherry-pick fails.
> 
> ...
> 
> git diff X X' is empty

It sounds like you really want to apply X--E--F on top of D, but I don't know how you can do that since you need to do *something* to D in order to get a tree that matches X, and that something is (presumably) *different* from the change that X applied to B. So if

	diff B X  !=  diff D X'

then I think Junio's right that the best you can do is change the meta-data in X' (commit message, Author, etc) to match X then apply E and F on top of that. But filter-branch seems like overkill to me here -- I'd just use "rebase -p" but not quite as Peff described:

	git checkout X'
	git commit --amend ....   # Replaces X' with X"
	git rebase -p --onto HEAD X F
Giving you
	C---D---X"---E---F
where
	diff D X'  ==   diff D X"
and	meta_data(X") == meta_data(X)

But if you're happy with C---D---X'---E---F then you can skip the "git commit --amend" step.

		M.

← back to recent threads