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:

  • How to maintain a linear history in git
  • Does 'git cherry' consider the number of commits in head and upstream?
  • Can I list source for already defined bash functions?
  • git alias command is not working can any one describe me syntax of git alias command
  • What are the implications of local clones for Git?
  • Git command to show which specific files are ignored by .gitignore
  • * (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
    

  • How to move certain commit to NEW branch
  • How to use GIT interactive rebase for signing off a series of commits
  • Why isn't this merge fast-forwarded?
  • git/cygwin silent failure
  • git upload the files as root
  • Maven Deployment Parameters in pom.xml
  • 3 Solutions collect form web for “Difference between “(no branch)” and “(detached at abc1234)””

    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.

    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...")
    

    Check if the version of git was the same in both cases.
    The article “Checking the current branch programatically” from 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
    

    That means the second output “(no branch)” is consistent with using a git pre-1.8.3, or with the fact that pygit2 uses an older version of libgit2, as commented by Jean Hominal


    If this is produced by the same git, then check the content of HEAD: see “user manual”

    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:

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

    However, in the second case, if pygit2 doesn’t set HEAD at all, the wt_status.c would display no branch.

    Git Baby is a git and github fan, let's start git clone.