Home git Why am I getting detached head?

Why am I getting detached head?

Author

Date

Category

git branch -a will output this

aleksey @ aleksey: ~ / Downloads / NTZ / FittingRoom $ git branch -a
* develop
master
remotes / origin / HEAD - & gt; origin / master
remotes / origin / develop
remotes / origin / master

after switching to the develop branch in the origin repository:

$ git checkout origin / develop

I get this output via git branch -a

aleksey @ aleksey: ~ / Downloads / NTZ / FittingRoom $ git branch -a
* (detached from origin / develop)
develop
master
remotes / origin / HEAD - & gt; origin / master
remotes / origin / develop
remotes / origin / master

So I read here that we get the detached state like this

It is characterized by the fact that HEAD does not point to the top of the branch, but simply to the commit. HEAD should always only point to the top of a branch!

Why then do I get detached if this is my branch ?? It’s not just a commit …

EDIT

When switching to a remote branch develop I get this message

aleksey @ aleksey: ~ / Downloads / NTZ / FittingRoom $ git checkout origin / develop
Note: checking out 'origin / develop'.
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 performing another checkout.
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 ee16cd4 ... service

Answer 1, authority 100%

  1. HEAD should always only point to the top of a branch!

    A branch in git is a floating commit pointer. the pointer does not and cannot have any “top”.

    The special pointer HEAD may well point not to a branch, but to a specific commit (the so-called detached head ). as in your case.

    This is simply a “non-standard” situation that may be needed in special cases.

  2. Why then do I get detached if this is my branch?

    origin / develop is a not branch from your local repository. As I understand from your previous questions, your local develop branch is “tied” to this branch. After full synchronization between them (git pull + git push ), both of them will point to the same commit, and hence the file / directory trees unpacked from that commit will be are completely identical.

Therefore, you most likely need

$ git checkout develop

not

$ git checkout origin / develop

Answers to additional questions asked in the comment:

1) If I want to switch to the remote develop branch, why am I getting a message about detached head ?

Short answer: because it is designed to do so.

The longer answer requires a very long distance. I’ll try.

As you (hopefully) know from the thick tutorials, each commit contains a binding to another, parent commit (there are two exceptions: the very first commit in the repository does not have such a binding, and the so-called . merge commits (merge commits can contain two or more parent commits ). You can view this information, for example, like this:

$ git cat-file -p hash commit
...
parent hash-of-parent-commit
...

How does the git program “know” what to put in there (when calling git commit )? It grabs information from the HEAD file at the root of the repository (.git / HEAD ).

If this file contains a hash of a commit (the so-called detached head state), then this commit is the parent .

And if this file contains a link to a branch (“normal state”) – ref: refs / heads / branch – then the hash of the parent commit is taken from the corresponding file – .git / refs / heads / branch .

I will not describe the procedure for creating a commit (its “technical” aspect) (“there is too little space in the margin” © Pierre Farm), but I will mention the action at the end of this process:

If the file HEAD contains the hash of the commit (“state detached head ), then new content is written to this file – the hash of the newly created commit.

And if this file contains a link to a branch (“normal state”), then the hash of the newly received commit is written to the file that this link points to – .git / refs / heads / branch . this is how the “floating pointer to commit” mechanism is implemented (which is the branch in git ).

Back to the question. The content of the HEAD file is modified by the checkout command. So why, if we point the command to a local branch, it will write ref: refs / heads / branch to this file, and if we point to a remote repository branch, it will write the hash of the commit pointed to by this branch (by creating “state detached head ) instead of eg ref: refs / remotes / repository / branch ?

Let’s see what happens in this case.

Let’s write by hand to the file .git / HEAD , for example, ref: refs / remotes / origin / master , let’s make a change to some file in the working directory and git commit .

The hash of this commit will be written into the file we specified – .git / refs / remotes / origin / master . Everything seems to be fine (for now).

But . if we execute the fetch command (the actions performed by it are also performed at the beginning of the execution of the pull command), then the contents of the file .git / refs / remotes / origin / master will be overwritten with information from the remote storage! And our new commit will “disappear” somewhere in the bowels of our local storage: it will not be referenced either by branches or by tags (tags are also pointers to a commit, but unlike from branches, “fixed”, not “floating”), nor by using the parent hash line in some other commit. Yes, of course, this orphan commit can be viewed by remembering its hash, but that’s all.

Here (in particular) in order not to create such a “mess”, checkout and will not write a link to the remote branch in the HEAD file.

Another reason (more compelling in my opinion) is the ambiguity of git actions with pull / push commands in our artificially created situation. Yes, in the current implementation, git will refuse to do anything, throwing out a sheet of error messages. But if you implement some kind of behavior in such a situation, then what should it be? I personally find it difficult to answer. It is likely that the developers of the program have the same problem. When git checkout remote-branch , they decided to write in HEAD the hash of the commit (creating a “detached head state”) rather than a link to the remote branch (creating ambiguity).

2) I switched to local develop , pushed to remote develop , then made a pool, and anyway when I switch to remote develop , it writes detached from origin / develop – is this normal or not?

Yes, that’s okay. see above.

3) Why, wherever I switch, my head always stays in place remotes / origin / HEAD - & gt; origin / master ?

This line in the output of the branch command appears due to the presence in the repository of the file refs / remotes / origin / HEAD , which in your case contains:

$ cat .git / refs / remotes / origin / HEAD
ref: refs / remotes / origin / master

You can delete this file absolutely painlessly. then this line will disappear from the output of the branch command.

This file was created during cloning and contains information about which branch was unpacked at the same time into your working directory . If you had cloned with the --bare option (git clone --bare repository url ), then this file would not have been created (nor would the working directory with unpacked files from the repository).

“Your” file is HEAD , located directly in the root of the repository: .git / HEAD .

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions