[git] How does origin/HEAD get set?

I have a branch set up to track a ref in origin. git checkout <branchname> switches to that branch, and a git status will show me how far ahead or behind my branch is from origin, but I'm surprised that origin/HEAD still points at origin/master, and not origin/<branchname>

So my question is, under what circumstances does origin/HEAD get moved?

EDIT:

I appreciate the answers about how to move origin/HEAD, but I'm interested in what "organically" moves it, outside of me explicitly telling it to do so.

For example, when I switch branches, git makes HEAD point at the branch I'm checking out, so I'm surprised that origin/HEAD doesn't move in the same manner.

This question is related to git

The answer is


It is your setting as the owner of your local repo. Change it like this:

git remote set-head origin some_branch

And origin/HEAD will point to your branch instead of master. This would then apply to your repo only and not for others. By default, it will point to master, unless something else has been configured on the remote repo.

Manual entry for remote set-head provides some good information on this.

Edit: to emphasize: without you telling it to, the only way it would "move" would be a case like renaming the master branch, which I don't think is considered "organic". So, I would say organically it does not move.


What moves origin/HEAD "organically"?

  • git clone sets it once to the spot where HEAD is on origin
    • it serves as the default branch to checkout after cloning with git clone

What does HEAD on origin represent?

  • on bare repositories (often repositories “on servers”) it serves as a marker for the default branch, because git clone uses it in such a way
  • on non-bare repositories (local or remote), it reflects the repository’s current checkout

What sets origin/HEAD?

  • git clone fetches and sets it
  • it would make sense if git fetch updates it like any other reference, but it doesn’t
  • git remote set-head origin -a fetches and sets it
    • useful to update the local knowledge of what remote considers the “default branch”

Trivia

  • origin/HEAD can also be set to any other value without contacting the remote: git remote set-head origin <branch>
    • I see no use-case for this, except for testing
  • unfortunately nothing is able to set HEAD on the remote
  • older versions of git did not know which branch HEAD points to on the remote, only which commit hash it finally has: so it just hopefully picked a branch name pointing to the same hash

Remember there are two independent git repos we are talking about. Your local repo with your code and the remote running somewhere else.

Your are right, when you change a branch, HEAD points to your current branch. All of this is happening on your local git repo. Not the remote repo, which could be owned by another developer, or siting on a sever in your office, or github, or another directory on the filesystem, or etc...

Your computer (local repo) has no business changing the HEAD pointer on the remote git repo. It could be owned by a different developer for example.

One more thing, what your computer calls origin/XXX is your computer's understanding of the state of the remote at the time of the last fetch.

So what would "organically" update origin/HEAD? It would be activity on the remote git repo. Not your local repo.

People have mentioned

git symbolic-ref HEAD refs/head/my_other_branch

Normally, that is used when there is a shared central git repo on a server for use by the development team. It would be a command executed on the remote computer. You would see this as activity on the remote git repo.


Disclaimer: this is an update to Cascabel's answer, which I'm writing to save the curious some time.

I tried in vain to replicate (in Git 2.0.1) the remote HEAD is ambiguous message that Cascabel mentions in his answer; so I did a bit of digging (by cloning https://github.com/git/git and searching the log). It used to be that

Determining HEAD is ambiguous since it is done by comparing SHA1s.

In the case of multiple matches we return refs/heads/master if it
matches, else we return the first match we encounter. builtin-remote
needs all matches returned to it, so add a flag for it to request such.

(Commit 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771, dated Feb 27, 2009, found with git log --reverse --grep="HEAD is ambiguous")

However, the ambiguity in question has since been lifted:

One long-standing flaw in the pack transfer protocol used by "git
clone" was that there was no way to tell the other end which branch
"HEAD" points at, and the receiving end needed to guess.  A new
capability has been defined in the pack protocol to convey this
information so that cloning from a repository with more than one
branches pointing at the same commit where the HEAD is at now
reliably sets the initial branch in the resulting repository.

(Commit 9196a2f8bd46d36a285bdfa03b4540ed3f01f671, dated Nov 8, 2013, found with git log --grep="ambiguous" --grep="HEAD" --all-match)

Edit (thanks to torek):

$ git name-rev --name-only 9196a2f8bd46d36a285bdfa03b4540ed3f01f671
tags/v1.8.4.3~3

This means that, if you're using Git v1.8.4.3 or later, you shouldn't run into any ambiguous-remote-HEAD problem.


Run the following commands from git CLI:

# move to the wanted commit
git reset --hard <commit-hash> 

# update remote
git push --force origin <branch-name>