Setting default branch randomly picks wrong branch

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

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 Join to answer
Community showcase
Piotr Plewa
Published Dec 27, 2017 in Bitbucket

Recipe: Deploying AWS Lambda functions with Bitbucket Pipelines

Bitbucket Pipelines helps me manage and automate a number of serverless deployments to AWS Lambda and this is how I do it. I'm building Node.js Lambda functions using node-lambda&nbsp...

631 views 0 4
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you
Atlassian Team Tour

Join us on the Team Tour

We're bringing product updates and pro tips on teamwork to ten cities around the world.

Save your spot