From: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: Sahil Dua <sahildua2305@gmail.com>,
Ramsay Jones <ramsay@ramsayjones.plus.com>,
Git Mailing List <git@vger.kernel.org>
Subject: Re: What's cooking in git.git (Jul 2017, #09; Mon, 31)
Date: Sun, 06 Aug 2017 22:26:39 +0200 [thread overview]
Message-ID: <873794zbls.fsf@gmail.com> (raw)
In-Reply-To: <xmqqpoc9sksg.fsf@gitster.mtv.corp.google.com>
On Sat, Aug 05 2017, Junio C. Hamano jotted:
> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> We've talked how this UX should look before on-list. Rather than
>> re-hashing the arguments I had before I thought it was useful to present
>> it as a table. Here's how the patch looks now:
>>
>> |----------------------------+--------------+-------+---------+-----------------+-------------|
>> | cmd | creates new? | moves | copies? | ...with config? | checks out? |
>> |----------------------------+--------------+-------+---------+-----------------+-------------|
>> | branch <name> | Y | N | N | N | N |
>> | checkout <name> | Y | N | N | N | Y |
>> | checkout -b <name> <start> | Y | N | Y | N | Y |
>> | branch -m <name> | Y | Y | N | Y | Y |
>> | NEW: branch -c <name> | Y | N | Y | Y | Y |
>> |----------------------------+--------------+-------+---------+-----------------+-------------|
>
> I actually consider "branch" to *never* invoking a checkout. Even
> when "git branch -m A B" happens to be done when your checked out
> branch is A and you end up being on B. That is not a "checkout".
I think we just have a different mental model of what "checkout"
means. In my mind any operation that updates the HEAD to point to a new
branch is a checkout of that branch.
In the interest of explaining what I mean with the above and not proving
you wrong or whatever, consider a basic implementation of git before
pack-refs or whatever.
You could then copy a branch name like:
$ cp .git/refs/heads/{master,master-copy}
Get your currently checked out branch with:
$ cat .git/HEAD
ref: refs/heads/master
And you could then implement "git checkout" like:
$ echo "ref: refs/heads/master-copy" >.git/HEAD
This still works today. Now if I make a commit it goes on the
.git/refs/heads/master-copy branch.
Now let's say I wanted to rename the 'master' branch. This would rename
it:
$ mv .git/refs/heads/{master,trunk}
But it wouldn't check it out, my HEAD would still point to master:
$ git log
fatal: your current branch 'master' does not have any commits yet
$ git log --oneline -1 trunk
8b18718 (trunk) moo
To check it out I need:
$ echo "ref: refs/heads/trunk" >.git/HEAD
Which yields:
$ git log --oneline -1 HEAD
8b18718 (HEAD -> trunk) moo
The mv sans the "echo" is what we'd get if we did:
diff --git a/builtin/branch.c b/builtin/branch.c
index 8a0595e115..62ed1a8e20 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -493,9 +493,6 @@ static void rename_branch(const char *oldname, const char *newname, int force)
if (recovery)
warning(_("Renamed a misnamed branch '%s' away"), oldref.buf + 11);
- if (replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
- die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
-
strbuf_release(&logmsg);
strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11);
I.e. the last step of "git branch -m" is checking out the branch by
updating the HEAD. Now let's compile git like that and rename "master"
to "trunk":
$ git symbolic-ref HEAD
refs/heads/master
$ ./git-branch -m trunk
$ git symbolic-ref HEAD
refs/heads/master
$ git show
fatal: your current branch 'master' does not have any commits yet
Now let's do the equivalent of that removed
replace_each_worktree_head_symref():
$ git checkout trunk
Switched to branch 'trunk'
And voila:
$ git symbolic-ref HEAD
refs/heads/trunk
This is why I'm saying that "git branch -m" involves a checkout. Because
it is literally exactly the case that it could be replaced by a
shellscript whose last step is a "git checkout" of the new branch.
Anyway, none of that changes what we /should/ be doing on the fact that
"git branch -m" not updating the HEAD would be rather useless. I just
wanted to explain what I was talking about and why I was talking about
"checkout" in that context.
> Really from the end-user's point of view that is not a checkout.
> The user renamed the branch A and the same conceptual entity, which
> is a branch, is now called B. If that branch was what was checked
> out (IOW, if that branch was what would be grown by one commit if
> the user did "git commit"), then now that branch's name is B. It is
> natural if you ask "symbolic-ref HEAD" what branch is checked out
> after renaming A to B (and A happened to be what was checked out),
> the answer chould be B.
>
> It's like the city you live in changed the name of the street your
> house is on. You do not call movers, you do not do anything, but
> your address changes.
Yeah I see what you mean, although this analogy rapidly breaks down when
you poke at it as shown above. My house (a sha1) can be on any number of
streets and new ones can be added/removed all the time without changing
where my house is at.
>> I.e. have "branch -c <name>" but just make it not checkout the new
>> thing. What you're describing above sounds to me like:
>>
>> |-------------------------------------------+--------------+-------+---------+-----------------+-------------|
>> | cmd | creates new? | moves | copies? | ...with config? | checks out? |
>> [... stuff above this point is the same ...]
>> | branch -m <name> | Y | Y | N | Y | Y |
>> [... so is branch -m but included for context ...]
>> | NEW: checkout --super-b -b <name> <start> | Y | N | Y | Y | Y |
>> |-------------------------------------------+--------------+-------+---------+-----------------+-------------|
>
> You are talking backwards. I do not want "branch -c A B", even when
> A happens to be what is checked out, to check out branch B. You and
> Sahil were who wanted to check out branch B while doing so, and I
> just tried to guess why you two wanted to have such a behaviour that
> did not make much sense to me. And my guess was "perhaps they want
> a way to create a new branch starting from another branch, and check
> it out, and do so in a single end-user operation".
The use-case is the following. When I hack on e.g. git.git I'm on
"master" with configured upstream info:
$ git log @{u}..
Because if I don't care about 'master' another shorter way to say:
$ git checkout -b topic -t origin/master
Is:
$ git branch -m topic
That's how I start hacking on "topic", now let's say I've submitted that
and want to start on topic-2 after getting feedback:
# While still on topic
$ git branch -c topic-2
So it's just a way to get something exactly like -m except the "move &&
checkout" logic is changed to "copy && checkout".
> I am not particulary interested in such an operation; in my guess,
> you two are. And the "super-b" thing was a suggestion to you two:
> If you so desperately want such an operation, then don't make
> "branch --copy A B" that operation. Such an operation better fits
> in "checkout", not "branch".
That's arguably another sensible way to do a /subset/ of what 'git
branch -c' does (or something in addition to this patch). But there's
another use-case it won't cover, i.e. the two-arg branch -m/-c
manipulating a branch that HEAD doesn't point to:
$ git checkout master
$ git branch -m topic avar/topic
You can now do that with -c to s/move/copy/, but couldn't do this with
checkout unless you wastefully and needlessly updated the working tree.
> If you are not interested in such an operation, then that is fine.
> Do not add the "super-b" mode to "checkout".
Yeah it's not something I'm interested in or have a use-case for,
although I think in the same way we have -t for checkout it might be
sensible to have e.g.:
$ git checkout -b topic-2 -c topic -t origin/master
Where the new -c or --config-from would mean "...and get the config from
'topic'". Such a name would probably be less confusing than
--super-b[branch?] which to be implies some ongoing hierarchical
relationship.
> But I won't defend a "branch --copy A B" that checks out B when
> users and other people like Ramsay think that such a behaviour is
> illogical, because I do think it is, too.
I just started this from the POV of using branch -m and wanting
something like that which didn't remove the old thing when it was done
as its last step, which seemed easy to implement & explain.
As noted above I think it probably makes sense to also have something
like [--config-from|-c] for checkout, which would have a related but not
exactly the same use-case.
next prev parent reply other threads:[~2017-08-06 20:26 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-31 22:30 What's cooking in git.git (Jul 2017, #09; Mon, 31) Junio C Hamano
2017-07-31 23:36 ` Ramsay Jones
2017-08-03 20:26 ` Sahil Dua
2017-08-03 21:07 ` Junio C Hamano
2017-08-03 22:20 ` Ramsay Jones
2017-08-05 20:34 ` Ævar Arnfjörð Bjarmason
2017-08-05 22:37 ` Junio C Hamano
2017-08-06 20:26 ` Ævar Arnfjörð Bjarmason [this message]
2017-08-07 21:25 ` Igor Djordjevic
2017-08-07 22:20 ` Igor Djordjevic
2017-08-08 13:14 ` Ævar Arnfjörð Bjarmason
2017-08-08 18:55 ` Igor Djordjevic
2017-08-03 20:17 ` Sahil Dua
2017-08-03 20:23 ` Stefan Beller
2017-08-03 21:17 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=873794zbls.fsf@gmail.com \
--to=avarab@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=ramsay@ramsayjones.plus.com \
--cc=sahildua2305@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).