How does origin/HEAD get set?

Note first that your question shows a bit of misunderstanding. origin/HEAD represents the default branch on the remote, i.e. the HEAD that's in that remote repository you're calling origin. When you switch branches in your repo, you're not affecting that. The same is true for remote branches; you might have master and origin/master in your repo, where origin/master represents a local copy of the master branch in the remote repository.

origin's HEAD will only change if you or someone else actually changes it in the remote repository, which should basically never happen - you want the default branch a public repo to stay constant, on the stable branch (probably master). origin/HEAD is a local ref representing a local copy of the HEAD in the remote repository. (Its full name is refs/remotes/origin/HEAD.)

I think the above answers what you actually wanted to know, but to go ahead and answer the question you explicitly asked... origin/HEAD is set automatically when you clone a repository, and that's about it. Bizarrely, that it's not set by commands like git remote update - I believe the only way it will change is if you manually change it. (By change I mean point to a different branch; obviously the commit it points to changes if that branch changes, which might happen on fetch/pull/remote update.)


Edit: The problem discussed below was corrected in Git 1.8.4.3; see this update.


There is a tiny caveat, though. HEAD is a symbolic ref, pointing to a branch instead of directly to a commit, but the git remote transfer protocols only report commits for refs. So Git knows the SHA1 of the commit pointed to by HEAD and all other refs; it then has to deduce the value of HEAD by finding a branch that points to the same commit. This means that if two branches happen to point there, it's ambiguous. (I believe it picks master if possible, then falls back to first alphabetically.) You'll see this reported in the output of git remote show origin:

$ git remote show origin
* remote origin
  Fetch URL: ...
  Push  URL: ...
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    foo
    master

Oddly, although the notion of HEAD printed this way will change if things change on the remote (e.g. if foo is removed), it doesn't actually update refs/remotes/origin/HEAD. This can lead to really odd situations. Say that in the above example origin/HEAD actually pointed to foo, and origin's foo branch was then removed. We can then do this:

$ git remote show origin
...
HEAD branch: master
$ git symbolic-ref refs/remotes/origin/HEAD
refs/remotes/origin/foo
$ git remote update --prune origin
Fetching origin
 x [deleted]         (none)     -> origin/foo
   (refs/remotes/origin/HEAD has become dangling)

So even though remote show knows HEAD is master, it doesn't update anything. The stale foo branch is correctly pruned, and HEAD becomes dangling (pointing to a nonexistent branch), and it still doesn't update it to point to master. If you want to fix this, use git remote set-head origin -a, which automatically determines origin's HEAD as above, and then actually sets origin/HEAD to point to the appropriate remote branch.


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

Tags:

Git