Difference between "(no branch)" and "(detached by abc1234)"

Usually when you run something like this inside a git repository:

git checkout abc1234

      

You will end up in a separate HEAD state. If you run it git branch

, the output looks something like this:

* (detached from abc1234)
  master

      

This is fine and expected behavior.

I recently played around with pygit2 and came across something I hadn't seen before. Let's say I am doing the following:

repo = pygit2.discover_repository("/path/to/repo")
repo.head = "abc1234"

      

I would expect the repository to be in a separate HEAD state. In my opinion, it happens after that. However, the output from git branch

looks slightly different:

* (no branch)
  master

      

Does anyone know what the difference is, why there is a difference, and what does that mean?

EDIT:

Below is the reflog after cloning the repository using pygit2, assigning a SHA1 commit hash to repo.head, then running git checkout master

, then running git checkout myhash

:

69df316 HEAD@{0}: checkout: moving from master to 69df3161f315e9b13ba4bd811635c11f67616598
d6ece61 HEAD@{1}: checkout: moving from 69df3161f315e9b13ba4bd811635c11f67616598 to master
69df316 HEAD@{2}:
d6ece61 HEAD@{3}: clone: from file:///path/to/repo

      

+3


source to share


3 answers


When in a "detached HEAD" state, git will display "(not branch)" or "(detached from abc)" depending on the content of the reflog entry.

In your code, you are simply overwriting the value without providing any message, and thus no message is written to the reflog (as you can see in the entry HEAD@{2}

from your reflog). If there is a similar "checkout" message, a separate text will appear.

pygit2 provides Reference.log_append()

for adding log entries, so you can create such an entry, although it will still create an empty one at this time). The solution would be to use the update method if it supports the new reflog handling that was introduced in libgit2 0.21.



Ways to define links Reference.set_target()

and Repository.set_head()

provide a place to put your self and post for the reflog, which you can use to provide a post equivalent to that git checkout command ./p>

You can try updating as you are now and manually write a reflog entry (it's under .git / logs / HEAD and it's a text file) to simulate what git will write and you should see a message appears " (detached from abc) ".

+4


source


Git indicates in the first example that you checked out a commit (not a branch) and therefore your head is detached.

In the second example, Git indicates that you checked something invalid. You are not in a separate HEAD state, your HEAD is pointing to an invalid branch, specifically pointing to a branch named after your commit id.



You have specified a string argument repo.head

as if it were the name of the branch. (And pygit dutifully put HEAD on the branch name, which doesn't exist.) Instead, you need to specify an Oid to indicate that the head should be detached:

repo.head = Oid(hex="abc1234...")

      

+2


source


Check if the git version was the same in both cases.
The article " Checking Current Branch Programmatically " by Junio ​​C Hamano states:

in fact, since release 1.8.3, the output when you are not on any branch has become something like this:

$ git checkout v1.8.3
$ git branch
* (detached from v1.8.3)
  master
  next

      

This means that the second output " (no branch)

" is consistent with using git pre-1.8.3 or that pygit2 uses an older version of libgit2 as commented by Jean Hominal


If it is produced by the same git then check the contents HEAD

: see the " user manual "

Then it HEAD

references the SHA-1 of the commit instead of the branch, and the git branch shows that you are no longer on the branch:

$ cat .git/HEAD
427abfa28afedffadfca9dd8b067eb6d36bac53f
$ git branch
* (detached from v2.6.17)
master

      

However, in the second case, if pygit2 doesn't install at all HEAD

, it wt_status.c

will display no branch

.

+1


source







All Articles