Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Normally when you run something like this inside of a git repository:

git checkout abc1234

You end up in a detached HEAD state. If you run git branch, the output will look something like this:

* (detached from abc1234)
  master

This is fine and expected behaviour.

I've been playing around with pygit2 recently, and have come across something I haven't seen before. Let's say I do the following:

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

I would expect the repository to be in a detached HEAD state. For all intents and purposes, I believe it is after doing this. However, the output from git branch looks a bit different:

* (no branch)
  master

Does anyone know what the difference is, why there is a difference, and what it means?

EDIT:

Below is the reflog after cloning a repository using pygit2, assigning a commit SHA1 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
like image 230
Matthew G Avatar asked Feb 12 '23 04:02

Matthew G


2 Answers

When in a "detached HEAD" state, git will show "(no branch)" or "(detached from abc)" depending on the contents of the reflog entry.

In your code, you simply overwrite the value without providing any message and thus no message is written to the reflog (as you can see in the HEAD@{2} entry from your reflog). If there were a similar "checkout" message, the detached text would appear.

pygit2 provides Reference.log_append() to append entries to the log, so you can create such an entry, though currently it would still create the empty one). The solution would be to use the update method once it supports the newer reflog handling which was introduced in libgit2 0.21.

The reference-setting methods Reference.set_target() and Repository.set_head() provide a place to put your own identity and message for the reflog, which you can use to provide a message equivalent to the one git's checkout command would create.

You can try doing the update as you currently are and writing by hand the entry in the reflog (it's under .git/logs/HEAD and it's a text file) to mimic what git would write and you should see the "(detached from abc)" message appear.

like image 188
Carlos Martín Nieto Avatar answered Feb 15 '23 09:02

Carlos Martín Nieto


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

In the second example, Git is indicating that you have checked out something invalid. You are not in a detached HEAD state, your HEAD is pointing to an invalid branch, in particular, it's pointing at a branch with the name of your commit ID.

You specified a string argument to repo.head, as if it were a branch name . (And pygit dutifully set HEAD to the branch name, which does not exist.) Instead, you need to specify an Oid, to indicate that the head should be detached:

repo.head = Oid(hex="abc1234...")
like image 25
Edward Thomson Avatar answered Feb 15 '23 08:02

Edward Thomson