git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Nicolas Pitre <nico@fluxnic.net>
Date
Jan 30, 2010, 04:03 UTC
Message-ID
<alpine.LFD.2.00.1001292232130.1681@xanadu.home>
In-Reply-To
<ron1-8B7921.19261029012010@news.gmane.org>
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
Previous: Ron GarretNext: Jay Soffian
Message 37 of 94 in “master^ is not a local branch -- huh?!?”
  1. Ron1Jan 29, 2010
  2. Jacob HelwigJan 29, 2010
  3. Sverre RabbelierJan 29, 2010
  4. Jacob HelwigJan 29, 2010
  5. Junio C HamanoJan 29, 2010
  6. Sverre RabbelierJan 29, 2010
  7. checkout: warn about 'branch name' rather than 'local branch'Sverre Rabbelier, Jan 29, 2010
  8. checkout: Fix test for s/local branch/branch name/ change.Jacob Helwig, Jan 29, 2010
  9. Sverre RabbelierJan 29, 2010
  10. Nicolas PitreJan 29, 2010
  11. Ron GarretJan 29, 2010
  12. Junio C HamanoJan 29, 2010
  13. Sverre RabbelierJan 29, 2010
  14. Junio C HamanoJan 29, 2010
  15. Nicolas PitreJan 29, 2010
  16. Sverre RabbelierJan 29, 2010
  17. Nicolas PitreJan 29, 2010
  18. Sverre RabbelierJan 29, 2010
  19. Nicolas PitreJan 29, 2010
  20. Junio C HamanoJan 29, 2010
  21. Sverre RabbelierJan 29, 2010
  22. Nicolas PitreJan 29, 2010
  23. Junio C HamanoJan 29, 2010
  24. Jacob HelwigJan 29, 2010
  25. Nicolas PitreJan 29, 2010
  26. Junio C HamanoJan 30, 2010
  27. Sverre RabbelierJan 30, 2010
  28. Junio C HamanoJan 30, 2010
  29. Sverre RabbelierJan 30, 2010
  30. Michael WittenJan 30, 2010
  31. Nicolas PitreJan 30, 2010
  32. Mark LodatoJan 30, 2010
  33. Nicolas PitreJan 30, 2010
  34. Ron GarretJan 30, 2010
  35. Junio C HamanoJan 30, 2010
  36. Ron GarretJan 30, 2010
  37. Nicolas PitreJan 30, 2010
  38. Jay SoffianJan 30, 2010
  39. Junio C HamanoJan 30, 2010
  40. Jay SoffianJan 30, 2010
  41. Nicolas PitreJan 30, 2010
  42. Junio C HamanoJan 30, 2010
  43. Ron GarretJan 30, 2010
  44. Junio C HamanoJan 30, 2010
  45. Jay SoffianJan 30, 2010
  46. Junio C HamanoJan 30, 2010
  47. Ron GarretJan 30, 2010
  48. Mark LodatoJan 30, 2010
  49. Nicolas PitreJan 30, 2010
  50. Mark LodatoJan 30, 2010
  51. Nicolas PitreJan 30, 2010
  52. Nicolas PitreJan 30, 2010
  53. Jay SoffianJan 30, 2010
  54. Nicolas PitreJan 30, 2010
  55. Mark LodatoJan 30, 2010
  56. Junio C HamanoJan 30, 2010
  57. Jeff KingJan 30, 2010
  58. Ron GarretJan 30, 2010
  59. A Large Angry SCMJan 29, 2010
  60. Junio C HamanoJan 29, 2010
  61. Johannes SchindelinJan 30, 2010
  62. Nicolas PitreJan 30, 2010
  63. Johannes SchindelinJan 29, 2010
  64. Ron1Jan 29, 2010
  65. Jacob HelwigJan 29, 2010
  66. Ron GarretJan 29, 2010
  67. Junio C HamanoJan 29, 2010
  68. Ron GarretJan 29, 2010
  69. Junio C HamanoJan 31, 2010
  70. Octavio AlvarezJan 29, 2010
  71. Ron GarretJan 29, 2010
  72. Octavio AlvarezJan 29, 2010
  73. Ron GarretJan 29, 2010
  74. Octavio AlvarezJan 29, 2010
  75. Junio C HamanoJan 29, 2010
  76. Ron GarretJan 29, 2010
  77. Julian PhillipsJan 29, 2010
  78. Ron GarretJan 30, 2010
  79. Ron GarretJan 30, 2010
  80. Junio C HamanoJan 30, 2010
  81. Ron GarretJan 30, 2010
  82. Scott R. GodinJan 29, 2010
  83. Ron GarretJan 29, 2010
  84. Sverre RabbelierJan 29, 2010
  85. Ron GarretJan 29, 2010
  86. Junio C HamanoJan 29, 2010
  87. Ron GarretJan 29, 2010
  88. Michael WittenJan 30, 2010
  89. Junio C HamanoJan 30, 2010
  90. Ron GarretJan 30, 2010
  91. Junio C HamanoJan 30, 2010
  92. Ron GarretJan 30, 2010
  93. Junio C HamanoJan 30, 2010
  94. Ron GarretJan 30, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.