threads / discuss / 22441

master^ is not a local branch -- huh?!?

Subject: master^ is not a local branch -- huh?!?

## tl;dr

94 messages between Jan 29, 2010 and Jan 31, 2010.

replies: 93people: 14as markdown or json

Ron1· Jan 29, 2010, 20:20 UTC · lore
[ron@mickey]$ git checkout master
Already on 'master'
[ron@mickey]$ git checkout master^
Note: moving to 'master^' which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
  git checkout -b <new_branch_name>
HEAD is now at 7be05e0... test
[ron@mickey]$ git branch
* (no branch)
  master
[ron@mickey]$
Huh?!?

This is a test repository which has never been pulled from nor pushed to anywhere. So how is it possible that I have a non-local branch?

Thanks, rg

Jacob Helwig· Jan 29, 2010, 20:27 UTC · re: Ron1 · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 12:20, Ron1 <ron1@flownet.com> wrote:
Show 21 quoted lines
> [ron@mickey]$ git checkout master
> Already on 'master'
> [ron@mickey]$ git checkout master^
> Note: moving to 'master^' which isn't a local branch
> If you want to create a new branch from this checkout, you may do so
> (now or later) by using -b with the checkout command again. Example:
>  git checkout -b <new_branch_name>
> HEAD is now at 7be05e0... test
> [ron@mickey]$ git branch
> * (no branch)
>  master
> [ron@mickey]$
>
> Huh?!?
>
> This is a test repository which has never been pulled from nor pushed to
> anywhere.  So how is it possible that I have a non-local branch?
>
> Thanks,
> rg
>

master^ is a commit (the first parent of master), not a branch (local or otherwise).

Sverre Rabbelier· Jan 29, 2010, 20:35 UTC · re: Jacob Helwig · lore

Re: master^ is not a local branch -- huh?!?

Heya,
On Fri, Jan 29, 2010 at 21:27, Jacob Helwig <jacob.helwig@gmail.com> wrote:
Show 6 quoted lines
> On Fri, Jan 29, 2010 at 12:20, Ron1 <ron1@flownet.com> wrote:
>> This is a test repository which has never been pulled from nor pushed to
>> anywhere.  So how is it possible that I have a non-local branch?
>
> master^ is a commit (the first parent of master), not a branch (local
> or otherwise).

Perhaps we should change the message to say "not a branch" if it's not a reference to a remote branch? Or simply changing the text to "not a (local) branch"?

-- 
Cheers,

Sverre Rabbelier
Jacob Helwig· Jan 29, 2010, 20:38 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 12:35, Sverre Rabbelier <srabbelier@gmail.com> wrote:
Show 14 quoted lines
> Heya,
>
> On Fri, Jan 29, 2010 at 21:27, Jacob Helwig <jacob.helwig@gmail.com> wrote:
>> On Fri, Jan 29, 2010 at 12:20, Ron1 <ron1@flownet.com> wrote:
>>> This is a test repository which has never been pulled from nor pushed to
>>> anywhere.  So how is it possible that I have a non-local branch?
>>
>> master^ is a commit (the first parent of master), not a branch (local
>> or otherwise).
>
> Perhaps we should change the message to say "not a branch" if it's not
> a reference to a remote branch? Or simply changing the text to "not a
> (local) branch"?
>

I think "not a branch" would be better than "not a (local) branch". In my mind, the latter reads almost exactly the same as the current message.

Junio C Hamano· Jan 29, 2010, 20:48 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

Sverre Rabbelier <srabbelier@gmail.com> writes:
Show 6 quoted lines
>> master^ is a commit (the first parent of master), not a branch (local
>> or otherwise).
>
> Perhaps we should change the message to say "not a branch" if it's not
> a reference to a remote branch? Or simply changing the text to "not a
> (local) branch"?

I think "not a branch" is a good suggestion, whether the target of checkout is "master^" or "origin/topic".

These days, you can say "git checkout topic" to automagically create a local "topic" branch that forks from "origin/topic" remote tracking branch when you have one, thanks to Dscho's UI improvement ideas (one less reason you may end up on a detached HEAD state without wanting to).

Sverre Rabbelier· Jan 29, 2010, 20:56 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

Heya,
On Fri, Jan 29, 2010 at 21:48, Junio C Hamano <gitster@pobox.com> wrote:
> I think "not a branch" is a good suggestion, whether the target of
> checkout is "master^" or "origin/topic".
Mhhh, for added clarity, do we want to change it to "branch name"? Since ...

$ git grep "branch name" Documentation/ | wc -l 58

... suggests that we use that in other places as well?
-- 
Cheers,

Sverre Rabbelier
Sverre Rabbelier· Jan 29, 2010, 21:09 UTC · re: Sverre Rabbelier · lore

[PATCH] checkout: warn about 'branch name' rather than 'local branch'

These days, you can say "git checkout topic" to automagically create a local "topic" branch that forks from "origin/topic" remote tracking branch when you have one, thanks to Dscho's UI improvement ideas. As such it is more appropriate to say that the user is checking out something that is not a branch name, rather than saying it is not a 'local branch'.

Signed-off-by: Sverre Rabbelier <srabbelier@gmail.com>
---
  Junio, I used part of your reply as the commit message, is that ok?
  Only change is s/local branch/branch name/.
 builtin-checkout.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 5277817..4b34314 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -523,7 +523,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 			   REF_NODEREF, DIE_ON_ERR);
 		if (!opts->quiet) {
 			if (old->path)
-				fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
+				fprintf(stderr, "Note: moving to '%s' which isn't a branch name\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
 			describe_detached_head("HEAD is now at", new->commit);
 		}
 	}
-- 
1.6.6.rc1.56.gaea25.dirty
Jacob Helwig· Jan 29, 2010, 21:19 UTC · re: Sverre Rabbelier · lore

[PATCH] checkout: Fix test for s/local branch/branch name/ change.

Signed-off-by: Jacob Helwig <jacob.helwig@gmail.com>
---

This should probably be squashed into Sverre Rabbelier's change, if this is decided as the way to go.

 t/t7201-co.sh |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 6442f71..b6e3216 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -171,7 +171,7 @@ test_expect_success 'checkout to detach HEAD' '
 	git checkout -f renamer && git clean -f &&
 	git checkout renamer^ 2>messages &&
 	(cat >messages.expect <<EOF
-Note: moving to '\''renamer^'\'' which isn'\''t a local branch
+Note: moving to '\''renamer^'\'' which isn'\''t a branch name
 If you want to create a new branch from this checkout, you may do so
 (now or later) by using -b with the checkout command again. Example:
   git checkout -b <new_branch_name>
-- 
1.6.6.1
Sverre Rabbelier· Jan 29, 2010, 21:20 UTC · re: Jacob Helwig · lore

Re: [PATCH] checkout: Fix test for s/local branch/branch name/ change.

Heya,
On Fri, Jan 29, 2010 at 22:19, Jacob Helwig <jacob.helwig@gmail.com> wrote:
> This should probably be squashed into Sverre Rabbelier's change, if this is
> decided as the way to go.

Ah, excellent point, apologies :(. I saw it show up when I grepped for the message, not sure why I didn't do anything with that.

-- 
Cheers,

Sverre Rabbelier
Nicolas Pitre· Jan 29, 2010, 21:40 UTC · re: Sverre Rabbelier · lore

Re: [PATCH] checkout: warn about 'branch name' rather than 'local branch'

On Fri, 29 Jan 2010, Sverre Rabbelier wrote:
Show 8 quoted lines
> These days, you can say "git checkout topic" to automagically create
> a local "topic" branch that forks from "origin/topic" remote tracking
> branch when you have one, thanks to Dscho's UI improvement ideas. As
> such it is more appropriate to say that the user is checking out
> something that is not a branch name, rather than saying it is not a
> 'local branch'.
> 
> Signed-off-by: Sverre Rabbelier <srabbelier@gmail.com>

For the record, I'm providing a NAK. First I don't agree with the UI "improvement" if there is no way to check out a remote branch without creating soon-to-be-stall local branches with the same name.

Next, the message can be made yet more clear and give the user more of a hint with what is going on. Something like:

	"%s is not a local branch head: creating a detached HEAD\n"

plus the remaining clue lines. This way people will have a much greater chance of understanding what state they're in, and a simple Google search for detached HEAD gives you the Git manual page with the needed info.

Nicolas
Ron Garret· Jan 29, 2010, 21:50 UTC · re: Nicolas Pitre · lore

Re: [PATCH] checkout: warn about 'branch name' rather than 'local branch'

In article <alpine.LFD.2.00.1001291621020.1681@xanadu.home>,
 Nicolas Pitre <nico@fluxnic.net> wrote:
Show 24 quoted lines
> On Fri, 29 Jan 2010, Sverre Rabbelier wrote:
> 
> > These days, you can say "git checkout topic" to automagically create
> > a local "topic" branch that forks from "origin/topic" remote tracking
> > branch when you have one, thanks to Dscho's UI improvement ideas. As
> > such it is more appropriate to say that the user is checking out
> > something that is not a branch name, rather than saying it is not a
> > 'local branch'.
> > 
> > Signed-off-by: Sverre Rabbelier <srabbelier@gmail.com>
> 
> For the record, I'm providing a NAK.  First I don't agree with the UI 
> "improvement" if there is no way to check out a remote branch without 
> creating soon-to-be-stall local branches with the same name.
> 
> Next, the message can be made yet more clear and give the user more of a 
> hint with what is going on.  Something like:
> 
> 	"%s is not a local branch head: creating a detached HEAD\n"
> 
> plus the remaining clue lines.  This way people will have a much greater 
> chance of understanding what state they're in, and a simple Google 
> search for detached HEAD gives you the Git manual page with the needed 
> info.
I agree that would be much better.
rg
Junio C Hamano· Jan 29, 2010, 21:42 UTC · re: Sverre Rabbelier · lore

Re: [PATCH] checkout: warn about 'branch name' rather than 'local branch'

Sverre Rabbelier <srabbelier@gmail.com> writes:
Show 13 quoted lines
> These days, you can say "git checkout topic" to automagically create
> a local "topic" branch that forks from "origin/topic" remote tracking
> branch when you have one, thanks to Dscho's UI improvement ideas. As
> such it is more appropriate to say that the user is checking out
> something that is not a branch name, rather than saying it is not a
> 'local branch'.
>
> Signed-off-by: Sverre Rabbelier <srabbelier@gmail.com>
> ---
>
>   Junio, I used part of your reply as the commit message, is that ok?
>
>   Only change is s/local branch/branch name/.

I explained why I think that is not solving the real problem. To a user faced with an unexpected detached HEAD situation, it is not very important to explain how we were forced to detach (i.e. because you didn't tell me to switch to a branch).

Sverre Rabbelier· Jan 29, 2010, 21:45 UTC · re: Junio C Hamano · lore

Re: [PATCH] checkout: warn about 'branch name' rather than 'local branch'

Heya,
On Fri, Jan 29, 2010 at 22:42, Junio C Hamano <gitster@pobox.com> wrote:
> I explained why I think that is not solving the real problem.  To a user
> faced with an unexpected detached HEAD situation, it is not very important
> to explain how we were forced to detach (i.e. because you didn't tell me
> to switch to a branch).
I agree your patch is better :).
-- 
Cheers,

Sverre Rabbelier
Junio C Hamano· Jan 29, 2010, 21:35 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

Sverre Rabbelier <srabbelier@gmail.com> writes:
Show 10 quoted lines
> On Fri, Jan 29, 2010 at 21:48, Junio C Hamano <gitster@pobox.com> wrote:
>> I think "not a branch" is a good suggestion, whether the target of
>> checkout is "master^" or "origin/topic".
>
> Mhhh, for added clarity, do we want to change it to "branch name"? Since ...
>
> $ git grep "branch name" Documentation/ | wc -l
> 58
>
> ... suggests that we use that in other places as well?
I think the confusion is twofold:
    $ git checkout master^
    Note: moving to 'master^' which isn't a local branch
    If you want to create a new branch from this checkout, you may do so
    ...
The notice tells us:
 - We are moving to 'master^', but it doesn't say what that really means;
 - That 'master^' isn't a local branch, but it doesn't say why it matters
   if it is a local branch (name) or not.
But what it really should tell new people are:
 - The user is no longer on any branch;
 - What the implications of not being on any branch are;

Your "branch _name_" suggestion deals with another issue that is of lessor importance compared to the above two:

 - The _reason_ we are detaching HEAD is because 'master^' did not spell a
   name of a local branch.
 - and perhaps how to be on a branch instead of detaching the head like so.

Compare the current output from "git checkout $commit" with output from "git checkout topic" when you don't have a local branch "topic" but have a unique remote tracking branch with the same name from a remote, namely "origin" (that's the UI improvement from Dscho I mentioned in the previous message):

    $ git checkout topic
    Branch topic set up to track remote branch topic from origin.
    Switched to a new branch 'topic'
which very clearly explains what is going on.

The current advisory message tells you what to do to create a new branch, but doesn't explain why you might want to do so (or what is the downside of not doing so) in the first place. That adds to frustration for new people.

So how about this strawman?
    $ git checkout origin/topic
    Note: checking out commit 'origin/topic'.
    You are no longer on any branch. You can look around, make changes and
    record them in new commits, but any new commit you make from now on will
    be lost when you check out another branch. If you want to create a new
    branch from this state to keep them, you may do so (now or later) by
    using -b with the checkout command again. Example:
      git checkout -b new_branch_name
    HEAD is now at f423ef5... tests: allow user to specify trash direc...

and hide the lines from "Note: checking out..." to the blank line before "HEAD is now at" inside advice.detachedHEAD, so that people who know what detached head is and want to take advantage of it to experiment without having to worry about cleaning up will have to see only:

    $ git checkout origin/topic
    HEAD is now at f423ef5... tests: allow user to specify trash direc...
diff --git a/advice.c b/advice.c
index 936d98b..0be4b5f 100644
--- a/advice.c
+++ b/advice.c
@@ -5,6 +5,7 @@ int advice_status_hints = 1;
 int advice_commit_before_merge = 1;
 int advice_resolve_conflict = 1;
 int advice_implicit_identity = 1;
+int advice_detached_head = 1;
 
 static struct {
 	const char *name;
@@ -15,6 +16,7 @@ static struct {
 	{ "commitbeforemerge", &advice_commit_before_merge },
 	{ "resolveconflict", &advice_resolve_conflict },
 	{ "implicitidentity", &advice_implicit_identity },
+	{ "detachedhead", &advice_detached_head },
 };
 
 int git_default_advice_config(const char *var, const char *value)
diff --git a/advice.h b/advice.h
index 9b7a3ad..3244ebb 100644
--- a/advice.h
+++ b/advice.h
@@ -8,6 +8,7 @@ extern int advice_status_hints;
 extern int advice_commit_before_merge;
 extern int advice_resolve_conflict;
 extern int advice_implicit_identity;
+extern int advice_detached_head;
 
 int git_default_advice_config(const char *var, const char *value);
 
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 5277817..0719e54 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -522,8 +522,16 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 		update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 			   REF_NODEREF, DIE_ON_ERR);
 		if (!opts->quiet) {
-			if (old->path)
-				fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
+			if (old->path && advice_detached_head)
+				fprintf(stderr, 
+"Note: checking out commit '%s'.\n"
+"You are no longer on any branch. You can look around, make changes and\n"
+"record them in new commits, but any new commit you make from now on will\n"
+"be lost when you check out another branch. If you want to create a new\n"
+"branch from this state to keep them, you may do so (now or later) by\n"
+"using -b with the checkout command again. Example:\n\n"
+"  git checkout -b new_branch_name\n\n",
+					new->name);
 			describe_detached_head("HEAD is now at", new->commit);
 		}
 	}
Nicolas Pitre· Jan 29, 2010, 21:20 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Junio C Hamano wrote:
Show 16 quoted lines
> Sverre Rabbelier <srabbelier@gmail.com> writes:
> 
> >> master^ is a commit (the first parent of master), not a branch (local
> >> or otherwise).
> >
> > Perhaps we should change the message to say "not a branch" if it's not
> > a reference to a remote branch? Or simply changing the text to "not a
> > (local) branch"?
> 
> I think "not a branch" is a good suggestion, whether the target of
> checkout is "master^" or "origin/topic".
> 
> These days, you can say "git checkout topic" to automagically create a
> local "topic" branch that forks from "origin/topic" remote tracking branch
> when you have one, thanks to Dscho's UI improvement ideas (one less
> reason you may end up on a detached HEAD state without wanting to).
If this is the case then I'm really disappointed.

With all due respects, I don't share Dscho's sentiment about Git's alleged non user-friendliness. And I always praised Git's ability to use a detached head to check out a remote branch, and never had any problem teaching this concept to people. So the above is not a UI improvement at all to me.

Nicolas
Sverre Rabbelier· Jan 29, 2010, 21:21 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Heya,
On Fri, Jan 29, 2010 at 22:20, Nicolas Pitre <nico@fluxnic.net> wrote:
Show 5 quoted lines
> With all due respects, I don't share Dscho's sentiment about Git's
> alleged non user-friendliness.  And I always praised Git's ability to
> use a detached head to check out a remote branch, and never had any
> problem teaching this concept to people.  So the above is not a UI
> improvement at all to me.
I think 'git checkout origin/master^0' still works?
-- 
Cheers,

Sverre Rabbelier
Nicolas Pitre· Jan 29, 2010, 21:29 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Sverre Rabbelier wrote:
Show 10 quoted lines
> Heya,
> 
> On Fri, Jan 29, 2010 at 22:20, Nicolas Pitre <nico@fluxnic.net> wrote:
> > With all due respects, I don't share Dscho's sentiment about Git's
> > alleged non user-friendliness.  And I always praised Git's ability to
> > use a detached head to check out a remote branch, and never had any
> > problem teaching this concept to people.  So the above is not a UI
> > improvement at all to me.
> 
> I think 'git checkout origin/master^0' still works?

Then who was arguing about making Git more user friendly rather then less?

Nicolas
Sverre Rabbelier· Jan 29, 2010, 21:32 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Heya,
On Fri, Jan 29, 2010 at 22:29, Nicolas Pitre <nico@fluxnic.net> wrote:
> Then who was arguing about making Git more user friendly rather
> then less?

Using a detached head is a more advanced feature than wanting to checkout a remote branch locally, creating a local tracking branch. As such, 'git checkout origin/topic' now means the same as 'git checkout -t origin/topic', and you can get the old behavior back by doing 'git checkout origin/topic^0'. I don't see what the problem is, if you're using a detached head you're an advanced enough git user that you can remember that you can use '^0' to detach your head. It's not all that uncommon to do 'git checkout HEAD^0' to detach your head to the current branch, no?

-- 
Cheers,

Sverre Rabbelier
Nicolas Pitre· Jan 29, 2010, 21:51 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Sverre Rabbelier wrote:
Show 11 quoted lines
> Heya,
> 
> On Fri, Jan 29, 2010 at 22:29, Nicolas Pitre <nico@fluxnic.net> wrote:
> > Then who was arguing about making Git more user friendly rather
> > then less?
> 
> Using a detached head is a more advanced feature than wanting to
> checkout a remote branch locally, creating a local tracking branch. As
> such, 'git checkout origin/topic' now means the same as 'git checkout
> -t origin/topic', and you can get the old behavior back by doing 'git
> checkout origin/topic^0'.

What purpose does this "feature" serve? Making sure people remain stupid and get even more confused when the special dwimery doesn't work because they don't know the difference between a local branch and a remote tracking branch?

And now people will be left wondering why after a fetch they don't get the latest stuff when they do "git checkout topic" again. Is this any better?

> I don't see what the problem is, if you're
> using a detached head you're an advanced enough git user that you can
> remember that you can use '^0' to detach your head.

I don't agree with the assertion that a detached HEAD is for advanced users only.

> It's not all that uncommon to do 'git checkout HEAD^0' to detach your 
> head to the current branch, no?

Certainly way more uncommon than 'git checkout origin/foo', and way less intuitive.

Nicolas
Junio C Hamano· Jan 29, 2010, 21:58 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Nicolas Pitre <nico@fluxnic.net> writes:
Show 8 quoted lines
> What purpose does this "feature" serve?  Making sure people remain 
> stupid and get even more confused when the special dwimery doesn't work 
> because they don't know the difference between a local branch and a 
> remote tracking branch?
>
> And now people will be left wondering why after a fetch they don't get 
> the latest stuff when they do "git checkout topic" again.  Is this any 
> better?
Sverre's explanation does not match reality.

We used to just say "topic is not a rev nor path" and failed when the user said "git checkout topic". And the magic kicks in when there is only one "remotes/*/topic".

Because this cannot be any request other than to check out a local branch "topic", and because there is no place more sensible than the "topic" taken from the "origin" (as that is the sole place that has "topic"), it dwims as a shorthand for "checkout -b topic origin/topic" and tells you that it did so.

So people _has_ to still know that local branches are the only thing they can check out (iow, "checkout topic" is not a request to check out a remote tracking branch).

Sverre Rabbelier· Jan 29, 2010, 22:00 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

Heya,
On Fri, Jan 29, 2010 at 22:58, Junio C Hamano <gitster@pobox.com> wrote:
> Sverre's explanation does not match reality.

Heh, that's the second time I messed up explaining this new feature, maybe I should stop doing that... eh... my bad.

-- 
Cheers,

Sverre Rabbelier
Nicolas Pitre· Jan 29, 2010, 22:34 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Junio C Hamano wrote:
Show 9 quoted lines
> We used to just say "topic is not a rev nor path" and failed when the user
> said "git checkout topic".  And the magic kicks in when there is only one
> "remotes/*/topic".
> 
> Because this cannot be any request other than to check out a local branch
> "topic", and because there is no place more sensible than the "topic"
> taken from the "origin" (as that is the sole place that has "topic"), it
> dwims as a shorthand for "checkout -b topic origin/topic" and tells you
> that it did so.
OK.  That is probably sensible.

I don't think any improvement on the detached head message should presume on this though.

And it might be a good idea to say explicitly that what happened is the creation of a detached HEAD, like in:

diff --git a/builtin-checkout.c b/builtin-checkout.c
index 5277817..c0a44d7 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -523,7 +523,10 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 			   REF_NODEREF, DIE_ON_ERR);
 		if (!opts->quiet) {
 			if (old->path)
-				fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
+				fprintf(stderr, "Note: '%s' isn't a local branch head: creating a detached HEAD\n"
+						"If you want to create a new branch from this checkout, you may do so\n"
+						"(now or later) by using -b with the checkout command again. Example:\n"
+						"  git checkout -b <new_branch_name>\n", new->name);
 			describe_detached_head("HEAD is now at", new->commit);
 		}
 	}

(string split onto multiple lines for easier source reading)

I think this is important to 1) mention the notion of a branch _head_, 
and 2) mention "detached HEAD" explicitly for people to be directed to 
appropriate documentation.  So with this change you know exactly what 
happened and why.


Nicolas
Junio C Hamano· Jan 29, 2010, 22:39 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Nicolas Pitre <nico@fluxnic.net> writes:
Show 19 quoted lines
> On Fri, 29 Jan 2010, Junio C Hamano wrote:
>
>> We used to just say "topic is not a rev nor path" and failed when the user
>> said "git checkout topic".  And the magic kicks in when there is only one
>> "remotes/*/topic".
>> 
>> Because this cannot be any request other than to check out a local branch
>> "topic", and because there is no place more sensible than the "topic"
>> taken from the "origin" (as that is the sole place that has "topic"), it
>> dwims as a shorthand for "checkout -b topic origin/topic" and tells you
>> that it did so.
>
> OK.  That is probably sensible.
>
> I don't think any improvement on the detached head message should 
> presume on this though.
>
> And it might be a good idea to say explicitly that what happened is the 
> creation of a detached HEAD, like in:
Any comment on my previous rewording patch ($gmane/138369)?

"Note: '%s' isn't a local branch head: creating a detached HEAD\n" "If you want to create a new branch from this checkout, you may do so\n" "(now or later) by using -b with the checkout command again. Example:\n" " git checkout -b <new_branch_name>\n", new->name);

A major difference I think is that I avoided a jargon (detached HEAD), and chose not to say why the input was interpreted as a request to switch to that state.

Oh, of course, I also added advice.detachedHEAD to squelch it ;-)
Jacob Helwig· Jan 29, 2010, 22:46 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 14:39, Junio C Hamano <gitster@pobox.com> wrote:
Show 13 quoted lines
> Any comment on my previous rewording patch ($gmane/138369)?
>
> "Note: '%s' isn't a local branch head: creating a detached HEAD\n"
> "If you want to create a new branch from this checkout, you may do so\n"
> "(now or later) by using -b with the checkout command again. Example:\n"
> "  git checkout -b <new_branch_name>\n", new->name);
>
> A major difference I think is that I avoided a jargon (detached HEAD), and
> chose not to say why the input was interpreted as a request to switch to
> that state.
>
> Oh, of course, I also added advice.detachedHEAD to squelch it ;-)
>
For what it's worth, I'm +1 for this.  Especially the ability to squelch it.
Nicolas Pitre· Jan 29, 2010, 23:43 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Junio C Hamano wrote:
> Any comment on my previous rewording patch ($gmane/138369)?

A bit too verbose (even if it can be configured out) and frightening I'd say.

Show 8 quoted lines
> "Note: '%s' isn't a local branch head: creating a detached HEAD\n"
> "If you want to create a new branch from this checkout, you may do so\n"
> "(now or later) by using -b with the checkout command again. Example:\n"
> "  git checkout -b <new_branch_name>\n", new->name);
> 
> A major difference I think is that I avoided a jargon (detached HEAD), and
> chose not to say why the input was interpreted as a request to switch to
> that state.

To the contrary, I think it is about time we use proper Git jargon. Otherwise how can we expect people to relate to the documentation where that jargon is indeed used? Even on this very mailing list we refer to that state as a "detached HEAD". And Google gives precisely the right info with "detached HEAD" while any other verbiage might not.

And just saying that "you're not on any branch anymore" is still leaving the user wondering why. At least with the "isn't a local branch head" the user has 2 clues: it has to be a _local_ branch and a branch _head_ not to create a detached HEAD. So I still prefer the above rewording.

> Oh, of course, I also added advice.detachedHEAD to squelch it ;-)
That is indeed an excellent idea.
Nicolas
Junio C Hamano· Jan 30, 2010, 00:14 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Nicolas Pitre <nico@fluxnic.net> writes:
Show 10 quoted lines
> To the contrary, I think it is about time we use proper Git jargon.  
> Otherwise how can we expect people to relate to the documentation where 
> that jargon is indeed used?  Even on this very mailing list we refer to 
> that state as a "detached HEAD".  And Google gives precisely the right 
> info with "detached HEAD" while any other verbiage might not.
>
> And just saying that "you're not on any branch anymore" is still leaving 
> the user wondering why.  At least with the "isn't a local branch head" 
> the user has 2 clues: it has to be a _local_ branch and a branch _head_ 
> not to create a detached HEAD.  So I still prefer the above rewording.
I can buy that argument, except for three minor points:
 - I think we also should give information necessary to judge if the user
   wants to stay in the detached HEAD state.  IOW, "Why am I getting an
   insn to create a new branch?  What is wrong with this detached HEAD
   state?  Why would I want a local branch?" are still not explained with
   the updated message.
 - Do we "create" a detached HEAD, or are we just "detaching HEAD"?
 - Running "checkout -b" now will create a new branch from that checkout,
   but doing so _later_ won't necessarily do so from that _checkout_.
So how about doing this (changes to advice.[ch] are omitted)?
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 5277817..41fc00a 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -522,8 +522,16 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 		update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 			   REF_NODEREF, DIE_ON_ERR);
 		if (!opts->quiet) {
-			if (old->path)
-				fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
+			if (old->path && advice_detached_head)
+				fprintf(stderr,
+"Note: '%s' isn't a local branch head.\n\n"
+"HEAD is detached at that commit. You can look around, even make changes\n"
+"and record them in new commits, but any new commit you make from now on\n"
+"will be lost when you check out another branch.\n"
+"If you want to create a new branch from this state, you may do so\n"
+"(now or later) by using -b with the checkout command again. Example:\n"
+"  git checkout -b <new_branch_name>\n\n",
+					new->name);
 			describe_detached_head("HEAD is now at", new->commit);
 		}
 	}
Sverre Rabbelier· Jan 30, 2010, 00:18 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

Heya,
On Sat, Jan 30, 2010 at 01:14, Junio C Hamano <gitster@pobox.com> wrote:
> +"If you want to create a new branch from this state, you may do so\n"
> +"(now or later) by using -b with the checkout command again.

I think the "this state" needs to be changed, it currently suggests what you mention earlier in you reply, that it's about the current state, even if you make commits on top of that. Maybe something in the spirit of "If you want to create a new branch from ?? where you are at the moment you follow these instructions ??".

-- 
Cheers,

Sverre Rabbelier
Junio C Hamano· Jan 30, 2010, 00:29 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

Sverre Rabbelier <srabbelier@gmail.com> writes:
Show 5 quoted lines
> I think the "this state" needs to be changed, it currently suggests
> what you mention earlier in you reply, that it's about the current
> state, even if you make commits on top of that. Maybe something in the
> spirit of "If you want to create a new branch from ?? where you are at
> the moment you follow these instructions ??".
True.  And I am a moron.

The "state" was not about the work-tree state, but about the "detached HEAD" state, which I didn't make it clear.

I also didn't address "scariness" point from Nico. And scariness can be removed by describing things in a positive way.

How about this?
-- >8 -- not a patch -- >8 --
Note: 'master^0' isn't a local branch head;

You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by checking out another branch.

If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new_branch_name>

HEAD is now at a9d7c95... Merge branch 'maint' -- 8< -- not a patch -- 8< --

Again, everything except for the last line would disappear by setting the advice.detachedHEAD configuration to false.

Sverre Rabbelier· Jan 30, 2010, 00:35 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

Heya,
On Sat, Jan 30, 2010 at 01:29, Junio C Hamano <gitster@pobox.com> wrote:
> True.  And I am a moron.
Not at all, you worded it very nicely I think.
> How about this?
Definitely a major improvement, nice.
-- 
Cheers,

Sverre Rabbelier
Michael Witten· Jan 30, 2010, 00:38 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 6:29 PM, Junio C Hamano <gitster@pobox.com> wrote:
> The "state" was not about the work-tree state, but about the
> "detached HEAD" state, which I didn't make it clear.

Maybe we should just introduce people to a more explicit command like the hypothetical 'update' command I sketch here:

    http://marc.info/?l=git&m=126481166426896&w=2
Nicolas Pitre· Jan 30, 2010, 00:39 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Junio C Hamano wrote:
Show 8 quoted lines
> How about this?
> 
> -- >8 -- not a patch -- >8 --
> Note: 'master^0' isn't a local branch head;
> 
> You are in 'detached HEAD' state. You can look around, make experimental
> changes and commit them, and you can discard any commits you make in this
> state without impacting any branches by checking out another branch.
s/checking out another branch/performing another checkout/
Show 10 quoted lines
> If you want to create a new branch to retain commits you create, you may
> do so (now or later) by using -b with the checkout command again. Example:
> 
>   git checkout -b <new_branch_name>
> 
> HEAD is now at a9d7c95... Merge branch 'maint'
> -- 8< -- not a patch -- 8< --
> 
> Again, everything except for the last line would disappear by setting the
> advice.detachedHEAD configuration to false.
Looks fine to me.
Nicolas
Mark Lodato· Jan 30, 2010, 01:01 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 7:29 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 16 quoted lines
> How about this?
>
> -- >8 -- not a patch -- >8 --
> Note: 'master^0' isn't a local branch head;
>
> You are in 'detached HEAD' state. You can look around, make experimental
> changes and commit them, and you can discard any commits you make in this
> state without impacting any branches by checking out another branch.
>
> If you want to create a new branch to retain commits you create, you may
> do so (now or later) by using -b with the checkout command again. Example:
>
>  git checkout -b <new_branch_name>
>
> HEAD is now at a9d7c95... Merge branch 'maint'
> -- 8< -- not a patch -- 8< --

First off, I would like to voice support for such a warning. This is so much more clear than the current message.

Still, I find it slightly confusing and unfriendly.  How about the following?

-- >8 -- not a patch -- >8 -- Checking out commit 'master^0'.

Since this is not a local branch head, any commits you make will be lost when you check out another branch or commit. (In git terminology, HEAD is detached.) If you just wish to look at files without committing, this is fine. If you wish to make commits and retain them, you may create a new branch by running:

  git checkout -b <new_branch_name>
HEAD is now at a9d7c95... Merge branch 'maint'
 - 8< -- not a patch -- 8< --

I think the above wording is fine for both commits (e.g. master^0) and remote branches (e.g. origin/pu). With other wording, we may wish to have two slightly different messages depending on what the user typed.

Also, I am not a big fan of "local branch head". How about "not the name of a local branch"? I'm not sure...

Nicolas Pitre· Jan 30, 2010, 01:22 UTC · re: Mark Lodato · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Mark Lodato wrote:
> Still, I find it slightly confusing and unfriendly.  How about the following?
It is slightly inaccurate.
Show 9 quoted lines
> Checking out commit 'master^0'.
> 
> Since this is not a local branch head, any commits you make will be lost
> when you check out another branch or commit.  (In git terminology, HEAD
> is detached.)  If you just wish to look at files without committing,
> this is fine.  If you wish to make commits and retain them, you may
> create a new branch by running:
> 
>   git checkout -b <new_branch_name>

This gives the impression that any commit you make on a detached HEAD are going to be lost, unless you create a new branch first.

And again, it is a good thing to have "detached HEAD" in there so to relate to existing documentation easily.

> I think the above wording is fine for both commits (e.g. master^0) and
> remote branches (e.g. origin/pu).  With other wording, we may wish to
> have two slightly different messages depending on what the user typed.

You could have tags too. So instead of trying to be too smart, it is best to simply display the provided name without qualifier.

> Also, I am not a big fan of "local branch head".  How about "not the
> name of a local branch"?  I'm not sure...

The confusion that started this thread was about "master^" which might be interpreted as the name of a local branch except for the fact that we want one commit back. So using "local commit head" is more precise.

Nicolas
Ron Garret· Jan 30, 2010, 02:38 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

In article <alpine.LFD.2.00.1001292013150.1681@xanadu.home>,
 Nicolas Pitre <nico@fluxnic.net> wrote:
Show 36 quoted lines
> On Fri, 29 Jan 2010, Mark Lodato wrote:
> 
> > Still, I find it slightly confusing and unfriendly.  How about the 
> > following?
> 
> It is slightly inaccurate.
> 
> > Checking out commit 'master^0'.
> > 
> > Since this is not a local branch head, any commits you make will be lost
> > when you check out another branch or commit.  (In git terminology, HEAD
> > is detached.)  If you just wish to look at files without committing,
> > this is fine.  If you wish to make commits and retain them, you may
> > create a new branch by running:
> > 
> >   git checkout -b <new_branch_name>
> 
> This gives the impression that any commit you make on a detached HEAD 
> are going to be lost, unless you create a new branch first.
> 
> And again, it is a good thing to have "detached HEAD" in there so to 
> relate to existing documentation easily.
> 
> > I think the above wording is fine for both commits (e.g. master^0) and
> > remote branches (e.g. origin/pu).  With other wording, we may wish to
> > have two slightly different messages depending on what the user typed.
> 
> You could have tags too.  So instead of trying to be too smart, it is 
> best to simply display the provided name without qualifier.
> 
> > Also, I am not a big fan of "local branch head".  How about "not the
> > name of a local branch"?  I'm not sure...
> 
> The confusion that started this thread was about "master^" which might 
> be interpreted as the name of a local branch except for the fact that we 
> want one commit back.  So using "local commit head" is more precise.

Since it is my confusion that started this thread (and I suppose is in part responsible for continuing it) I should be clear that master^ was just an example. My first attempt to roll back to an earlier version was actually "git checkout HEAD^". That produced the same result, since HEAD was pointing to master at the time. But one of the things I realized was that HEAD was a variable, and so I chose to frame my example in terms of master instead of HEAD in order to eliminate ambiguity.

FWIW, here are some observations based on my current understanding:
1.  The term "detached HEAD" is inherently misleading.  A detached HEAD 
isn't detached from anything, it's just pointing to the middle of a 
branch, which is to say, to a commit that happens to already have 
descendants.  For that matter, the name HEAD is itself misleading, since 
HEAD need not be the head of a branch (though normally it is).  A better 
name for HEAD would have been CURRENT or ACTIVE.  I recognize it's 
probably too late to change it now.
2.  There are a lot of things in the documentation that turn out, now 
that I understand what is going on, to be subtly misleading.  For 
example, "A single git repository can track development on multiple 
branches. It does this by keeping a list of heads which reference the 
latest commit on each branch."  That last part is only true if the heads 
are not "detached".

I do not yet understand enough about git to know if this is a reasonable suggestion, but one possibility is to separate the notion of a head from the notion of a pointer to a commit. A head would be a pointer to a commit that can only point to a commit with no descendants, whereas a pointer could point anywhere. What is now called HEAD would be a pointer, not a head under this ontology.

Another example: "The HEAD then refers to the SHA-1 of the commit instead of to a branch, and git branch shows that you are no longer on a branch:" But you *are* on a branch, you just aren't at the head of the branch. In fact, by the definition of branch the whole concept of "not being on a branch" is non-sensical. (Isn't that part of the whole point of git? That everything is a branch?)

3.  These observations suggest ways in which the situation could be 
improved.

First, I think Michael Witten is on the right track with his proposal for a redesign of git-checkout and the new git-update command (though I have not yet had time to think deeply about the details). There are only a small number of things that are actually going on under the hood, and the closer the map between the command set and those primitive operations can be made the better.

Second, the real problem underlying the original warning that started all this is that if you do a commit from a "detached head" then you have effectively created a branch whether you meant to or not. This suggests a very straightforward warning:

"WARNING: Your HEAD is now pointing to a commit that has descendants. If you do a commit from here, you will be creating a branch. If this is not what you intend, read the documentation and achieve clarity before proceeding. If you just want to bail out of this situation without doing your homework, do a 'git checkout master' or something like that."

Or something like that :-)
rg
Junio C Hamano· Jan 30, 2010, 02:59 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Ron Garret <ron1@flownet.com> writes:
Show 7 quoted lines
> 1.  The term "detached HEAD" is inherently misleading.  A detached HEAD 
> isn't detached from anything, it's just pointing to the middle of a 
> branch, which is to say, to a commit that happens to already have 
> descendants.  For that matter, the name HEAD is itself misleading, since 
> HEAD need not be the head of a branch (though normally it is).  A better 
> name for HEAD would have been CURRENT or ACTIVE.  I recognize it's 
> probably too late to change it now.

This description, especially the phrase "middle of a branch" shows that you don't understand git yet. A git branch is _not_ a line (nor multiple lines) of development. It is merely a _point_ in the history.

"A commit that is in the middle of an ancestry chain with existing descendants" can be at the tip of a branch and does not have anything to do with detached HEAD state.

When HEAD points at a branch, making a commit advances _that_ branch. And we say you are "on that branch". When HEAD is detached, because it is not attached to anything, it advances no branch. "detached HEAD" is detached in the very real sense. It is not attached to _any_ branch.

Show 6 quoted lines
> 2.  There are a lot of things in the documentation that turn out, now 
> that I understand what is going on, to be subtly misleading.  For 
> example, "A single git repository can track development on multiple 
> branches. It does this by keeping a list of heads which reference the 
> latest commit on each branch."  That last part is only true if the heads 
> are not "detached".

This is from old terminology. We used to use "head" (lowercase) and "branches" pretty much interchangeably and the quoted description is from the era _before_ detached HEAD was invented, as a way to quickly get a temporary state where you can browse around freely and without having to worry about having to clean up afterwards even if you made commits in that state by simply going back to an attached state.

So do a "s/a list of heads/a list of branch pointers/" replacement and you will be fine.

> Another example: "The HEAD then refers to the SHA-1 of the commit 
> instead of to a branch, and git branch shows that you are no longer on a 
> branch:"  But you *are* on a branch, you just aren't at the head of the 
> branch.
No, you are _literally_ not on _any_ branch at that point.

Making a commit from that state does not advance _any_ branch and doing "reset --hard $commit" from that state does not affect _any_ branch.

Ron Garret· Jan 30, 2010, 03:26 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7vbpgc8fhb.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 12 quoted lines
> Ron Garret <ron1@flownet.com> writes:
> 
> > 1.  The term "detached HEAD" is inherently misleading.  A detached HEAD 
> > isn't detached from anything, it's just pointing to the middle of a 
> > branch, which is to say, to a commit that happens to already have 
> > descendants.  For that matter, the name HEAD is itself misleading, since 
> > HEAD need not be the head of a branch (though normally it is).  A better 
> > name for HEAD would have been CURRENT or ACTIVE.  I recognize it's 
> > probably too late to change it now.
> 
> This description, especially the phrase "middle of a branch" shows that
> you don't understand git yet.
That could well be, but it's not for lack of trying :-)
> A git branch is _not_ a line (nor multiple
> lines) of development.  It is merely a _point_ in the history.

By "middle of a branch" I simply meant "a commit that already has one or more descendants" (or, to be even more precise, a commit that has one or more commits that reference that commit as one of their predecessors). I do understand that histories aren't linear.

> "A commit that is in the middle of an ancestry chain with existing
> descendants" can be at the tip of a branch and does not have anything to
> do with detached HEAD state.
Ah, then you're right.  I really don't get it yet.
> When HEAD points at a branch, making a commit advances _that_ branch.  And
> we say you are "on that branch".  When HEAD is detached, because it is not
> attached to anything, it advances no branch.  "detached HEAD" is detached
> in the very real sense.  It is not attached to _any_ branch.

OK. The docs do not make that clear at all. In fact, the following statement, copied straight from the manual, flatly contradicts what you just said:

"The special symbol "HEAD" can always be used to refer to the current branch."

Always.  Except when it can't.
Soooo.....

Sometimes HEAD can refer to a branch head which is a pointer to a commit, and sometimes HEAD can refer to a commit directly without indirecting through a branch head (lower case), in which case it is detached. Is that right?

If that's true, then I'm back to wondering what good is a detached head. Why would you ever want one? What can you do with a detached head that you could not do just as easily without one?

rg
Nicolas Pitre· Jan 30, 2010, 04:03 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Ron Garret wrote:
Show 8 quoted lines
> In article <7vbpgc8fhb.fsf@alter.siamese.dyndns.org>,
>  Junio C Hamano <gitster@pobox.com> wrote:
> 
> > "A commit that is in the middle of an ancestry chain with existing
> > descendants" can be at the tip of a branch and does not have anything to
> > do with detached HEAD state.
> 
> Ah, then you're right.  I really don't get it yet.
Have a look at http://eagain.net/articles/git-for-computer-scientists/

That's one of the clearest explanation of the Git branching model I've seen.

Show 13 quoted lines
> > When HEAD points at a branch, making a commit advances _that_ branch.  And
> > we say you are "on that branch".  When HEAD is detached, because it is not
> > attached to anything, it advances no branch.  "detached HEAD" is detached
> > in the very real sense.  It is not attached to _any_ branch.
> 
> OK.  The docs do not make that clear at all.  In fact, the following 
> statement, copied straight from the manual, flatly contradicts what you 
> just said:
> 
> "The special symbol "HEAD" can always be used to refer to the current 
> branch."
> 
> Always.  Except when it can't.

There is no contradiction. The "detached HEAD" corresponds to HEAD pointing at no branch in particular. There is just no current branch in that case.

Show 6 quoted lines
> Soooo.....
> 
> Sometimes HEAD can refer to a branch head which is a pointer to a 
> commit, and sometimes HEAD can refer to a commit directly without 
> indirecting through a branch head (lower case), in which case it is 
> detached.  Is that right?
Exact.
> If that's true, then I'm back to wondering what good is a detached head.  
> Why would you ever want one?  What can you do with a detached head that 
> you could not do just as easily without one?

By definition, remote tracking branches are "read-only" because we want those branch heads to reflect what the remote repository they're tracking has. In other words, you're not supposed to add commits to a remote branch or it would move that branch to the new commit which is no longer a representation of the corresponding remote repository. In order to actually add commits on top of a remote branch, you first have to make a local branch being a copy of the remote branch of interest (which in practice means only making the local branch point at the same commit node as the remote branch) and then any commit will advance that local branch and leave the remote branch behind.

But what if you just want to check out the content corresponding to that remote branch without adding any new commits? What if you wish to do the same with a tag instead of a branch (a tag being immutable)?

If you could have HEAD pointing to a tag or a remote branch then many operations such as 'git commit' would need to be blocked in order to preserve the read-only nature of such references.

The detached HEAD solves the issue really neatly in those cases. Instead of having HEAD pointing to a remote branch record, the detached HEAD points directly at the provided commit from the remote branch head or tag, and any commit operation will simply update that direct reference alone, creating a fork point in the history graph.

If you wish to preserve this branch in the graph sense then you can create a new branch head with the current HEAD position. Or if you don't care about those commits you made on the detached HEAD, then simply moving HEAD to anything else with another checkout command will drop and forget about that string of commits you created.

So a detached HEAD is useful for checking out a read-only branch or tag without having to forbid a bunch of operations or needing for you to create a dummy temporary local branch just for the purpose of such a checkout. Many operations with intermediate states such as 'git rebase' or 'git bisect' can be implemented without polluting the branch namespace, etc.

Nicolas
Jay Soffian· Jan 30, 2010, 05:06 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 11:03 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> Have a look at http://eagain.net/articles/git-for-computer-scientists/
>
> That's one of the clearest explanation of the Git branching model I've
> seen.

Ah, I never realized this before, but it doesn't include any discussion/graphic of what a detached HEAD is. It only shows HEAD referring to a named branch.

> There is no contradiction.  The "detached HEAD" corresponds to HEAD
> pointing at no branch in particular.  There is just no current branch in
> that case.

Again (referring to my last message), I think Ron's confusion is that "branch" can mean either a branch in the DAG which is your repo's history, or it can mean a named branch (something under .git/refs), and they aren't necessarily the same, although around here when we say "branch" we almost always mean a named branch.

When HEAD is detached and you create a commit, you're effectively creating a branch in the DAG, but this branch is anonymous and subject to garbage collection.

j.
Junio C Hamano· Jan 30, 2010, 05:09 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Ron Garret <ron1@flownet.com> writes:
Show 8 quoted lines
>> When HEAD points at a branch, making a commit advances _that_ branch.  And
>> we say you are "on that branch".  When HEAD is detached, because it is not
>> attached to anything, it advances no branch.  "detached HEAD" is detached
>> in the very real sense.  It is not attached to _any_ branch.
>
> OK.  The docs do not make that clear at all.  In fact, the following 
> statement, copied straight from the manual, flatly contradicts what you 
> just said:

There are many places in the documentation that simply predate the introduction of detached HEAD. The description talks as if you cannot be in any state other than on a particular branch. For example, "git pull" talks about choosing where to fetch from and what to merge to the head based on what your current branch is---obviously such a description is ancient and doesn't talk about what should happen when you do not simply have any "current" branch.

So it is understandable that you get confused and it is all documentation's fault, not yours.

> "The special symbol "HEAD" can always be used to refer to the current 
> branch."
>
> Always.  Except when it can't.
Exactly.

We would need to update the documentation. While doing so, a general guideline would be to keep in mind that they were written back when you had to always be on _a_ branch (and they called it "current branch", "branch HEAD points at", etc.). When they describe that "the current branch is updated in such and such way", what happens in a detached HEAD state is that only the HEAD pointer that directly points at the "currently checked out commit" is updated, without affecting _any_ branch.

Jay Soffian· Jan 30, 2010, 04:52 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 9:59 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 22 quoted lines
> Ron Garret <ron1@flownet.com> writes:
>
>> 1.  The term "detached HEAD" is inherently misleading.  A detached HEAD
>> isn't detached from anything, it's just pointing to the middle of a
>> branch, which is to say, to a commit that happens to already have
>> descendants.  For that matter, the name HEAD is itself misleading, since
>> HEAD need not be the head of a branch (though normally it is).  A better
>> name for HEAD would have been CURRENT or ACTIVE.  I recognize it's
>> probably too late to change it now.
>
> This description, especially the phrase "middle of a branch" shows that
> you don't understand git yet.  A git branch is _not_ a line (nor multiple
> lines) of development.  It is merely a _point_ in the history.
>
> "A commit that is in the middle of an ancestry chain with existing
> descendants" can be at the tip of a branch and does not have anything to
> do with detached HEAD state.
>
> When HEAD points at a branch, making a commit advances _that_ branch.  And
> we say you are "on that branch".  When HEAD is detached, because it is not
> attached to anything, it advances no branch.  "detached HEAD" is detached
> in the very real sense.  It is not attached to _any_ branch.

Let me try wording this slightly different, because I think I can see Ron's confusion.

HEAD normally refers to a named branch. For example "master" (technically, HEAD would contain "ref: refs/heads/master"), but we'll just say "master" for now.

Meanwhile, the branch named "master" refers to a specific commit by its SHA-1 hash.

The particular commit which "master" refers to is a branch head.

Now, when you create a commit in this state, the branch named "master" is updated with the SHA-1 of the new commit. So let's say you create a new repo and have three commits. Your history would look like this:

a---b---c master (HEAD is "ref: refs/heads/master")

That is, if you look at .git/HEAD, it will say "ref: refs/heads/master" and if you look at .git/refs/heads/master it will have the SHA-1 of commit "c". If you create a new commit:

a---b---c---d master (HEAD is "ref: refs/heads/master")

.git/HEAD still says "ref: refs/heads/master" but now .git/refs/heads/master has the SHA-1 of commit "d".

Okay, now let's talk about what happens when you type:
$ git checkout master^
At this point, git updates HEAD to contain the SHA-1 of "c":
a---b---c---d master (HEAD is c's SHA-1)

You now have a "detached HEAD" because HEAD doesn't refer to any named branch. Instead it refers to a specific commit by its SHA-1. So let's create a new commit while HEAD is detached:

a---b---c---d master
         \
          e   (HEAD is e's SHA-1)

So, yes, you've created a "branch" in the DAG sense of the word. But this branch is anonymous since it has no name. That means that commit "e" is subject to garbage collection and may be removed. If you want to keep it around, then you need to create a name for it. Git provides you a number of ways to "name" commits:

$ git checkout -b foo # (1) $ git branch foo # (2) $ git tag foo # (3)

(1) will create .git/refs/heads/foo, make it have the SHA-1 of commit "e", then update HEAD to say "ref: refs/heads/foo". You are now "on" branch "foo" and any commits you create will update .git/refs/heads/foo:

a---b---c---d master
         \
          e  foo (HEAD is "ref: refs/heads/foo")

(2) will also create .refs/heads/foo, and make it have the SHA-1 of commit "e", but will leave HEAD as it is:

a---b---c---d master
         \
          e  foo (HEAD is SHA-1 of "e")

You still have a detached HEAD and any commits you create that descend from "e" are still subject to garbage collection (although "e" itself is not), as follows:

a---b---c---d master
         \
          e  <-- foo
           \
            f (HEAD is SHA-1 of "f")
(3) creates .refs/tags/foo, but is otherwise the same as (2).

So that was a really long explanation, but I hope it clears things up. I think the disconnect between you and Junio is that you're thinking of branches in the DAG sense of the word, while Junio is talking about them in the context of git.

j.
Nicolas Pitre· Jan 30, 2010, 05:15 UTC · re: Jay Soffian · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Jay Soffian wrote:
Show 7 quoted lines
> > When HEAD points at a branch, making a commit advances _that_ branch.  And
> > we say you are "on that branch".  When HEAD is detached, because it is not
> > attached to anything, it advances no branch.  "detached HEAD" is detached
> > in the very real sense.  It is not attached to _any_ branch.
> 
> Let me try wording this slightly different, because I think I can see
> Ron's confusion.
[...]

Could you please take this really nice explanation and make it into a patch adding a "Detached HEAD" section in the git-checkout.txt manual page please?

Nicolas
Junio C Hamano· Jan 30, 2010, 05:21 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Nicolas Pitre <nico@fluxnic.net> writes:
> Could you please take this really nice explanation and make it into a 
> patch adding a "Detached HEAD" section in the git-checkout.txt manual 
> page please?
Good suggestion.

I'd be happier if the description didn't say "SHA-1", but instead said "object name".

Also it would be nicer (just a personal preference) if a picture that forks only one branch forks it upwards, like this:

             o---o
            /    
    ---o---o---o
not downwards, like this:
    ---o---o---o
            \
             o---o
Ron Garret· Jan 30, 2010, 06:25 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7v1vh8417w.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 23 quoted lines
> Nicolas Pitre <nico@fluxnic.net> writes:
> 
> > Could you please take this really nice explanation and make it into a 
> > patch adding a "Detached HEAD" section in the git-checkout.txt manual 
> > page please?
> 
> Good suggestion.
> 
> I'd be happier if the description didn't say "SHA-1", but instead said
> "object name".
> 
> Also it would be nicer (just a personal preference) if a picture that
> forks only one branch forks it upwards, like this:
> 
>              o---o
>             /    
>     ---o---o---o
> 
> not downwards, like this:
> 
>     ---o---o---o
>             \
>              o---o

Just out of curiosity, why does this matter to you? Downwards seems more intuitive to me. Time should advance left to right and top to bottom IMHO.

rg
Junio C Hamano· Jan 30, 2010, 18:25 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Ron Garret <ron1@flownet.com> writes:
Show 14 quoted lines
>> Also it would be nicer (just a personal preference) if a picture that
>> forks only one branch forks it upwards, like this:
>> 
>>              o---o
>>             /    
>>     ---o---o---o
>> 
>> not downwards, like this:
>> 
>>     ---o---o---o
>>             \
>>              o---o
>
> Just out of curiosity, why does this matter to you?

Imagine you pick up the whole assembly and let it fall (gravity works from top to bottom of the sheet of paper it is printed on, not from above down to the face of paper it is printed on)? Which one looks more stable and would land on the floor as-is?

The top one, of course. It sits better when printed, and especially so when it is presented as an illustration that comes before a paragraph, which is a more-or-less rectangular-looking block of text; at least it looks that way to me.

Didn't I say it is just a "personal preference"?  ;-)
Jay Soffian· Jan 30, 2010, 05:45 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

On Sat, Jan 30, 2010 at 12:15 AM, Nicolas Pitre <nico@fluxnic.net> wrote:
> Could you please take this really nice explanation and make it into a
> patch adding a "Detached HEAD" section in the git-checkout.txt manual
> page please?
Will do, and I'll even make the branches go upwards. :-)
j.
Junio C Hamano· Jan 30, 2010, 05:18 UTC · re: Jay Soffian · lore

Re: master^ is not a local branch -- huh?!?

Jay Soffian <jaysoffian@gmail.com> writes:
> So that was a really long explanation, but I hope it clears things up.
> I think the disconnect between you and Junio is that you're thinking
> of branches in the DAG sense of the word, while Junio is talking about
> them in the context of git.

Yeah, in short, a "branch" is a point, not a line (or lines) of development that leads to a point, as I said in the beginning.

Ron Garret· Jan 30, 2010, 06:23 UTC · re: Jay Soffian · lore

Re: master^ is not a local branch -- huh?!?

In article 
<76718491001292052x7f46d479lfeff7b66121502c3@mail.gmail.com>,
 Jay Soffian <jaysoffian@gmail.com> wrote:
Show 26 quoted lines
> On Fri, Jan 29, 2010 at 9:59 PM, Junio C Hamano <gitster@pobox.com> wrote:
> > Ron Garret <ron1@flownet.com> writes:
> >
> >> 1.  The term "detached HEAD" is inherently misleading.  A detached HEAD
> >> isn't detached from anything, it's just pointing to the middle of a
> >> branch, which is to say, to a commit that happens to already have
> >> descendants.  For that matter, the name HEAD is itself misleading, since
> >> HEAD need not be the head of a branch (though normally it is).  A better
> >> name for HEAD would have been CURRENT or ACTIVE.  I recognize it's
> >> probably too late to change it now.
> >
> > This description, especially the phrase "middle of a branch" shows that
> > you don't understand git yet.  A git branch is _not_ a line (nor multiple
> > lines) of development.  It is merely a _point_ in the history.
> >
> > "A commit that is in the middle of an ancestry chain with existing
> > descendants" can be at the tip of a branch and does not have anything to
> > do with detached HEAD state.
> >
> > When HEAD points at a branch, making a commit advances _that_ branch.  And
> > we say you are "on that branch".  When HEAD is detached, because it is not
> > attached to anything, it advances no branch.  "detached HEAD" is detached
> > in the very real sense.  It is not attached to _any_ branch.
> 
> Let me try wording this slightly different, because I think I can see
> Ron's confusion.
[snip]
> So that was a really long explanation, but I hope it clears things up.
Yes, that was very helpful, thank you.

Might it make more sense to talk about "anonymous branches" or "unnamed branches" instead of "detached heads"? I think something like the following would be much easier to grasp:

WARNING: Your HEAD is now pointing to a commit that is not a named
branch head.  As a result of this, any commits off of this one may
be lost during the next garbage collection.  If you want to prevent
this, you should give this branch head a name by doing ...
rg
Mark Lodato· Jan 30, 2010, 02:40 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 8:22 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
Show 5 quoted lines
> On Fri, 29 Jan 2010, Mark Lodato wrote:
>
>> Still, I find it slightly confusing and unfriendly.  How about the following?
>
> It is slightly inaccurate.
Is the following the only inaccuracy?  Do you have any other feedback?
Show 12 quoted lines
>> Checking out commit 'master^0'.
>>
>> Since this is not a local branch head, any commits you make will be lost
>> when you check out another branch or commit.  (In git terminology, HEAD
>> is detached.)  If you just wish to look at files without committing,
>> this is fine.  If you wish to make commits and retain them, you may
>> create a new branch by running:
>>
>>   git checkout -b <new_branch_name>
>
> This gives the impression that any commit you make on a detached HEAD
> are going to be lost, unless you create a new branch first.

What about "...you may want to create..."? This does not imply that creating a new branch now is the *only* way, just the most likely. If a user knows another way, that user probably does not need this warning in the first place.

Nicolas Pitre· Jan 30, 2010, 03:11 UTC · re: Mark Lodato · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Mark Lodato wrote:
Show 26 quoted lines
> On Fri, Jan 29, 2010 at 8:22 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> > On Fri, 29 Jan 2010, Mark Lodato wrote:
> >
> >> Still, I find it slightly confusing and unfriendly.  How about the following?
> >
> > It is slightly inaccurate.
> 
> Is the following the only inaccuracy?  Do you have any other feedback?
> 
> >> Checking out commit 'master^0'.
> >>
> >> Since this is not a local branch head, any commits you make will be lost
> >> when you check out another branch or commit.  (In git terminology, HEAD
> >> is detached.)  If you just wish to look at files without committing,
> >> this is fine.  If you wish to make commits and retain them, you may
> >> create a new branch by running:
> >>
> >>   git checkout -b <new_branch_name>
> >
> > This gives the impression that any commit you make on a detached HEAD
> > are going to be lost, unless you create a new branch first.
> 
> What about "...you may want to create..."?  This does not imply that
> creating a new branch now is the *only* way, just the most likely.  If
> a user knows another way, that user probably does not need this
> warning in the first place.

Still, you don't know what way the unsuspected user will take to get there.

Do you still have a problem with the latest version of the text from Junio? Looks like you based your modification on an earlier version.

Nicolas
Mark Lodato· Jan 30, 2010, 03:59 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 10:11 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
Show 26 quoted lines
> On Fri, 29 Jan 2010, Mark Lodato wrote:
>> On Fri, Jan 29, 2010 at 8:22 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
>> > On Fri, 29 Jan 2010, Mark Lodato wrote:
>> >
>> >> Still, I find it slightly confusing and unfriendly.  How about the following?
>> >
>> >> Checking out commit 'master^0'.
>> >>
>> >> Since this is not a local branch head, any commits you make will be lost
>> >> when you check out another branch or commit.  (In git terminology, HEAD
>> >> is detached.)  If you just wish to look at files without committing,
>> >> this is fine.  If you wish to make commits and retain them, you may
>> >> create a new branch by running:
>> >>
>> >>   git checkout -b <new_branch_name>
>> >
>> > This gives the impression that any commit you make on a detached HEAD
>> > are going to be lost, unless you create a new branch first.
>>
>> What about "...you may want to create..."?  This does not imply that
>> creating a new branch now is the *only* way, just the most likely.  If
>> a user knows another way, that user probably does not need this
>> warning in the first place.
>
> Still, you don't know what way the unsuspected user will take to get
> there.

Sorry, I don't understand. What do you mean by "take to get there"? Are you referring to how the user arrived in this detached HEAD state, or what the user wishes to do next? Either way, I still am not sure why this wording is no good. Could please elaborate?

> Do you still have a problem with the latest version of the text from
> Junio?  Looks like you based your modification on an earlier version.
Yes, I do.  I thought his earlier version was more clear.  Particularly:
  Note: 'master^0' isn't a local branch head;

This isn't very friendly. It sounds like an admonition. Rather, I suggest that the first sentence be similar to, but distinct from, "Switched to branch foo," to inform the user that they did something different, which may or may not be intentional.

  You are in 'detached HEAD' state. You can look around, make experimental
  changes and commit them, and you can discard any commits you make in this
  state without impacting any branches by checking out another branch.

First, we shouldn't start off with the term "detached HEAD". I used a parenthetical comment to mention it, in case the user wants to look it up or refer to this state. Otherwise, the term conveys no meaning, unless one understand enough about git to not need this advice.

Second, this advice should be a warning that commits may be lost unless one knows what one is doing. Saying "you can discard commits" makes it sound like a feature! Sure, that may be so for advanced users, but for beginners (for whom this advice is intended), this is a common trap. I tried to word the advice so that the users will know that they should not commit without first creating a branch (or knowing what they're doing), but that if they don't commit, there's no problem. The wording quoted above does not convey this meaning to me.

  If you want to create a new branch to retain commits you create, you may
  do so (now or later) by using -b with the checkout command again. Example:
    git checkout -b <new_branch_name>
I basically retained this, with rewording.

This discussion brings up another good point: The main worry about a detached head is losing commits. Back in 2008, it was suggested to have a warning when committing on a detached HEAD:

http://kerneltrap.org/mailarchive/git/2008/9/2/3169744

This was before the advice system, so folks complained about it getting in the way, and it was never implemented. Since we now have a way to easily turn off the warning, perhaps we should bring this topic up again (probably as a separate thread.)

Nicolas Pitre· Jan 30, 2010, 04:39 UTC · re: Mark Lodato · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Mark Lodato wrote:
Show 30 quoted lines
> On Fri, Jan 29, 2010 at 10:11 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> > On Fri, 29 Jan 2010, Mark Lodato wrote:
> >> On Fri, Jan 29, 2010 at 8:22 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> >> > On Fri, 29 Jan 2010, Mark Lodato wrote:
> >> >
> >> >> Still, I find it slightly confusing and unfriendly.  How about the following?
> >> >
> >> >> Checking out commit 'master^0'.
> >> >>
> >> >> Since this is not a local branch head, any commits you make will be lost
> >> >> when you check out another branch or commit.  (In git terminology, HEAD
> >> >> is detached.)  If you just wish to look at files without committing,
> >> >> this is fine.  If you wish to make commits and retain them, you may
> >> >> create a new branch by running:
> >> >>
> >> >>   git checkout -b <new_branch_name>
> >> >
> >> > This gives the impression that any commit you make on a detached HEAD
> >> > are going to be lost, unless you create a new branch first.
> >>
> >> What about "...you may want to create..."?  This does not imply that
> >> creating a new branch now is the *only* way, just the most likely.  If
> >> a user knows another way, that user probably does not need this
> >> warning in the first place.
> >
> > Still, you don't know what way the unsuspected user will take to get
> > there.
> 
> Sorry, I don't understand.  What do you mean by "take to get there"?
> Are you referring to how the user arrived in this detached HEAD state,
Yes.
> or what the user wishes to do next?  Either way, I still am not sure
> why this wording is no good.  Could please elaborate?

First, I'm afraid that "Checking out commit 'foobar'" might be confusing as this may happen through either a remote branch, a tag, or any random commit. It seems to me that "Checking out 'v2.5'" is less confusing than "Checking out commit 'v2.5'". But that's a minor detail and probably a personal preference.

Show 6 quoted lines
>   Note: 'master^0' isn't a local branch head;
> 
> This isn't very friendly.  It sounds like an admonition.  Rather, I
> suggest that the first sentence be similar to, but distinct from,
> "Switched to branch foo," to inform the user that they did something
> different, which may or may not be intentional.

I consider that starting the explanation paragraph with " any commits you make will be lost" is even more unfriendly, and misleading. That is sure to scare people needlessly.

Show 8 quoted lines
>   You are in 'detached HEAD' state. You can look around, make experimental
>   changes and commit them, and you can discard any commits you make in this
>   state without impacting any branches by checking out another branch.
> 
> First, we shouldn't start off with the term "detached HEAD".  I used a
> parenthetical comment to mention it, in case the user wants to look it
> up or refer to this state.  Otherwise, the term conveys no meaning,
> unless one understand enough about git to not need this advice.

To the contrary: this "detached HEAD" is exactly what you need if you want to relate to any documentation or perform a search for more information. Like it or not, this detached HEAD term is exactly what this Git concept is all about and how it is designated everywhere. The sooner Git users see and learn about it the better.

Show 8 quoted lines
> Second, this advice should be a warning that commits may be lost
> unless one knows what one is doing.  Saying "you can discard commits"
> makes it sound like a feature!  Sure, that may be so for advanced
> users, but for beginners (for whom this advice is intended), this is a
> common trap.  I tried to word the advice so that the users will know
> that they should not commit without first creating a branch (or
> knowing what they're doing), but that if they don't commit, there's no
> problem.  The wording quoted above does not convey this meaning to me.

I think your wording is just too far on the negative side, and makes Git look like an even more difficult tool than it actually is. And you help no one by stating things that are not exactly true even if the truth implies that you need to know what you're doing. The _whole_ and only point of a detached HEAD is actually to be able to make commits even without having to create a new branch first.

Show 10 quoted lines
> This discussion brings up another good point: The main worry about a
> detached head is losing commits.  Back in 2008, it was suggested to
> have a warning when committing on a detached HEAD:
> 
> http://kerneltrap.org/mailarchive/git/2008/9/2/3169744
> 
> This was before the advice system, so folks complained about it
> getting in the way, and it was never implemented.  Since we now have a
> way to easily turn off the warning, perhaps we should bring this topic
> up again (probably as a separate thread.)

Possibly. I don't like the message proposed in that patch though. Since the warning when actually detaching HEAD is about to become way more prominent, the per-commit warning doesn't have to be that noisy anymore.

Nicolas
Nicolas Pitre· Jan 30, 2010, 05:05 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010, Nicolas Pitre wrote:
Show 17 quoted lines
> On Fri, 29 Jan 2010, Mark Lodato wrote:
> 
> > This discussion brings up another good point: The main worry about a
> > detached head is losing commits.  Back in 2008, it was suggested to
> > have a warning when committing on a detached HEAD:
> > 
> > http://kerneltrap.org/mailarchive/git/2008/9/2/3169744
> > 
> > This was before the advice system, so folks complained about it
> > getting in the way, and it was never implemented.  Since we now have a
> > way to easily turn off the warning, perhaps we should bring this topic
> > up again (probably as a separate thread.)
> 
> Possibly.  I don't like the message proposed in that patch though.  
> Since the warning when actually detaching HEAD is about to become way 
> more prominent, the per-commit warning doesn't have to be that noisy 
> anymore.

Thinking more about it, I still consider that making 'git commit' more noisy is the wrong approach. Again, the problem is not about making commits on a detached HEAD. but rather about losing those commits at the next 'git checkout'. Probably a warning should be made when that checkout is attempted after one or more commits were made on a detached HEAD instead, and refuse the checkout by default unless it is forced (-f is already taken for some other force meaning). The warning should say how not to lose those commits by suggesting a branch creation, or give the hint for performing the checkout anyway.

Nicolas
Jay Soffian· Jan 30, 2010, 05:11 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

On Sat, Jan 30, 2010 at 12:05 AM, Nicolas Pitre <nico@fluxnic.net> wrote:
Show 9 quoted lines
> Thinking more about it, I still consider that making 'git commit' more
> noisy is the wrong approach.  Again, the problem is not about making
> commits on a detached HEAD.  but rather about losing those commits at
> the next 'git checkout'.  Probably a warning should be made when that
> checkout is attempted after one or more commits were made on a detached
> HEAD instead, and refuse the checkout by default unless it is forced (-f
> is already taken for some other force meaning).  The warning should say
> how not to lose those commits by suggesting a branch creation, or give
> the hint for performing the checkout anyway.

This sounds right to me too. There's nothing wrong with having a detached HEAD, and nothing wrong with creating commits in that state. You're effectively creating an anonymous branch in the DAG and it's subject to garbage collection if you move away from that anonymous branch w/o naming it.

Pedantic note: you don't lose those commits at the next checkout. They are merely subject to garbage collection (and not until they age out of HEAD's reflog). I know you know that, just being precise. :-)

j.
Nicolas Pitre· Jan 30, 2010, 05:25 UTC · re: Jay Soffian · lore

Re: master^ is not a local branch -- huh?!?

On Sat, 30 Jan 2010, Jay Soffian wrote:
Show 9 quoted lines
> This sounds right to me too. There's nothing wrong with having a
> detached HEAD, and nothing wrong with creating commits in that state.
> You're effectively creating an anonymous branch in the DAG and it's
> subject to garbage collection if you move away from that anonymous
> branch w/o naming it.
> 
> Pedantic note: you don't lose those commits at the next checkout. They
> are merely subject to garbage collection (and not until they age out
> of HEAD's reflog). I know you know that, just being precise. :-)

Being the actual author of the code managing the separate HEAD reflog, I do know that indeed. ;-)

Nicolas
Mark Lodato· Jan 30, 2010, 05:53 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 11:39 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
Show 5 quoted lines
> First, I'm afraid that "Checking out commit 'foobar'" might be confusing
> as this may happen through either a remote branch, a tag, or any random
> commit.  It seems to me that "Checking out 'v2.5'" is less confusing
> than "Checking out commit 'v2.5'".  But that's a minor detail and
> probably a personal preference.
I'm fine with "Checking out 'v2.5'".
> I consider that starting the explanation paragraph with " any commits
> you make will be lost" is even more unfriendly, and misleading.  That is
> sure to scare people needlessly.
See wording below.
> I think your wording is just too far on the negative side, and makes Git
> look like an even more difficult tool than it actually is.  And you help
> no one by stating things that are not exactly true even if the truth
> implies that you need to know what you're doing.

What is not true? Sure, they're not really "lost", but there's no concise yet fully correct way to say the full truth. Would you prefer "discarded"?

> The _whole_ and only
> point of a detached HEAD is actually to be able to make commits even
> without having to create a new branch first.

Wrong. I have never (purposefully) made a commit on a detached HEAD, yet I use a detached HEAD all the time. Why? Because I checkout a particular commit to look at code at a given location. For example, I recently ran "git checkout v1.6.6.1". I did not intend to make any commits on this; I just wanted to look at and compile code at a particular version. I think most users do the same thing. The reason for the warning is that folks make a mistake of trying to commit without first switching back to (or creating) a branch.

Anyway, how about the following message, which is more in line with Junio's last version?

-- >8 -- not a patch -- >8 -- Checking out 'master^0'.

This is not a local branch head, so you are in a 'detached HEAD' state. If you only plan to look at files, this is fine. However, any commits you make will not update a branch, and may be discarded when you check out another branch or commit.

If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example:

 git checkout -b <new_branch_name>

HEAD is now at a9d7c95... Merge branch 'maint' -- 8< -- not a patch -- 8< --

Junio C Hamano· Jan 30, 2010, 06:03 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Nicolas Pitre <nico@fluxnic.net> writes:
Show 11 quoted lines
> First, I'm afraid that "Checking out commit 'foobar'" might be confusing 
> as this may happen through either a remote branch, a tag, or any random 
> commit.  It seems to me that "Checking out 'v2.5'" is less confusing 
> than "Checking out commit 'v2.5'".  But that's a minor detail and 
> probably a personal preference.
> ...
> To the contrary: this "detached HEAD" is exactly what you need if you 
> want to relate to any documentation or perform a search for more 
> information.  Like it or not, this detached HEAD term is exactly what 
> this Git concept is all about and how it is designated everywhere.  The 
> sooner Git users see and learn about it the better.

As I am not good at keeping track of different proposals to change this word here and that word there, I expect this will probably need at least few rotations of earth to get input from people in different timezones, and I think this is post 1.7.0 item anyway, I'll queue the attached draft in 'pu' and keep it there, to make it easier for others to tweak the message.

-- >8 --
Subject: [PATCH] Reword "detached HEAD" notification

The old "advice" message explained how to create a branch after going into a detached HEAD state but didn't make it clear why the user may want to do so. Also "moving to ... which isn't a local branch" was unclear if it is complaining, if it is describing the new state, or if it is explaining why the HEAD is detached (the true reason is the last one).

Give the established phrase 'detached HEAD' first to make it easy for users to look up the concept in documentation, and briefly describe what can be done in the state (i.e. play around without having to clean up) before telling the user how to keep what was done during the temporary state.

Allow the long description to be hidden by setting advice.detachedHead configuration to false.

We might want to customize the advice depending on how the commit to check out was spelled (e.g. instead of "new-branch-name", we way want to say "topic" when "git checkout origin/topic" triggered this message) in later updates, but this encapsulates that into a separate function and it should be a good first step.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/config.txt |    5 +++++
 advice.c                 |    2 ++
 advice.h                 |    1 +
 builtin-checkout.c       |   18 ++++++++++++++++--
 t/t7201-co.sh            |   32 ++++++++++++++++++++++----------
 5 files changed, 46 insertions(+), 12 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 17901e2..fee44d8 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -138,6 +138,11 @@ advice.*::
 		Advice on how to set your identity configuration when
 		your information is guessed from the system username and
 		domain name. Default: true.
+
+	detachedHead::
+		Advice shown when you used linkgit::git-checkout[1] to
+		move to the detach HEAD state, to instruct how to create
+		a local branch after the fact.  Default: true.
 --
 
 core.fileMode::
diff --git a/advice.c b/advice.c
index 936d98b..0be4b5f 100644
--- a/advice.c
+++ b/advice.c
@@ -5,6 +5,7 @@ int advice_status_hints = 1;
 int advice_commit_before_merge = 1;
 int advice_resolve_conflict = 1;
 int advice_implicit_identity = 1;
+int advice_detached_head = 1;
 
 static struct {
 	const char *name;
@@ -15,6 +16,7 @@ static struct {
 	{ "commitbeforemerge", &advice_commit_before_merge },
 	{ "resolveconflict", &advice_resolve_conflict },
 	{ "implicitidentity", &advice_implicit_identity },
+	{ "detachedhead", &advice_detached_head },
 };
 
 int git_default_advice_config(const char *var, const char *value)
diff --git a/advice.h b/advice.h
index 9b7a3ad..3244ebb 100644
--- a/advice.h
+++ b/advice.h
@@ -8,6 +8,7 @@ extern int advice_status_hints;
 extern int advice_commit_before_merge;
 extern int advice_resolve_conflict;
 extern int advice_implicit_identity;
+extern int advice_detached_head;
 
 int git_default_advice_config(const char *var, const char *value);
 
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 5277817..c5ab783 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -488,6 +488,20 @@ static void report_tracking(struct branch_info *new)
 	strbuf_release(&sb);
 }
 
+static void detach_advice(const char *old_path, const char *new_name)
+{
+	const char fmt[] =
+	"Note: checking out '%s'.\n\n"
+	"You are in 'detached HEAD' state. You can look around, make experimental\n"
+	"changes and commit them, and you can discard any commits you make in this\n"
+	"state without impacting any branches by performing another checkout.\n\n"
+	"If you want to create a new branch to retain commits you create, you may\n"
+	"do so (now or later) by using -b with the checkout command again. Example:\n\n"
+	"  git checkout -b new_branch_name\n\n";
+
+	fprintf(stderr, fmt, new_name);
+}
+
 static void update_refs_for_switch(struct checkout_opts *opts,
 				   struct branch_info *old,
 				   struct branch_info *new)
@@ -522,8 +536,8 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 		update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 			   REF_NODEREF, DIE_ON_ERR);
 		if (!opts->quiet) {
-			if (old->path)
-				fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
+			if (old->path && advice_detached_head)
+				detach_advice(old->path, new->name);
 			describe_detached_head("HEAD is now at", new->commit);
 		}
 	}
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 6442f71..d20ed61 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -166,19 +166,31 @@ test_expect_success 'checkout -m with merge conflict' '
 	! test -s current
 '
 
-test_expect_success 'checkout to detach HEAD' '
+test_expect_success 'checkout to detach HEAD (with advice declined)' '
 
+	git config advice.detachedHead false &&
 	git checkout -f renamer && git clean -f &&
 	git checkout renamer^ 2>messages &&
-	(cat >messages.expect <<EOF
-Note: moving to '\''renamer^'\'' which isn'\''t a local branch
-If you want to create a new branch from this checkout, you may do so
-(now or later) by using -b with the checkout command again. Example:
-  git checkout -b <new_branch_name>
-HEAD is now at 7329388... Initial A one, A two
-EOF
-) &&
-	test_cmp messages.expect messages &&
+	grep "HEAD is now at 7329388" messages &&
+	test 1 -eq $(wc -l <messages) &&
+	H=$(git rev-parse --verify HEAD) &&
+	M=$(git show-ref -s --verify refs/heads/master) &&
+	test "z$H" = "z$M" &&
+	if git symbolic-ref HEAD >/dev/null 2>&1
+	then
+		echo "OOPS, HEAD is still symbolic???"
+		false
+	else
+		: happy
+	fi
+'
+
+test_expect_success 'checkout to detach HEAD' '
+	git config advice.detachedHead true &&
+	git checkout -f renamer && git clean -f &&
+	git checkout renamer^ 2>messages &&
+	grep "HEAD is now at 7329388" messages &&
+	test 1 -lt $(wc -l <messages) &&
 	H=$(git rev-parse --verify HEAD) &&
 	M=$(git show-ref -s --verify refs/heads/master) &&
 	test "z$H" = "z$M" &&
-- 
1.7.0.rc0.187.g226c
Jeff King· Jan 30, 2010, 08:59 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 04:51:18PM -0500, Nicolas Pitre wrote:
Show 14 quoted lines
> > Using a detached head is a more advanced feature than wanting to
> > checkout a remote branch locally, creating a local tracking branch. As
> > such, 'git checkout origin/topic' now means the same as 'git checkout
> > -t origin/topic', and you can get the old behavior back by doing 'git
> > checkout origin/topic^0'.
> 
> What purpose does this "feature" serve?  Making sure people remain 
> stupid and get even more confused when the special dwimery doesn't work 
> because they don't know the difference between a local branch and a 
> remote tracking branch?
> 
> And now people will be left wondering why after a fetch they don't get 
> the latest stuff when they do "git checkout topic" again.  Is this any 
> better?

I am entering the discussion a bit late, and things have moved on from this point, but I wanted to mention that I have in the past made the same argument that you have in your second paragraph (that you leave users _more_ confused after a fetch), but somebody (I think Jay) managed to convince me otherwise.

The saving feature is that we now print out the symmetric difference information between a branch and its upstream during checkout. So the user experience looks like:

  $ git checkout topic
  Branch topic set up to track remote branch topic from origin.
  Switched to a new branch 'topic'
  ... time passes ...
  $ git fetch
  ...
     9f137a4..22ac6a6  topic      -> origin/topic
  $ git checkout topic
  Switched to branch 'topic'
  Your branch is behind 'origin/topic' by 6 commits, and can be fast-forwarded.

So I think it is not quite as bad as at least I had originally thought. There are still a few rough edges, though:

  1. If I stay on the 'topic' branch and run "git fetch", then I don't
     see the checkout message. If I don't understand that a local branch
     has been created, I might expect the new changes to be present. But
     they're not. If I do a pull instead, it does "just work", even if I
     am clueless about the local branch.
     I wonder if a "fetch" which updates the upstream branch of the
     current HEAD should print something like the "Your branch is
     behind..." message.
  2. If I am clueless that the local branch exists, I can see that there
     are new changes that I can "fast forward". But if I am clueless
     about local branches, do I know that means I need to run "git merge
     origin/topic"?  However, I can't think of an improved message that
     would make the situation clear without adding a bunch of annoying
     text.
-Peff
Ron Garret· Jan 30, 2010, 18:40 UTC · re: Jeff King · lore

Re: master^ is not a local branch -- huh?!?

In article <20100130085957.GA20112@coredump.intra.peff.net>,
 Jeff King <peff@peff.net> wrote:
>      I can't think of an improved message that
>      would make the situation clear without adding a bunch of annoying
>      text.

In situations like that a pointer to the docs, or a keyword to search on is often sufficient.

rg
A Large Angry SCM· Jan 29, 2010, 23:16 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

Sverre Rabbelier wrote:
Show 16 quoted lines
> Heya,
> 
> On Fri, Jan 29, 2010 at 22:29, Nicolas Pitre <nico@fluxnic.net> wrote:
>> Then who was arguing about making Git more user friendly rather
>> then less?
> 
> Using a detached head is a more advanced feature than wanting to
> checkout a remote branch locally, creating a local tracking branch. As
> such, 'git checkout origin/topic' now means the same as 'git checkout
> -t origin/topic', and you can get the old behavior back by doing 'git
> checkout origin/topic^0'. I don't see what the problem is, if you're
> using a detached head you're an advanced enough git user that you can
> remember that you can use '^0' to detach your head. It's not all that
> uncommon to do 'git checkout HEAD^0' to detach your head to the
> current branch, no?
> 
[I'm still catching up on this thread]

What we call 'Detached head' is _the_ normal way ti use git for quite a number of users. And given the current UI, it's not really advanced.

Junio C Hamano· Jan 29, 2010, 21:49 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Nicolas Pitre <nico@fluxnic.net> writes:
Show 12 quoted lines
>> These days, you can say "git checkout topic" to automagically create a
>> local "topic" branch that forks from "origin/topic" remote tracking branch
>> when you have one, thanks to Dscho's UI improvement ideas (one less
>> reason you may end up on a detached HEAD state without wanting to).
>
> If this is the case then I'm really disappointed.
>
> With all due respects, I don't share Dscho's sentiment about Git's 
> alleged non user-friendliness.  And I always praised Git's ability to 
> use a detached head to check out a remote branch, and never had any 
> problem teaching this concept to people.  So the above is not a UI 
> improvement at all to me.
Just in case you misunderstood...

This is "git checkout topic", not "git checkout origin/topic". The rule kicks in when you do not have local branch "topic" and there is a unique "refs/remotes/*/topic". Existing ways to explicitly ask for detaching are unaffected, so "checkout origin/topic" or "checkout origin/topic^0" do what you expect.

We used to just say "topic is not a rev nor path" and failed when the user sayd "git checkout topic".

Because this cannot be any request other than to check out a local branch "topic", and because there is no place more sensible than the "topic" taken from the "origin" (as that is the sole place that has "topic"), it dwims as a shorthand for "checkout -b topic origin/topic" and tells you that it did so.

Johannes Schindelin· Jan 30, 2010, 02:13 UTC · re: Nicolas Pitre · lore

Re: master^ is not a local branch -- huh?!?

Hi,
On Fri, 29 Jan 2010, Nicolas Pitre wrote:
> With all due respects, I don't share Dscho's sentiment about Git's 
> alleged non user-friendliness.

Of course you don't. You are a Git oldtimer. Probably you do not even have much exposure to complete programming newbies.

Well, guess what. I have. And guess what even more: they are the majority, not you and me.

Ciao, Dscho

Nicolas Pitre· Jan 30, 2010, 03:15 UTC · re: Johannes Schindelin · lore

Re: master^ is not a local branch -- huh?!?

On Sat, 30 Jan 2010, Johannes Schindelin wrote:
Show 9 quoted lines
> Hi,
> 
> On Fri, 29 Jan 2010, Nicolas Pitre wrote:
> 
> > With all due respects, I don't share Dscho's sentiment about Git's 
> > alleged non user-friendliness.
> 
> Of course you don't.  You are a Git oldtimer.  Probably you do not even 
> have much exposure to complete programming newbies.
Welllll... That depends.

If you mean people who, despite a CS degree, are still unable to figure out if some loop exit condition should be > or >= except by testing the compiled code and see if a crash occurs, then yes I do feel the pain of being exposed to such people way too often for my taste. And frankly I just don't care if those people can't grok the Git UI.

Git is meant to be a tool for people performing a minimum of development tasks. If those people can't grasp the Git UI and concepts with little effort then they're either 1) uninterested or 2) incompetent. For the uninterested people there are GUIs out there. And don't get me started on the incompetent ones.

And for the rest of the world, such as my boss, there is gitweb.
> Well, guess what.  I have.  And guess what even more: they are the 
> majority, not you and me.

Did you ever got them to use P4? I'm convinced that learning how to use P4 for a Git user is way more painful than a P4 user to learn Git. Similarly for Arch or many other alternatives.

HG looks easier? Sure. But it isn't exactly as flexible and powerful as Git is though. You prefer a less powerful but simpler tool? OK just go with HG then -- I have no problem with that. Even SVN might be just what you need. But if you prefer the power of Git then there is a price to pay for it. Making Git simpler would inevitably reduces its power.

I hope newbies won't stay newbies all their life. If the majority of all the people are newbies then no need to wonder why there is so much crap being produced by the computing industry then. Learning isn't only a nasty thing that they force you to do at school and which you get over with once you escape from there.

Incidentally we've been getting more positive feedback than negative ones about Git from newbies on this list lately. That might be because our UI, although still not perfect, improved quite a bit, and most probably because the documentation surrounding Git has improved tremendously too.

Nicolas
Johannes Schindelin· Jan 29, 2010, 20:35 UTC · re: Jacob Helwig · lore

Re: master^ is not a local branch -- huh?!?

Hi,
On Fri, 29 Jan 2010, Jacob Helwig wrote:
Show 21 quoted lines
> On Fri, Jan 29, 2010 at 12:20, Ron1 <ron1@flownet.com> wrote:
> > [ron@mickey]$ git checkout master
> > Already on 'master'
> > [ron@mickey]$ git checkout master^
> > Note: moving to 'master^' which isn't a local branch
> > If you want to create a new branch from this checkout, you may do so
> > (now or later) by using -b with the checkout command again. Example:
> >  git checkout -b <new_branch_name>
> > HEAD is now at 7be05e0... test
> > [ron@mickey]$ git branch
> > * (no branch)
> >  master
> > [ron@mickey]$
> >
> > Huh?!?
> >
> > This is a test repository which has never been pulled from nor pushed to
> > anywhere.  So how is it possible that I have a non-local branch?
> 
> master^ is a commit (the first parent of master), not a branch (local
> or otherwise).

Indeed. Maybe you (Ron1) need to get a bit more acquainted to Git before complaining.

Git is not user-friendly (much to my chagrin, and I tried to change it, but it is not going to happen), so the only way out is to really read up on good tutorials/manuals before you complain about something that is not working as you expect it.

Just as a general hint, I think the best documentation about Git was written by J. Bruce Fields (the user manual) and Scott Chacon (everything that has GitHub written on it, and Git Pro, and much, much more). If you happen to speak Japanese, Junio's book might help you understand the ideas behind the current Git user interface, too.

Hth, Dscho

Ron1· Jan 29, 2010, 21:16 UTC · re: Johannes Schindelin · lore

Re: master^ is not a local branch -- huh?!?

In article <alpine.DEB.1.00.1001292131330.3749@intel-tinevez-2-302>,
 Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
Show 28 quoted lines
> Hi,
> 
> On Fri, 29 Jan 2010, Jacob Helwig wrote:
> 
> > On Fri, Jan 29, 2010 at 12:20, Ron1 <ron1@flownet.com> wrote:
> > > [ron@mickey]$ git checkout master
> > > Already on 'master'
> > > [ron@mickey]$ git checkout master^
> > > Note: moving to 'master^' which isn't a local branch
> > > If you want to create a new branch from this checkout, you may do so
> > > (now or later) by using -b with the checkout command again. Example:
> > >  git checkout -b <new_branch_name>
> > > HEAD is now at 7be05e0... test
> > > [ron@mickey]$ git branch
> > > * (no branch)
> > >  master
> > > [ron@mickey]$
> > >
> > > Huh?!?
> > >
> > > This is a test repository which has never been pulled from nor pushed to
> > > anywhere.  So how is it possible that I have a non-local branch?
> > 
> > master^ is a commit (the first parent of master), not a branch (local
> > or otherwise).
> 
> Indeed.  Maybe you (Ron1) need to get a bit more acquainted to Git before 
> complaining.
Chill, dude.  I'm not complaining.  I'm just confused.

I know that master^ is a commit and not a branch.  I thought I was invoking the third variant of git-checkout (as given on the git-checkout man page) and checking out a commit (which the man page calls a tree-ish).

In any case, since my question seems to have sparked some discussion, I'd like to offer two observations:

1.  Saying "isn't a local branch" is mightily confusing, because it is 
ambiguous whether the problem is that it isn't a branch or if it isn't 
local.
2.  If I pass something to git checkout (or any other command for that 
matter) that it expects to be a branch but isn't a branch it would be 
much better if it just gave an error and did nothing rather than give a 
(confusing) warning and try to extrapolate the user's intentions.  
Whatever a user could possibly mean by 'git checkout master^' it is 
almost certainly not what that command actually does at the moment.
rg
Jacob Helwig· Jan 29, 2010, 21:25 UTC · re: Ron1 · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 13:16, Ron1 <ron1@flownet.com> wrote:
Show 19 quoted lines
> I know that master^ is a commit and not a branch.  I thought I was
> invoking the third variant of git-checkout (as given on the git-checkout
> man page) and checking out a commit (which the man page calls a
> tree-ish).
>
> In any case, since my question seems to have sparked some discussion,
> I'd like to offer two observations:
>
> 1.  Saying "isn't a local branch" is mightily confusing, because it is
> ambiguous whether the problem is that it isn't a branch or if it isn't
> local.
>
> 2.  If I pass something to git checkout (or any other command for that
> matter) that it expects to be a branch but isn't a branch it would be
> much better if it just gave an error and did nothing rather than give a
> (confusing) warning and try to extrapolate the user's intentions.
> Whatever a user could possibly mean by 'git checkout master^' it is
> almost certainly not what that command actually does at the moment.
>

I don't think that #2 would be possible. My understanding is that branches are basically just there as convenient "names" for arbitrary commits. In other words (in my understanding): There is no place that expects a "branch" where a commit (SHA-1) would not work (and be a perfectly valid use).

Ron Garret· Jan 29, 2010, 21:43 UTC · re: Jacob Helwig · lore

Re: master^ is not a local branch -- huh?!?

In article <8c9a061001291325i4b8898b9m46054040c69f8fc6@mail.gmail.com>,
 Jacob Helwig <jacob.helwig@gmail.com> wrote:
Show 22 quoted lines
> On Fri, Jan 29, 2010 at 13:16, Ron1 <ron1@flownet.com> wrote:
> > I know that master^ is a commit and not a branch.  I thought I was
> > invoking the third variant of git-checkout (as given on the git-checkout
> > man page) and checking out a commit (which the man page calls a
> > tree-ish).
> >
> > In any case, since my question seems to have sparked some discussion,
> > I'd like to offer two observations:
> >
> > 1.  Saying "isn't a local branch" is mightily confusing, because it is
> > ambiguous whether the problem is that it isn't a branch or if it isn't
> > local.
> >
> > 2.  If I pass something to git checkout (or any other command for that
> > matter) that it expects to be a branch but isn't a branch it would be
> > much better if it just gave an error and did nothing rather than give a
> > (confusing) warning and try to extrapolate the user's intentions.
> > Whatever a user could possibly mean by 'git checkout master^' it is
> > almost certainly not what that command actually does at the moment.
> >
> 
> I don't think that #2 would be possible.

Of course it's possible. It git can complain and do something (which is what it does now) then it can just as easily complain and do nothing.

Show 5 quoted lines
> My understanding is that
> branches are basically just there as convenient "names" for arbitrary
> commits.  In other words (in my understanding): There is no place that
> expects a "branch" where a commit (SHA-1) would not work (and be a
> perfectly valid use).

No, that's not true. Branches have names that are recorded separately from non-branch commits. It's not a big difference, but it is a difference.

rg
Junio C Hamano· Jan 29, 2010, 21:59 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Ron Garret <ron1@flownet.com> writes:
> Of course it's possible.  It git can complain and do something (which is 
> what it does now) then it can just as easily complain and do nothing.

It is not complaining. It is telling you that you might have triggered an advanced feature you may not be prepared to use yet.

So forbidding the advanced feature from everybody won't be a solution.
Ron Garret· Jan 29, 2010, 22:18 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7veil8h8rk.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 9 quoted lines
> Ron Garret <ron1@flownet.com> writes:
> 
> > Of course it's possible.  It git can complain and do something (which is 
> > what it does now) then it can just as easily complain and do nothing.
> 
> It is not complaining.  It is telling you that you might have triggered an
> advanced feature you may not be prepared to use yet.
> 
> So forbidding the advanced feature from everybody won't be a solution.
s/complain/warn/

I'm just suggesting that maybe triggering the advanced feature ought not to be such an easy thing to do by accident. It's certainly possible to make that change. Reasonable people could disagree over whether this is desirable, or whether it would be better to just add this to a FAQ somewhere, or maybe even just leave this as a rite of passage. Apparently I'm the first person to ever have this problem or it would not have triggered so much discussion.

rg
Junio C Hamano· Jan 31, 2010, 07:32 UTC · re: Johannes Schindelin · lore

Re: master^ is not a local branch -- huh?!?

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> Just as a general hint, I think the best documentation about Git was 
> written by J. Bruce Fields (the user manual) and Scott Chacon (everything 
> that has GitHub written on it, and Git Pro, and much, much more).
The last one is "Pro Git": http://progit.org/book/; highly recommended.
> ... If you
> happen to speak Japanese, Junio's book might help you understand the ideas 
> behind the current Git user interface, too.
Nah, I don't talk about UIs.  I talk more about concepts.
Octavio Alvarez· Jan 29, 2010, 20:32 UTC · re: Ron1 · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010 12:20:46 -0800, Ron1 <ron1@flownet.com> wrote:
Show 17 quoted lines
> [ron@mickey]$ git checkout master
> Already on 'master'
> [ron@mickey]$ git checkout master^
> Note: moving to 'master^' which isn't a local branch
> If you want to create a new branch from this checkout, you may do so
> (now or later) by using -b with the checkout command again. Example:
>   git checkout -b <new_branch_name>
> HEAD is now at 7be05e0... test
> [ron@mickey]$ git branch
> * (no branch)
>   master
> [ron@mickey]$
>
> Huh?!?
>
> This is a test repository which has never been pulled from nor pushed to
> anywhere.  So how is it possible that I have a non-local branch?
"Is a non-local branch" is not the same as "is not a local branch".
Think "branches" as tags that advance when you commit over them.

If you do gitk --all, only those commits with a green tag are "branches".

It means that if you switch to master^ and commit, your commit will be applied but not tracked (since there is not any branch to advance).

You would need to do git checkout -b 'new_branch', and then commit. Now, new_branch will advance with your new commit.

Ron Garret· Jan 29, 2010, 21:34 UTC · re: Octavio Alvarez · lore

Re: master^ is not a local branch -- huh?!?

In article <op.u7a909hf4oyyg1@alvarezp-ws>,
 "Octavio Alvarez" <alvarezp@alvarezp.ods.org> wrote:
Show 32 quoted lines
> On Fri, 29 Jan 2010 12:20:46 -0800, Ron1 <ron1@flownet.com> wrote:
> 
> > [ron@mickey]$ git checkout master
> > Already on 'master'
> > [ron@mickey]$ git checkout master^
> > Note: moving to 'master^' which isn't a local branch
> > If you want to create a new branch from this checkout, you may do so
> > (now or later) by using -b with the checkout command again. Example:
> >   git checkout -b <new_branch_name>
> > HEAD is now at 7be05e0... test
> > [ron@mickey]$ git branch
> > * (no branch)
> >   master
> > [ron@mickey]$
> >
> > Huh?!?
> >
> > This is a test repository which has never been pulled from nor pushed to
> > anywhere.  So how is it possible that I have a non-local branch?
> 
> "Is a non-local branch" is not the same as "is not a local branch".
> 
> Think "branches" as tags that advance when you commit over them.
> 
> If you do gitk --all, only those commits with a green tag are
> "branches".
> 
> It means that if you switch to master^ and commit, your commit will
> be applied but not tracked (since there is not any branch to advance).
> 
> You would need to do git checkout -b 'new_branch', and then commit.
> Now, new_branch will advance with your new commit.
OK, I think I understand that.
Here's the thing: I can do this:
git checkout commit-id filename

and restore a particular revision of a particular file to my working tree without affecting my HEAD pointer. I would expect then that

git checkout commit-id

with no filename would do the same thing, except restore the entire tree from that commit (including deleting files that didnt' exist then). And indeed it does that (or at least appears to -- I haven't explored this in depth), except that it DOES move my HEAD pointer to this weird non-branch thing.

Here's what I think would be the correct behavior:
[ron@mickey]$ git checkout master^

"WARNING: master^ is not a branch. It is a commit on the master branch. Since the the commit you are asking for is on the same branch as your current HEAD pointer, here's what I'm going to do:

1.  Copy the master^ commit to your working tree
2.  Leave your HEAD pointer where is was (i.e. pointing to the head
of the master branch).

If this is not what you wanted, you can undo it by typing "git checkout HEAD". Also, in the future, you can avoid this warning by typing ... instead.

Or something like that.
rg
Octavio Alvarez· Jan 29, 2010, 22:32 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010 13:34:01 -0800, Ron Garret <ron1@flownet.com> wrote:
Show 27 quoted lines
> In article <op.u7a909hf4oyyg1@alvarezp-ws>,
>  "Octavio Alvarez" <alvarezp@alvarezp.ods.org> wrote:
>
>> On Fri, 29 Jan 2010 12:20:46 -0800, Ron1 <ron1@flownet.com> wrote:
>>
>> It means that if you switch to master^ and commit, your commit will
>> be applied but not tracked (since there is not any branch to advance).
>>
>> You would need to do git checkout -b 'new_branch', and then commit.
>> Now, new_branch will advance with your new commit.
>
> OK, I think I understand that.
>
> Here's the thing: I can do this:
>
> git checkout commit-id filename
>
> and restore a particular revision of a particular file to my working
> tree without affecting my HEAD pointer.  I would expect then that
>
> git checkout commit-id
>
> with no filename would do the same thing, except restore the entire tree
> from that commit (including deleting files that didnt' exist then).  And
> indeed it does that (or at least appears to -- I haven't explored this
> in depth), except that it DOES move my HEAD pointer to this weird
> non-branch thing.

I see. You somehow imply that "git checkout commit-id" overlaps with "git reset --hard commit-id".

Even assuming the behavior was not documented in man git-checkout, the second example looks useless. What is your use case? What would you do after having all the files in the tree switched to another commit, without actually updating HEAD to the commit, other than git reset --hard again or git revert?

Ron Garret· Jan 29, 2010, 22:47 UTC · re: Octavio Alvarez · lore

Re: master^ is not a local branch -- huh?!?

In article <op.u7bfjni44oyyg1@alvarezp-ws>,
 "Octavio Alvarez" <alvarezp@alvarezp.ods.org> wrote:
Show 32 quoted lines
> On Fri, 29 Jan 2010 13:34:01 -0800, Ron Garret <ron1@flownet.com> wrote:
> 
> > In article <op.u7a909hf4oyyg1@alvarezp-ws>,
> >  "Octavio Alvarez" <alvarezp@alvarezp.ods.org> wrote:
> >
> >> On Fri, 29 Jan 2010 12:20:46 -0800, Ron1 <ron1@flownet.com> wrote:
> >>
> >> It means that if you switch to master^ and commit, your commit will
> >> be applied but not tracked (since there is not any branch to advance).
> >>
> >> You would need to do git checkout -b 'new_branch', and then commit.
> >> Now, new_branch will advance with your new commit.
> >
> > OK, I think I understand that.
> >
> > Here's the thing: I can do this:
> >
> > git checkout commit-id filename
> >
> > and restore a particular revision of a particular file to my working
> > tree without affecting my HEAD pointer.  I would expect then that
> >
> > git checkout commit-id
> >
> > with no filename would do the same thing, except restore the entire tree
> > from that commit (including deleting files that didnt' exist then).  And
> > indeed it does that (or at least appears to -- I haven't explored this
> > in depth), except that it DOES move my HEAD pointer to this weird
> > non-branch thing.
> 
> I see. You somehow imply that "git checkout commit-id" overlaps with
> "git reset --hard commit-id".

I'm not intentionally implying that. I don't think git reset --hard does what I want either (but I could be wrong about that).

Show 5 quoted lines
> Even assuming the behavior was not documented in man git-checkout, the
> second example looks useless. What is your use case? What would you do
> after having all the files in the tree switched to another commit,
> without actually updating HEAD to the commit, other than git reset --hard
> again or git revert?
My actual use case is very complicated, but here's a simplified version:

Suppose I'm using git as a back-end for a wiki. I want to look at the state of the entire wiki as it was in some point in the past, and I also want to be able to look at the diffs between individual pages as they were then and as they are now. The most straightforward way I can think of to do that is to simply copy an old commit into my working tree without changing anything else. Then I can look at the old version by simply looking at the files, and I can get the diffs by simply doing a git diff.

If I do a git reset --hard then I get the old version, but I lose my HEAD pointer so that git diff doesn't give me what I want any more.

BTW, it turns out that git checkout [commit] . doesn't do the right thing either. Apparently, it still updates my index, so git diff still doesn't do the right thing.

rg
Octavio Alvarez· Jan 29, 2010, 23:05 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010 14:47:49 -0800, Ron Garret <ron1@flownet.com> wrote:
Show 5 quoted lines
>
> My actual use case is very complicated, but here's a simplified version:
>
> Suppose I'm using git as a back-end for a wiki.  I want to look at the
> state of the entire wiki as it was in some point in the past,
mkdir new_dir; git archive --format=tar tree-ish | tar -C new_dir -x

Of course, this is slower than just checking out the files that differ, I agree.

> and I also
> want to be able to look at the diffs between individual pages as they
> were then and as they are now.
git diff commit-ish1 commit-ish2 file1 file2 ...

Or you could just clone it and compare whatever you want there and just erase when done. This would allow you to do "git pull" from the origin.

> If I do a git reset --hard then I get the old version, but I lose my
> HEAD pointer so that git diff doesn't give me what I want any more.

You could tag the current version before resetting and then issue git reset --hard the_tag, but I guess you would run into race conditions: someone updates the wiki while the HEAD is in another commit.

Hope it helps. :-)
Junio C Hamano· Jan 29, 2010, 23:12 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Ron Garret <ron1@flownet.com> writes:
Show 6 quoted lines
> My actual use case is very complicated, but here's a simplified version:
>
> Suppose I'm using git as a back-end for a wiki.  I want to look at the 
> state of the entire wiki as it was in some point in the past, and I also 
> want to be able to look at the diffs between individual pages as they 
> were then and as they are now.

Don't think you are so special ;-) "git checkout $that_old_commit" was invented _exactly_ for that use case. You can look around from that state, and when you are done sightseeing, you can come back by doing a "git checkout master" (or whichever branch you want to be on).

You don't necessarily have to check out an old state if the only thing you are interested in is to review how the contents changed over time. Use "git log -p" (from the current tip) for that.

If you chose to have an old checkout and then traverse the changes over time leading to the current tip, you would say "git log -p ..master" instead.

Ron Garret· Jan 29, 2010, 23:30 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7vk4v0fqts.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 10 quoted lines
> Ron Garret <ron1@flownet.com> writes:
> 
> > My actual use case is very complicated, but here's a simplified version:
> >
> > Suppose I'm using git as a back-end for a wiki.  I want to look at the 
> > state of the entire wiki as it was in some point in the past, and I also 
> > want to be able to look at the diffs between individual pages as they 
> > were then and as they are now.
> 
> Don't think you are so special ;-)
Never.  :-)
> "git checkout $that_old_commit" was
> invented _exactly_ for that use case.  You can look around from that
> state, and when you are done sightseeing, you can come back by doing a
> "git checkout master" (or whichever branch you want to be on).

Yes, that's what I would have expected. Except that it not only updates my working tree, it updates my head also, so git diff doesn't give me the diffs that I want. (This makes sense for the usual use case.)

Show 7 quoted lines
> You don't necessarily have to check out an old state if the only thing
> you are interested in is to review how the contents changed over time.
> Use "git log -p" (from the current tip) for that.
> 
> If you chose to have an old checkout and then traverse the changes over
> time leading to the current tip, you would say "git log -p ..master"
> instead.
There's also this:
git rev-list HEAD -- [filename]
git ls-tree [some-hash-from-the-list-above]
Then for each line in the result:
git cat-file blob [hash] > [filename]
which seems like a horrible hack, but actually does what I want.
rg
Julian Phillips· Jan 29, 2010, 23:28 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

On Fri, 29 Jan 2010 14:47:49 -0800, Ron Garret <ron1@flownet.com> wrote:
> My actual use case is very complicated, but here's a simplified version:
> 
> Suppose I'm using git as a back-end for a wiki.  I want to look at the 
> state of the entire wiki as it was in some point in the past, and I also
> want to be able to look at the diffs between individual pages as they 
> were then and as they are now.  The most straightforward way I can think
Show 11 quoted lines
> of to do that is to simply copy an old commit into my working tree 
> without changing anything else.  Then I can look at the old version by 
> simply looking at the files, and I can get the diffs by simply doing a 
> git diff.
> 
> If I do a git reset --hard then I get the old version, but I lose my 
> HEAD pointer so that git diff doesn't give me what I want any more.
> 
> BTW, it turns out that git checkout [commit] . doesn't do the right 
> thing either.  Apparently, it still updates my index, so git diff still 
> doesn't do the right thing.
If I understand what you want correctly, then:
git diff --cached -R [path]
should be the appropriate command after the "git checkout <commit> .".
-- 
Julian
Ron Garret· Jan 30, 2010, 00:14 UTC · re: Julian Phillips · lore

Re: master^ is not a local branch -- huh?!?

In article <bd7fb2a884e55e176eea3002fd0c68dd@212.159.54.234>,
 Julian Phillips <julian@quantumfyre.co.uk> wrote:
Show 26 quoted lines
> On Fri, 29 Jan 2010 14:47:49 -0800, Ron Garret <ron1@flownet.com> wrote:
> > My actual use case is very complicated, but here's a simplified version:
> > 
> > Suppose I'm using git as a back-end for a wiki.  I want to look at the 
> > state of the entire wiki as it was in some point in the past, and I also
> 
> > want to be able to look at the diffs between individual pages as they 
> > were then and as they are now.  The most straightforward way I can think
> 
> > of to do that is to simply copy an old commit into my working tree 
> > without changing anything else.  Then I can look at the old version by 
> > simply looking at the files, and I can get the diffs by simply doing a 
> > git diff.
> > 
> > If I do a git reset --hard then I get the old version, but I lose my 
> > HEAD pointer so that git diff doesn't give me what I want any more.
> > 
> > BTW, it turns out that git checkout [commit] . doesn't do the right 
> > thing either.  Apparently, it still updates my index, so git diff still 
> > doesn't do the right thing.
> 
> If I understand what you want correctly, then:
> 
> git diff --cached -R [path]
> 
> should be the appropriate command after the "git checkout <commit> .".

Yep, that works. Alternatively, is there a way to clear the index? Seems like that would be better.

rg
Ron Garret· Jan 30, 2010, 00:18 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

In article <ron1-A99355.16145629012010@news.gmane.org>,
 Ron Garret <ron1@flownet.com> wrote:
Show 32 quoted lines
> In article <bd7fb2a884e55e176eea3002fd0c68dd@212.159.54.234>,
>  Julian Phillips <julian@quantumfyre.co.uk> wrote:
> 
> > On Fri, 29 Jan 2010 14:47:49 -0800, Ron Garret <ron1@flownet.com> wrote:
> > > My actual use case is very complicated, but here's a simplified version:
> > > 
> > > Suppose I'm using git as a back-end for a wiki.  I want to look at the 
> > > state of the entire wiki as it was in some point in the past, and I also
> > 
> > > want to be able to look at the diffs between individual pages as they 
> > > were then and as they are now.  The most straightforward way I can think
> > 
> > > of to do that is to simply copy an old commit into my working tree 
> > > without changing anything else.  Then I can look at the old version by 
> > > simply looking at the files, and I can get the diffs by simply doing a 
> > > git diff.
> > > 
> > > If I do a git reset --hard then I get the old version, but I lose my 
> > > HEAD pointer so that git diff doesn't give me what I want any more.
> > > 
> > > BTW, it turns out that git checkout [commit] . doesn't do the right 
> > > thing either.  Apparently, it still updates my index, so git diff still 
> > > doesn't do the right thing.
> > 
> > If I understand what you want correctly, then:
> > 
> > git diff --cached -R [path]
> > 
> > should be the appropriate command after the "git checkout <commit> .".
> 
> Yep, that works.  Alternatively, is there a way to clear the index?  
> Seems like that would be better.

Well, whaddyaknow: git reset without any arguments has a use after all :-)

rg
Junio C Hamano· Jan 30, 2010, 19:02 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Ron Garret <ron1@flownet.com> writes:
>> > > If I do a git reset --hard then I get the old version, but I lose my 
>> > > HEAD pointer so that git diff doesn't give me what I want any more.

I think it would be helpful to point out one issue that may hurt you (and anybody who thinks "git update --tree" without --index is a good idea).

Keeping the index and HEAD in sync but matching the work tree files to that of a different commit has one major downside. To git, a work tree file that does not exist in the index is a yet-to-be-added-untracked file (that is how and why "rm --cached file" works, for example). It won't participate in the diff output (other than being treated as "no such file in the work tree version").

Suppose that you used to have a path in older revision, but not in the current revision. You remove everything from the work tree and replace it with the files in the older revision, and you do not touch HEAD nor index. "git diff -R" appears to show "what changed since that older version and the latest", because it compares what is in the index relative to what is in the work tree. Nice.

Not quite. Since the index does not know that path you recently removed, you won't see that path. If you run "git ls-files" for a list of files known to git, it wouldn't be shown either.

Your original "git checkout master^" is a valid and probably the optimal way to get a checkout of a older revision (which you could feed to your running Lisp interpreter, in addition to being able to run "less" and "make" on them). Exactly because the index is updated to that of the older version, you won't lose the sight of the path that you removed in a later version, and you can review the change with "git diff -R master".

I think this is an XY problem that comes from your wanting to use "git diff" (compare work tree with index) instead of "git diff $commit", and that was because you wanted to use "HEAD" as a name of a commit. If you used a branch name you originally came from, none of this desire to "keep index intact" or "keep HEAD intact" would have been necessary.

But this is all tangent; I think you now know more about git to improve your IDE integration, without fighting with git but instead taking advantage of it.

Ron Garret· Jan 30, 2010, 19:24 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7veil7pgb2.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 38 quoted lines
> Ron Garret <ron1@flownet.com> writes:
> 
> >> > > If I do a git reset --hard then I get the old version, but I lose my 
> >> > > HEAD pointer so that git diff doesn't give me what I want any more.
> 
> I think it would be helpful to point out one issue that may hurt you (and
> anybody who thinks "git update --tree" without --index is a good idea).
> 
> Keeping the index and HEAD in sync but matching the work tree files to
> that of a different commit has one major downside.  To git, a work tree
> file that does not exist in the index is a yet-to-be-added-untracked file
> (that is how and why "rm --cached file" works, for example).  It won't
> participate in the diff output (other than being treated as "no such file
> in the work tree version").
> 
> Suppose that you used to have a path in older revision, but not in the
> current revision.  You remove everything from the work tree and replace it
> with the files in the older revision, and you do not touch HEAD nor index.
> "git diff -R" appears to show "what changed since that older version and
> the latest", because it compares what is in the index relative to what is
> in the work tree.  Nice.
> 
> Not quite.  Since the index does not know that path you recently removed,
> you won't see that path.  If you run "git ls-files" for a list of files
> known to git, it wouldn't be shown either.
> 
> Your original "git checkout master^" is a valid and probably the optimal
> way to get a checkout of a older revision (which you could feed to your
> running Lisp interpreter, in addition to being able to run "less" and
> "make" on them).  Exactly because the index is updated to that of the
> older version, you won't lose the sight of the path that you removed in a
> later version, and you can review the change with "git diff -R master".
> 
> I think this is an XY problem that comes from your wanting to use "git
> diff" (compare work tree with index) instead of "git diff $commit", and
> that was because you wanted to use "HEAD" as a name of a commit.  If you
> used a branch name you originally came from, none of this desire to "keep
> index intact" or "keep HEAD intact" would have been necessary.
That's a very good point.
> But this is all tangent; I think you now know more about git to improve
> your IDE integration, without fighting with git but instead taking
> advantage of it.
I hope so :-)

Thanks to everyone who responded in this thread. It's been very educational. I am very impressed at how supportive this community is to a newcomer like me.

rg
Scott R. Godin· Jan 29, 2010, 20:36 UTC · re: Ron1 · lore

Re: master^ is not a local branch -- huh?!?

On 01/29/2010 03:20 PM, Ron1 wrote:
Show 21 quoted lines
> [ron@mickey]$ git checkout master
> Already on 'master'
> [ron@mickey]$ git checkout master^
> Note: moving to 'master^' which isn't a local branch
> If you want to create a new branch from this checkout, you may do so
> (now or later) by using -b with the checkout command again. Example:
>    git checkout -b<new_branch_name>
> HEAD is now at 7be05e0... test
> [ron@mickey]$ git branch
> * (no branch)
>    master
> [ron@mickey]$
>
> Huh?!?
>
> This is a test repository which has never been pulled from nor pushed to
> anywhere.  So how is it possible that I have a non-local branch?
>
> Thanks,
> rg
>

I believe what you're seeing is known as a detached head (see <http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html> though I could be wrong about this.)

I think you may have intended to do git checkout HEAD^ or something similar? basically what you did was (I think) checkout (or attempt to checkout) the parent commit on master.

this may offer some additional food for thought: <http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html#_exploring_history>

-- 
(please respond to the list as opposed to my email box directly,
unless you are supplying private information you don't want public
on the list)
Ron Garret· Jan 29, 2010, 21:24 UTC · re: Scott R. Godin · lore

Re: master^ is not a local branch -- huh?!?

In article <hjvgs1$rep$1@ger.gmane.org>,
 "Scott R. Godin" <scottg.wp-hackers@mhg2.com> wrote:
Show 29 quoted lines
> On 01/29/2010 03:20 PM, Ron1 wrote:
> > [ron@mickey]$ git checkout master
> > Already on 'master'
> > [ron@mickey]$ git checkout master^
> > Note: moving to 'master^' which isn't a local branch
> > If you want to create a new branch from this checkout, you may do so
> > (now or later) by using -b with the checkout command again. Example:
> >    git checkout -b<new_branch_name>
> > HEAD is now at 7be05e0... test
> > [ron@mickey]$ git branch
> > * (no branch)
> >    master
> > [ron@mickey]$
> >
> > Huh?!?
> >
> > This is a test repository which has never been pulled from nor pushed to
> > anywhere.  So how is it possible that I have a non-local branch?
> >
> > Thanks,
> > rg
> >
> 
> I believe what you're seeing is known as a detached head (see 
> <http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html> 
> though I could be wrong about this.)
> 
> I think you may have intended to do git checkout HEAD^ or something 
> similar?

Yes, in fact that is exactly what I am trying to do. But that has the same result.

> basically what you did was (I think) checkout (or attempt to 
> checkout) the parent commit on master.

Yes. I posted it that way simply because 'git commit HEAD' depends on what HEAD is. If HEAD is the head of master (which it was) then the result is the same.

> 
> this may offer some additional food for thought: 
> <http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html#_exploring_h
> istory>

Yes, I read that. But what I'm trying to do is not just *look* at the history, I want to restore my working tree to a previous version. The "Exploring History" section of the docs doesn't say how to do that.

rg
Sverre Rabbelier· Jan 29, 2010, 21:28 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Heya,
On Fri, Jan 29, 2010 at 22:24, Ron Garret <ron1@flownet.com> wrote:
> Yes, I read that.  But what I'm trying to do is not just *look* at the
> history, I want to restore my working tree to a previous version.  The
> "Exploring History" section of the docs doesn't say how to do that.

Do you want to restore your working tree only, or also throw away the history? If the former, you could look at 'git revert', if the latter, 'git reset --hard' could be what you need (warning: the latter is a destructive command that will let you _throw away history_).

-- 
Cheers,

Sverre Rabbelier
Ron Garret· Jan 29, 2010, 21:40 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

In article 
<fabb9a1e1001291328s1df443d6jdf0501cda17072de@mail.gmail.com>,
 Sverre Rabbelier <srabbelier@gmail.com> wrote:
Show 8 quoted lines
> Heya,
> 
> On Fri, Jan 29, 2010 at 22:24, Ron Garret <ron1@flownet.com> wrote:
> > Yes, I read that.  But what I'm trying to do is not just *look* at the
> > history, I want to restore my working tree to a previous version.  The
> > "Exploring History" section of the docs doesn't say how to do that.
> 
> Do you want to restore your working tree only,
Yes.
> or also throw away the history?
No.
> If the former, you could look at 'git revert'

If that's the right answer then the docs needs serious revision. The docs for "git revert" say that what it does is:

"Given one existing commit, revert the change the patch introduces, and record a new commit that records it."

which does not sound at all like what I'm trying to do.

All I want to do is copy an old commit to my working tree, nothing else. I don't want to move my head pointer. I don't want to muck with my index. I don't want to commit any changes or undo any history. It's a very simple thing. It ought to be simple to do, but it doesn't seem to be.

rg
Junio C Hamano· Jan 29, 2010, 21:54 UTC · re: Sverre Rabbelier · lore

Re: master^ is not a local branch -- huh?!?

Sverre Rabbelier <srabbelier@gmail.com> writes:
Show 7 quoted lines
> On Fri, Jan 29, 2010 at 22:24, Ron Garret <ron1@flownet.com> wrote:
>> Yes, I read that.  But what I'm trying to do is not just *look* at the
>> history, I want to restore my working tree to a previous version.  The
>> "Exploring History" section of the docs doesn't say how to do that.
>
> Do you want to restore your working tree only, or also throw away the
> history? If the former, you could look at 'git revert',...

I think he wanted to check paths out of a commit and the set of paths happened to be "everything".

IOW, "checkout $commit ."
Ron Garret· Jan 29, 2010, 22:12 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7vmxzwh906.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 14 quoted lines
> Sverre Rabbelier <srabbelier@gmail.com> writes:
> 
> > On Fri, Jan 29, 2010 at 22:24, Ron Garret <ron1@flownet.com> wrote:
> >> Yes, I read that.  But what I'm trying to do is not just *look* at the
> >> history, I want to restore my working tree to a previous version.  The
> >> "Exploring History" section of the docs doesn't say how to do that.
> >
> > Do you want to restore your working tree only, or also throw away the
> > history? If the former, you could look at 'git revert',...
> 
> I think he wanted to check paths out of a commit and the set of paths
> happened to be "everything".
> 
> IOW, "checkout $commit ."
Yes!!!  That's it exactly!
rg
Michael Witten· Jan 30, 2010, 00:33 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

On Fri, Jan 29, 2010 at 4:12 PM, Ron Garret <ron1@flownet.com> wrote:
Show 19 quoted lines
> In article <7vmxzwh906.fsf@alter.siamese.dyndns.org>,
>  Junio C Hamano <gitster@pobox.com> wrote:
>
>> Sverre Rabbelier <srabbelier@gmail.com> writes:
>>
>> > On Fri, Jan 29, 2010 at 22:24, Ron Garret <ron1@flownet.com> wrote:
>> >> Yes, I read that.  But what I'm trying to do is not just *look* at the
>> >> history, I want to restore my working tree to a previous version.  The
>> >> "Exploring History" section of the docs doesn't say how to do that.
>> >
>> > Do you want to restore your working tree only, or also throw away the
>> > history? If the former, you could look at 'git revert',...
>>
>> I think he wanted to check paths out of a commit and the set of paths
>> happened to be "everything".
>>
>> IOW, "checkout $commit ."
>
> Yes!!!  That's it exactly!

However, that updates the index and doesn't delete files that didn't exist in $commit, and you said earlier that you don't want to update the index (though perhaps you didn't really know what you wanted there).

My idea:

Isn't the difference between 'checkout' and 'reset' almost essentially a matter of whether the branch reference (HEAD), index, and tree are modified? Couldn't these commands be merged into one command or make use of one command?

Rather than relying on flags like --hard, --soft, and --mixed, why not *also* provide flags for specifying at a finer granularity what is desired for the index, working tree, and HEAD.

Then:
    git checkout $commit
does a lot of its work through something like:
    git update --index --tree --detach $commit
Also:
    git checkout $commit $f
translates:
    git update --index --tree --keep-tracked-files $commit $f
Also:
    git reset [--mixed] $commit
translates:
    git update --index --head $commit
Also:
    git reset --soft $commit
translates:
    git update --head $commit
Also:
    git reset --hard $commit
translates:
    git update --index --tree --head $commit
And so on.

In fact, with --no-* flags, you could modify 'reset' and 'checkout' commands from their defaults. So, to update all of the paths (including deleting tracked files not in $commit), but keep the index untouched, we have:

    git checkout --no-update-index --no-update-keep-files $commit .

Of course, you might as well just use the hypothetical 'update' command directly:

    git update --tree $commit .

Sincerely, Michael Witten

Junio C Hamano· Jan 30, 2010, 03:06 UTC · re: Michael Witten · lore

Re: master^ is not a local branch -- huh?!?

Michael Witten <mfwitten@gmail.com> writes:
> Isn't the difference between 'checkout' and 'reset' almost essentially
> a matter of whether the branch reference (HEAD), index, and tree are
> modified? Couldn't these commands be merged into one command or make
> use of one command?
I don't think that reduces any confusion.

By exposing orthogonal options like --index, --head, etc., you are opening yourself to nonsensical combinations that were never possible with the existing command set, and I suspect it would make it even more confusing, not less.

What does "git update --detach $commit" _really_ mean, for example?

You can of course say "it detaches the HEAD at $commit, but otherwise does not change anything else", but such a mechanical description does not give an answer that helps end users. "What would I do after doing that?" and "What would I use this for?" are the questions they need an answer to.

What matters is "after doing this, next commit will record _this_, which is often what users want in _that_ situation, and that is why this combination of options makes sense." Do all (or majority) of option combinations to your "update" think have _meaning_ in that sense? I don't think so.

Flexibility and orthogonality is often good, but uncontrolled flexibility is not. And I suspect your "git update" is just an uncontrolled mess that would not help users [*1*].

[Footnote]

*1* It is a different matter to have something like that as an ingredient to build Porcelain scripts out of. Porcelain writers may appreciate the flexibility and they will choose to use only combinations that make sense for the situation they are trying to deal with.

Ron Garret· Jan 30, 2010, 06:16 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7vvdek70ma.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 8 quoted lines
> Michael Witten <mfwitten@gmail.com> writes:
> 
> > Isn't the difference between 'checkout' and 'reset' almost essentially
> > a matter of whether the branch reference (HEAD), index, and tree are
> > modified? Couldn't these commands be merged into one command or make
> > use of one command?
> 
> I don't think that reduces any confusion.
Ahem... as the confused one here I respectfully disagree.
> By exposing orthogonal options like --index, --head, etc., you are opening
> yourself to nonsensical combinations that were never possible with the
> existing command set, and I suspect it would make it even more confusing,
> not less.

No, because it would make it much easier to map intent back into a command that implements that intent. Don't forget, this whole thing began because I wanted to do something very simple, tried what seemed to be the obvious way to do it, and stumbled accidentally on an advanced feature. That would not have happened if I'd been able to just do a git update --tree master^.

> What does "git update --detach $commit" _really_ mean, for example?

What difference does that make? Sure, there would be ways to shoot yourself in the foot with git update, but there is no shortage of ways to shoot yourself in the foot now. And now if you shoot yourself in the foot you have to start by trying to figure out where the bullet came from.

BTW, nothing prevents you from providing the usual repertoire of higher-level functionality as thin layers on top of something like git update.

> You can of course say "it detaches the HEAD at $commit, but otherwise does
> not change anything else", but such a mechanical description does not give
> an answer that helps end users.  "What would I do after doing that?" and
> "What would I use this for?" are the questions they need an answer to.

Sure. So document the combinations that make sense, and then say "You can mix and match the options in other ways, but you probably shouldn't unless you really know what you're doing." Done.

> Flexibility and orthogonality is often good, but uncontrolled flexibility
> is not.

That seems to me to run directly counter to the design philosophy behind git.

rg
Junio C Hamano· Jan 30, 2010, 06:45 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Ron Garret <ron1@flownet.com> writes:
Show 6 quoted lines
> No, because it would make it much easier to map intent back into a 
> command that implements that intent.  Don't forget, this whole thing 
> began because I wanted to do something very simple, tried what seemed to 
> be the obvious way to do it, and stumbled accidentally on an advanced 
> feature.  That would not have happened if I'd been able to just do a git 
> update --tree master^.

Doing that _will_ confuse you in your next step. Can you explain what happens if you run "git commit" from that state, why "git commit" does so, and how that is useful?

You may be too narrowly focused on only one single step, but I am more worried about the whole user experience: "I managed to do this, I am happy, but then the next step doesn't make much sense. Now what?"

> What difference does that make?  Sure, there would be ways to shoot 
> yourself in the foot with git update, but there is no shortage of ways 
> to shoot yourself in the foot now.

As long as you have a coherent picture of the workflow individual commands are supporting, there is no "shoot yourself in the foot". "git update" on the other hand is _designed_ not to allow such a coherent picture to be formed in the user's head, by letting random combinations that may or may not make sense.

> BTW, nothing prevents you from providing the usual repertoire of 
> higher-level functionality as thin layers on top of something like git 
> update.

That is more or less the same as what I said in the footnote, which you didn't quote from my message.

The flexibility of "update" may help Porcelain writers to pick and use only useful/usable combinations to present "the usual repertoire" for end users. At the philosophical level of "building blocks", I do not oppose to such flexibility [*1*].

But.

As the main point of Michael's message was that he thought it may make things less confusing to the end users, I am pointing out that unleashing such an uncontrolled flexibility directly to end users will _not_ help reduce their confusion.

[Footnote]

*1* As a set of "building blocks" to implement "reset" and "checkout", I don't necessarily agree that "update" would be a good way to go from the implementation standpoint, but that is a totally separate matter.

Ron Garret· Jan 30, 2010, 07:31 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7vaavw1478.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 11 quoted lines
> Ron Garret <ron1@flownet.com> writes:
> 
> > No, because it would make it much easier to map intent back into a 
> > command that implements that intent.  Don't forget, this whole thing 
> > began because I wanted to do something very simple, tried what seemed to 
> > be the obvious way to do it, and stumbled accidentally on an advanced 
> > feature.  That would not have happened if I'd been able to just do a git 
> > update --tree master^.
> 
> Doing that _will_ confuse you in your next step.  Can you explain what
> happens if you run "git commit" from that state,
Nothing.
> why "git commit" does so,
Because my index would be empty.
> and how that is useful?

It wouldn't. Was this a trick question? Did you mean to ask what would happen if I ran commit -a?

> You may be too narrowly focused on only one single step, but I am more
> worried about the whole user experience: "I managed to do this, I am
> happy, but then the next step doesn't make much sense.  Now what?"
I think you may be making some unwarranted assumptions about my end goal.
Show 9 quoted lines
> > What difference does that make?  Sure, there would be ways to shoot 
> > yourself in the foot with git update, but there is no shortage of ways 
> > to shoot yourself in the foot now.
> 
> As long as you have a coherent picture of the workflow individual commands
> are supporting, there is no "shoot yourself in the foot".  "git update" on
> the other hand is _designed_ not to allow such a coherent picture to be
> formed in the user's head, by letting random combinations that may or may
> not make sense.

That is a valid point. I guess this depends on whether you think of git as merely a revision control system for computer source code, or if you think of it as a more general tool that can and should be used in other kinds of applications as well.

Show 6 quoted lines
> > BTW, nothing prevents you from providing the usual repertoire of 
> > higher-level functionality as thin layers on top of something like git 
> > update.
> 
> That is more or less the same as what I said in the footnote, which you
> didn't quote from my message.
Yes, sorry about that.
Show 17 quoted lines
> The flexibility of "update" may help Porcelain writers to pick and use
> only useful/usable combinations to present "the usual repertoire" for end
> users.  At the philosophical level of "building blocks", I do not oppose
> to such flexibility [*1*].
> 
> But.
> 
> As the main point of Michael's message was that he thought it may make
> things less confusing to the end users, I am pointing out that unleashing
> such an uncontrolled flexibility directly to end users will _not_ help
> reduce their confusion.
> 
> [Footnote]
> 
> *1* As a set of "building blocks" to implement "reset" and "checkout", I
> don't necessarily agree that "update" would be a good way to go from the
> implementation standpoint, but that is a totally separate matter.
Did you mean "don't necessarily DISagree"?
rg
Junio C Hamano· Jan 30, 2010, 08:02 UTC · re: Ron Garret · lore

Re: master^ is not a local branch -- huh?!?

Ron Garret <ron1@flownet.com> writes:
> It wouldn't.  Was this a trick question?  Did you mean to ask what would 
> happen if I ran commit -a?

I didn't mean _literally_ "git commit". Any random thing you may want to do when you come back to work the next day and find a checked out work tree. Viewing, editing, committing, etc.

Show 5 quoted lines
>> *1* As a set of "building blocks" to implement "reset" and "checkout", I
>> don't necessarily agree that "update" would be a good way to go from the
>> implementation standpoint, but that is a totally separate matter.
>
> Did you mean "don't necessarily DISagree"?
I have huge doubts that "update" is the best way to do reset/checkout.
Ron Garret· Jan 30, 2010, 08:56 UTC · re: Junio C Hamano · lore

Re: master^ is not a local branch -- huh?!?

In article <7vhbq4xbok.fsf@alter.siamese.dyndns.org>,
 Junio C Hamano <gitster@pobox.com> wrote:
Show 8 quoted lines
> Ron Garret <ron1@flownet.com> writes:
> 
> > It wouldn't.  Was this a trick question?  Did you mean to ask what would 
> > happen if I ran commit -a?
> 
> I didn't mean _literally_ "git commit".  Any random thing you may want to
> do when you come back to work the next day and find a checked out work
> tree.  Viewing, editing, committing, etc.

Then I really don't understand the issue. I'd be in a situation that is no different from (in fact indistinguishable from) having manually edited my code so that it looks like an earlier checked-in version. What's the problem?

rg

← back to recent threads