128

How do I set a Git remote's HEAD reference to point to something besides "master"?

My project has a policy not to use a "master" branch (all branches are to have meaningful names). Furthermore, the canonical master repository is only accessible via ssh://, with no shell access (like GitHub or Unfuddle).

My problem is that the remote repository still has a HEAD reference to refs/heads/master, but I need it to point to a different branch. This is causing two problems:

  1. When cloning the repo, there this,

    warning: remote HEAD refers to nonexistent ref, unable to checkout.

    That's confusing and inconvenient.

  2. The web-based code browser depends on HEAD as a basis for browsing the tree. I need HEAD to point to a valid branch, then.

random
  • 9,324
  • 10
  • 63
  • 77
JasonSmith
  • 68,848
  • 21
  • 119
  • 147
  • Just added one possibility for the record, but not suitable for your case. – VonC Sep 28 '09 at 06:20
  • "no-common-ancestor" trick: interesting. You could post it as a detailed answer and select it as the official one if you find it working. – VonC Sep 28 '09 at 06:48
  • 12
    FWIW, since you mentioned GitHub in the question -- if you want to change the HEAD ref on GitHub, just go to the repository's "Admin" screen, and change the "Default Branch" dropdown to whatever branch you want HEAD to point to. – Joe Jun 25 '12 at 15:17
  • See also https://help.github.com/articles/error-remote-head-refers-to-nonexistent-ref-unable-to-checkout – Tino Jul 01 '12 at 13:26
  • 1
    possible duplicate of [create a git symbolic ref in remote repository](http://stackoverflow.com/questions/847609/create-a-git-symbolic-ref-in-remote-repository) – Ciro Santilli新疆棉花TRUMP BAN BAD Feb 02 '14 at 22:52
  • A better asked question with a very good accepted answer is [Git: Correct way to change Active Branch in a bare repository?](https://stackoverflow.com/q/3301956/260122), if you are on a repo where you have command-line access. For a repo on a hosting service, see https://stackoverflow.com/a/2962737/260122 below. – clacke Mar 28 '17 at 16:45

11 Answers11

64

There was almost the same question on GitHub a year ago.

The idea was to rename the master branch:

git branch -m master development
git branch -m published master
git push -f origin master 

Making master have what you want people to use, and do all other work in branches.

(a "git-symbolic-ref HEAD refs/head/published" would not be propagated to the remote repo)

This is similar to "How do I delete origin/master in Git".


As said in this thread: (emphasis mine)

"git clone" creates only a single local branch.
To do that, it looks at the HEAD ref of the remote repo, and creates a local branch with the same name as the remote branch referenced by it.

So to wrap that up, you have repo A and clone it:

  • HEAD references refs/heads/master and that exists
    -> you get a local branch called master, starting from origin/master

  • HEAD references refs/heads/anotherBranch and that exists
    -> you get a local branch called anotherBranch, starting from origin/anotherBranch

  • HEAD references refs/heads/master and that doesn't exist
    -> "git clone" complains

Not sure if there's any way to directly modify the HEAD ref in a repo.

(which is the all point of your question, I know ;) )


Maybe the only way would be a "publication for the poor", where you:

 $ git-symbolic-ref HEAD refs/head/published
 $ git-update-server-info
 $ rsync -az .git/* server:/local_path_to/git/myRepo.git/

But that would involve write access to the server, which is not always possible.


As I explain in "Git: Correct way to change Active Branch in a bare repository?", git remote set-head wouldn't change anything on the remote repo.

It would only change the remote tracking branch stored locally in your local repo, in remotes/<name>/HEAD.


With Git 2.29 (Q4 2020), "git remote set-head(man)" that failed still said something that hints the operation went through, which was misleading.

See commit 5a07c6c (17 Sep 2020) by Christian Schlack (cschlack).
(Merged by Junio C Hamano -- gitster -- in commit 39149df, 22 Sep 2020)

remote: don't show success message when set-head fails

Signed-off-by: Christian Schlack

Suppress the message 'origin/HEAD set to master' in case of an error.

$ git remote set-head origin -a
error: Not a valid ref: refs/remotes/origin/master
origin/HEAD set to master
VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
  • Thanks, VonC. I read that before posting here. But as you can see, a branch called "master" is unwelcome in this project for technical and policy reasons. – JasonSmith Sep 28 '09 at 05:57
  • You could then enforce that policy by disallowing any update on master branch through a pre-commit hook. – VonC Sep 28 '09 at 05:58
  • Yes, if it turns out that there is no way to do what I want then I will do exactly that and accept your answer. Thanks for following up! – JasonSmith Sep 28 '09 at 06:06
  • Thanks for the update. For the moment, I used the "no-common-ancestor" trick to make a master branch with only one commit. (I.e.: git branch -D master; echo ref: refs/heads/master > .git/HEAD; rm *). Then I just touched a file called GO_AWAY, and commit message explains the situation. That will work for now. I may check through the source and track down where the receiving side sets HEAD for a final answer. – JasonSmith Sep 28 '09 at 06:37
  • This gave me a 'non-fast-forward' error. The only way I was able to do it was using the answer here: http://superuser.com/a/749412/399381 – ctn May 26 '15 at 16:30
  • 1
    @ctn That is simply because I forgot the `-f` (`--force`) option. I have edited the answer accordingly. Then answer you reference does use that same option. – VonC May 26 '15 at 16:35
44

Update: This only works for the local copy of the repository (the "client"). Please see others' comments below.

With a recent version of git (Feb 2014), the correct procedure would be:

git remote set-head $REMOTE_NAME $BRANCH

So for example, switching the head on remote origin to branch develop would be:

git remote set-head origin develop

jrhorn424
  • 1,863
  • 1
  • 21
  • 24
  • Does this feature need recent version of git on the server or is it enough if client machine has recent git installed? – Mikko Rantalainen Mar 06 '14 at 09:48
  • 3
    @Totor is terse but right; this answer should be downvoted. Git has this somewhat confusing concept of a "local, default branch for the remote". It lets you type "origin" instead of "origin/defaultbranch" and is a *pure client-side* thing. Long story at https://git-scm.com/docs/git-remote #set-head – MarcH Dec 18 '16 at 19:52
  • 1
    to confirm what @MarchH is talking about: run `git checkout -b default; git push origin HEAD; git remote set-head origin default`. You can then inspect the local changes with `cat .git/refs/remotes/origin/HEAD` (it should be `ref: refs/remotes/origin/default`), and the lack of remote changes with `git remote show origin` (it will still be whatever it was before you added the default branch). – De Novo Mar 03 '19 at 23:42
36

Since you mention GitHub, to do it on their site simply go into your project, then...

admin > Default Branch > (choose something)

Done.

srcspider
  • 10,171
  • 5
  • 35
  • 33
16

See: http://www.kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html

This sets the default branch in the git repository. You can run this in bare or mirrored repositories.

Usage:

$ git symbolic-ref HEAD refs/heads/<branch name>
selurvedu
  • 451
  • 1
  • 8
  • 20
mani-fresh
  • 261
  • 2
  • 2
  • 6
    $ git symbolic-ref HEAD refs/heads/name-of-branch – Yasen Nov 26 '12 at 09:26
  • I did this in my remote repo and it fixed my problems cloning where for some reason the head was another branch name and therefore trying to clone master would result in an error whilst trying to close master in composer, this might be very specific to this scenario, but others might be in that position and wondering what to do – Christopher Thomas Apr 13 '15 at 10:28
10

(There was already basically the same question "create a git symbolic ref in remote repository", which received no universal answer.)

But there are a specific answers for various git "farms" (where multiple users can manage git repos through a restricted interface: via http and ssh): http://Github.com, http://Gitorious.org, http://repo.or.cz, Girar (http://git.altlinux.org).

These specific answers might be useful for those reading this page and thinking about these specific services.

MarcH
  • 16,107
  • 1
  • 26
  • 22
  • 4
    Now they have a drop-down menu for selecting the HEAD branch at http://repo.or.cz (example: http://repo.or.cz/editproj.cgi?name=for-me-and-for-all_imz.git ) and http://gitorious.org , too. Great! – imz -- Ivan Zakharyaschev May 04 '11 at 17:19
7

If you have access to the remote repo from a shell, just go into the .git (or the main dir if its a bare repo) and change the HEAD file to point to the correct head. For example, by default it always contains 'refs: refs/heads/master', but if you need foo to be the HEAD instead, just edit the HEAD file and change the contents to 'refs: refs/heads/foo'.

squeegee
  • 744
  • 7
  • 9
  • I have admin rights on Git server and i did exactly the same. We use Gitolite and i went to the repository which i created. The directory name is `myrepo.git`. The content of HEAD file in the given directory was changed from `ref: refs/heads/master` to `ref: refs/heads/mainline`. Now, when i try to clone the repository on my local box, it still points to master. I ran `git clone ssh://gitolite@git.server/myrepo` command. Any idea for such behaviour? – Technext Mar 20 '15 at 13:28
  • Git server version: `git version 1.7.1` & Git client version: `git version 1.9.4.msysgit.2` – Technext Mar 20 '15 at 13:35
6

You can create a detached master branch using only porcelain Git commands:

git init
touch GO_AWAY
git add GO_AWAY
git commit -m "GO AWAY - this branch is detached from reality"

That gives us a master branch with a rude message (you may want to be more polite). Now we create our "real" branch (let's call it trunk in honour of SVN) and divorce it from master:

git checkout -b trunk
git rm GO_AWAY
git commit --amend --allow-empty -m "initial commit on detached trunk"

Hey, presto! gitk --all will show master and trunk with no link between them.

The "magic" here is that --amend causes git commit to create a new commit with the same parent as the current HEAD, then make HEAD point to it. But the current HEAD doesn't have a parent as it's the initial commit in the repository, so the new HEAD doesn't get one either, making them detached from each other.

The old HEAD commit doesn't get deleted by git-gc because refs/heads/master still points to it.

The --allow-empty flag is only needed because we're committing an empty tree. If there were some git add's after the git rm then it wouldn't be necessary.

In truth, you can create a detached branch at any time by branching the initial commit in the repository, deleting its tree, adding your detached tree, then doing git commit --amend.

I know this doesn't answer the question of how to modify the default branch on the remote repository, but it gives a clean answer on how to create a detached branch.

kbro
  • 4,051
  • 6
  • 27
  • 35
  • 1
    You can create a detached branch easier by fetching an unrelated branch from another repo and giving it a name. For example, `git fetch git:user@example.com:foo remote-branch-name && git checkout -b detached-branch FETCH_HEAD` will add new branch `detached-branch` that matches the branch `remote-branch-name` in remote `git:user@example.com:foo`. Of course, the "remote" can be a repository in local file system you have previously prepared. – Mikko Rantalainen Mar 26 '13 at 07:02
3

Related to the question, I ended up here when searching for:

How do I make a local repo aware of a changed default branch on GitHub

For completeness, adding the answer:

git remote set-head origin -a
friederbluemle
  • 22,961
  • 11
  • 88
  • 92
2

First, create the new branch you would like to set as your default, for example:

$>git branch main

Next, push that branch to the origin:

$>git push origin main

Now when you login to your GitHub account, you can go to your repository and choose Settings>Default Branch and choose "main."

Then, if you so choose, you can delete the master branch:

$>git push origin :master

4mnes7y
  • 148
  • 8
  • The key point to understand is that if you hosting provider (GitHub in this example) does not provide a method for modifying default branch, you're out of luck. Git protocol does not provide a feature to modify the remote default branch; you would need to be able to run `git symbolic-ref` on the remote shell or otherwise able to modify text file called `HEAD` in the remote repository root directory. – Mikko Rantalainen Mar 26 '13 at 07:07
0

For gitolite people, gitolite supports a command called -- wait for it -- symbolic-ref. It allows you to run that command remotely if you have W (write) permission to the repo.

Nilesh
  • 17,950
  • 11
  • 74
  • 119
sitaram
  • 1
  • 1
-1

Simple just log into your GitHub account and on the far right side in the navigation menu choose Settings, in the Settings Tab choose Default Branch and return back to main page of your repository that did the trick for me.

Matija
  • 16,018
  • 2
  • 39
  • 38
  • 1
    While it shows the new branch as the default in the GitHub interface, when doing a git clone [repo], I'm not getting that branch. i.e. .git/HEAD contains the wrong ref. – Joseph Sheedy Feb 14 '13 at 18:16