Question:
The git branch -a
command outputs this
aleksey@aleksey:~/Downloads/NTZ/FittingRoom$ git branch -a
* develop
master
remotes/origin/HEAD -> 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 -> 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 some branch!
Why then am I getting detached
if this is my branch ?? It's not just a commit …
EDIT
When switching to a remote develop
branch, 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:
-
HEAD should always only point to the top of some branch!
A branch in git is a floating commit pointer. the pointer does not and cannot have any "top".
The special
HEAD
pointer 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.
-
Why then do I get detached if this is my branch?
origin/develop
is a branch not from your local repository. As far as I understand from your previous questions, your localdevelop
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 therefore the unpacked file / directory trees from this commit will be completely identical.
Therefore, you most likely need
$ git checkout develop
but not
$ git checkout origin/develop
Answers to additional questions asked in the comment:
1) If I want to switch to a remote
develop
branch, why am I getting adetached head
message?
The short answer is: because it is intended.
The longer answer requires approaching very far away. I'll try.
As you (hopefully) know of thick manuals, each commit contains a binding to another parent commit (with two exceptions: the very first commit in the repository does not have the binding and commits so-called merger (merge commits) may contain two and more parent commits ). You can view this information, for example, like this:
$ git cat-file -p хэш-коммита
...
parent хэше-родительского-коммита
...
How does the git program "know" what to put in there (when calling git commit
)? It pulls 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/ветка
– then the hash of the parent commit is taken from the corresponding file – .git/refs/heads/ветка
.
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 HEAD
file contains a hash of a commit (" detached head state), 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/ветка
. this is how the "floating pointer to commit" mechanism (which is a branch in git ) is implemented.
We return to the question. The contents of the HEAD
file are modified with the checkout
command. So why, if we point the command to a local branch, it will write to this file ref: refs/heads/ветка
, and if we point to a branch of the remote repository, then it will write the hash of the commit pointed to by this branch to the file (creating the “ detached head ) instead of e.g. ref: refs/remotes/хранилище/ветка
?
Let's see what happens in this case.
Let's write it manually to the .git/HEAD
file, for example, ref: refs/remotes/origin/master
, make a change to some file in the working directory and make a git commit .
The hash of this commit will be written into the file we specified – .git/refs/remotes/origin/master
. It seems (so far) everything is in order.
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 repository! 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 branches, are "fixed", not "floating"), nor by using the parent хэш
string in some other commit. Yes, of course, this orphan commit can be viewed, 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 (in my opinion, more compelling) 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 удалённая-ветка
they decided to write the hash of the commit to the HEAD
(creating a " detached head state"), and not a link to the remote branch (creating ambiguity).
2) I switched to local
develop
, pushed to remotedevelop
, then made a pool, and anyway, when I switch to remotedevelop
, it writesdetached from origin/develop
– is this normal or not?
Yes, it is normal. see above.
3) Why, wherever I switch, my head always stands at
remotes/origin/HEAD -> origin/master
?
This line in the output of the branch
command appears due to the refs/remotes/origin/HEAD
file in the repository, 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 cloned with the --bare
option ( git clone --bare url-хранилища
), then this file would not be created (as well as the working directory with unpacked files from the repository).
"Your" HEAD
file is located directly in the root of the repository: .git/HEAD
.