Re: [PATCH 2/2] learn to pick/revert into unborn branch

2 messages, 2 authors, 2016-06-15 · open the first message on its own page

Re: [PATCH 2/2] learn to pick/revert into unborn branch

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:55:35

Martin von Zweigbergk [off-list ref] writes:
On Sat, Dec 22, 2012 at 7:24 PM, Junio C Hamano [off-list ref] wrote:
quoted
Martin von Zweigbergk [off-list ref] writes:
quoted
quoted
From the user's point of view, it seems natural to think that
cherry-picking into an unborn branch should work, so make it work,
with or without --ff.
I actually am having a hard time imagining how that could ever be
natural.
Fair enough. What's natural is of course very subjective.  ...
happens to be empty. Of course, pretty much any operation that needs
more than the tree (indirectly) pointed to by HEAD would fail the
"whenever possible" clause. I realize that cherry-pick _does_ need the
current commit to record the parent of the resulting commit,...
Yes, and I do not think it is an implementation detail.

I am not opposed to an "internal use" of the cherry-pick machinery to
implement a corner case of "rebase -i":

    1. Your first commit adds "Makefile" and "hello.c", to build the
       "Hello world" program.

    2. Your second commmit adds "goodbye.c" and modifies "Makefile",
       to add the "Goodbye world" program.

    3. You run "rebase -i --root" to get this insn sheet:

	pick Add Makefile and hello.c for "Hello world"
        pick Add goodbye.c for "Goodbye world"

       and swap them:

        pick Add goodbye.c for "Goodbye world"
	pick Add Makefile and hello.c for "Hello world"

    4. The first one conflicts, as it wants to add new bits in
       "Makefile" that does not exist.  You edit it and make the
       result pretend as if "goodbye.c were the first program you
       added to the project (i.e. adding the common build
       infrastructure bits you did not change from the real first
       commit back to "Makefile", but making sure it does not yet
       mention "hello.c").

    5. "rebase --continue" will give you conflicts for the second
       one too, and your resolution is likely to match the tip
       before you started the whole "rebase -i".

In step 4., you would be internally using the cherry-pick machinery
to implement the step of "rebase -i" sequence.  That is what I would
call an implementation detail.  And that is cherry-picking to the
root.  It transplants something that used to depend on the entire
history behind it to be the beginning of the history so its log
needs to be adjusted, but "rebase -i" can choose to always make it
conflict and force the user to write a correct log message, so it
won't expose the fundamental flaw you would add if you allowed the
end-user facing "cherry-pick" to pick something to create a new root
commit without interaction.
In the same way, I think "git reset" should work on an unborn branch,
even though there is no commit that we can be "modifying index and
working tree to match" (from man page).
I agree that "git reset" without any commit parameter to reset the
index and optionally the working tree (with "--hard") should reset
from an empty tree when you do not yet have any commit.  If HEAD
points at an existing commit, its tree is what you reset the
contents from.  If you do not have any commit yet, by definition
that tree is an empty tree.

But I do not think it has anything to do with "cherry-pick to empty",
so I do not agree with "In the same way" at all.
As for use cases, I didn't consider that much more than that it might
be useful for implementing "git rebase --root". I haven't implemented
that yet, so I can't say for sure that it will work out.
I think it makes sense only as an internal implementation detail of
"rebase -i --root".
One use case might be to rewrite history by creating an new unborn
branch and picking the initial commit and a subset of other commits.
If you mean, in the above sample history, to "git cherry-pick" the
commit that starts the "Hello world" and then do something else on
top of the resulting history, how would that be different from
forking from that existing root commit?
Anyway, I didn't implement it because I thought it would be very
useful, but mostly because I just thought it should work (for
completeness).
I would not exactly call X "complete" if X works in one way in most
cases and it works in quite a different way in one other case, only
because it would have to barf if it wanted to work in the same way
as in most cases, and the different behaviour is chosen only because
"X that does something is better than X that stops in an impossible
situation and barfs".

Re: [PATCH 2/2] learn to pick/revert into unborn branch

From: Martin von Zweigbergk <hidden>
Date: 2016-06-15 22:55:35

On Sun, Dec 23, 2012 at 11:18 AM, Junio C Hamano [off-list ref] wrote:
Martin von Zweigbergk [off-list ref] writes:
quoted
On Sat, Dec 22, 2012 at 7:24 PM, Junio C Hamano [off-list ref] wrote:
I am not opposed to an "internal use" of the cherry-pick machinery to
implement a corner case of "rebase -i":
....
    3. You run "rebase -i --root" to get this insn sheet:

        pick Add Makefile and hello.c for "Hello world"
        pick Add goodbye.c for "Goodbye world"

       and swap them:

        pick Add goodbye.c for "Goodbye world"
        pick Add Makefile and hello.c for "Hello world"
Right, and as you point out in your later message, editing the initial
commit is another (and more useful) use case. It could of course be
special cased in "git rebase", but I think doing it "git cherry-pick"
is the right thing to do. Hopefully git-rebase.sh can then just reset
to the void state and git-rebase--interactive.sh can just continue
without knowing or caring whether it got started on an unborn branch.
Hmm... I just realized the "branch" in "unborn branch" really means we
don't have "unborn detached HEAD", do we? So some more tricks are
probably necessary after all. :-(
[...] It transplants something that used to depend on the entire
history behind it to be the beginning of the history so its log
needs to be adjusted, but "rebase -i" can choose to always make it
conflict and force the user to write a correct log message, so it
won't expose the fundamental flaw you would add if you allowed the
end-user facing "cherry-pick" to pick something to create a new root
commit without interaction.
If I understand you correctly, you are suggesting that "git rebase"
should set the action from "pick" to "edit" for the first commit in
the insn sheet if it is not a root commit. "git rebase -i --root"
doesn't currently do that, but it certainly could.
I agree that "git reset" without any commit parameter to reset the
index and optionally the working tree (with "--hard") should reset
from an empty tree when you do not yet have any commit.
Good to hear.
But I do not think it has anything to do with "cherry-pick to empty",
so I do not agree with "In the same way" at all.
See later comment.
quoted
One use case might be to rewrite history by creating an new unborn
branch and picking the initial commit and a subset of other commits.
If you mean, in the above sample history, to "git cherry-pick" the
commit that starts the "Hello world" and then do something else on
top of the resulting history, how would that be different from
forking from that existing root commit?
True, the result would be the same. The user's thought process might
be a little different ("let me start from scratch" vs "let me start
almost from scratch"), but that's a very minor difference that I'm
sure any user would quickly overcome.
quoted
Anyway, I didn't implement it because I thought it would be very
useful, but mostly because I just thought it should work (for
completeness).
I would not exactly call X "complete" if X works in one way in most
cases and it works in quite a different way in one other case, only
because it would have to barf if it wanted to work in the same way
as in most cases, and the different behaviour is chosen only because
"X that does something is better than X that stops in an impossible
situation and barfs".
I agree, of course, but I don't see the behavior as different. When
thinking about behavior around the root of the history, I imagine that
all root commits actually have a parent, and that they all have the
same parent. I also imagine that on an unborn branch, instead of being
invalid, HEAD points to that same "single root" commit with an empty
tree. Despite this model not matching git's, I find that this helps me
reason about what the behavior of various commands should be.

With this reasoning, cherry-picking into an unborn branch is no
different from cherry-picking into any commit with an empty tree
(which of course would be rare, but not forbidden).
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help