Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Setting default branch randomly picks wrong branch

Bobby Gaza October 23, 2012

occasionally when we set the default branch for a repo (from the web ui and from a put to the rest api) a git clone will not respect the default branch I saved in stash. I've verified this by performing a fresh clone, or a git branch -r from the commandline.

1 answer

1 vote
Douglas Fabretti
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 25, 2012

Hi Bobby.

Here is the explanation from our Developer Bryan Turner about that feature:

Unfortunately, the feature you're using doesn't work for what you're trying to use it for. Setting the default branch in Stash has only limited control over what you will receive when you clone the repository, due to how git's wire protocol works. The real purpose of the feature is to allow customers to control which branch is selected by default in the branch selector. For example, some projects do not use "master" as their development branch, preferring to use "trunk" or "development" instead. Such repositories may not even have a "master" branch. However, git's default behaviour is for <tt>HEAD</tt> to point to <tt>refs/heads/master</tt>, which results in a pretty unpleasant user experience when browsing a repository in Stash. When hitting the "Files" or "Commits" tabs, Stash displays a warning indicating the default branch does not exist, and the user then has to go select a different branch. Setting the default branch allows Stash to display a useful initial branch, rather than a warning.

When cloning a repository, git goes through a "ref advertisement" phase where the client asks the server what refs it has available. Here's an excerpt of that from the repository hosting Stash itself:

a26508497de6d4a8fb28dcb2f4b143ef6c587317 HEAD
1c787adcaebd09e0fa923e581e09819c54b20272 refs/heads/1.0
410a8d44418450f2a4e575ab4370082f56390144 refs/heads/1.1
46da3ee9cf2854cd535d94c576cb4d7063f507e3 refs/heads/1.2
ed99a76e91d3dde8f54e1c34a086652e5f267cb6 refs/heads/1.3
710b822fee4fe3abd54cd9fd623313b3a08ad98c refs/heads/STASH-2542
6d9202cf375da3495511a98e31c6f153bb50e96c refs/heads/STASH-2673
a26508497de6d4a8fb28dcb2f4b143ef6c587317 refs/heads/master

The important thing to notice in this output is that <tt>HEAD</tt> is not sent as a name, it's sent as the commit hash it's referring to. You can see in the output that follows that <tt>refs/heads/master</tt> is pointing to the same hash. As a result, the local client assumes <tt>HEAD -> refs/heads/master</tt>. In the case of this repository, that assumption is correct.

Now, let's consider another repository I've created. The ref advertisement for that repository looks like this:

d456b884414cc5e1939a3e5ba1e7f7e5d1b6b943 HEAD
d456b884414cc5e1939a3e5ba1e7f7e5d1b6b943 refs/heads/next
d456b884414cc5e1939a3e5ba1e7f7e5d1b6b943 refs/heads/trunk

Notice, no "master" branch, just "next" and "trunk", and all three refs have the same hash. In the repository backing Stash, you can see that I've selected "trunk" as the default branch:

auri:51 bturner$ cat HEAD
ref: refs/heads/trunk

However, cloning the repository results in this:

Cloning into 'no-master'...
Password for 'http://admin@localhost:7990': 
remote: Counting objects: 2747, done.
remote: Compressing objects: 100% (576/576), done.
remote: Total 2747 (delta 886), reused 2747 (delta 886)
Receiving objects: 100% (2747/2747), 1.02 MiB, done.
Resolving deltas: 100% (886/886), done.
auri:clones bturner$ cd no-master/
auri:no-master bturner$ git branch
* next

Oops. The branch it picked was "next", not "trunk". That's because the first branch git encountered with the same hash as <tt>HEAD</tt> was "next" because it is alphabetically sorted before "trunk", and git always maintains its refs in alphabetical order (to optimize looking them up).

What this means is that if you frequently have multiple branches that point to the same hash, while setting the default branch in Stash will result in the right branch being selected by default in the branch selector, the branch checked out immediately after a clone will be the first branch, alphabetically, with a hash that matches the hash for <tt>HEAD</tt>. There are no guarantees it will be the default branch you've picked in Stash, and, unfortunately, there is no way for Stash to "fix" that; it's just how git works. If there is a specific branch you want to get immediately on cloning, you can do your clone like this:

auri:clones bturner$ git clone -b trunk http://admin@localhost:7990/stash/scm/QA/no-master.git
Cloning into 'no-master'...
Password for 'http://admin@localhost:7990': 
remote: Counting objects: 2747, done.
remote: Compressing objects: 100% (576/576), done.
remote: Total 2747 (delta 886), reused 2747 (delta 886)
Receiving objects: 100% (2747/2747), 1.02 MiB, done.
Resolving deltas: 100% (886/886), done.
auri:clones bturner$ cd no-master/
auri:no-master bturner$ git branch
* trunk

If you'd like to see the ref advertisement for yourself, here's how:

  1. Locate your libexec/git-core directory
    • For me, it's in /opt/local/libexec/git-core
  2. From a clone of the repository, run <tt>/path/to/libexec/git-core/git-remote-http origin</tt>
    • If your URL is HTTPS, run <tt>git-remote-https</tt> instead of <tt>git-remote-http</tt>
    • The command will start and will display no output
  3. Type "list" and hit enter
  4. You will be prompted for your password, and then it will display the ref advertisement it received from the server
  5. Hit enter again to terminate the command

I hope this helps.

Cheers,
Douglas Fabretti
Atlassian Support

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events