Git clone fails with "remote HEAD refers to nonexistent ref" when default branch is not master
Description
When cloning a Keybase git repository where the default branch is main (or any branch other than master), the clone succeeds but no files are checked out. Git reports:
warning: remote HEAD refers to nonexistent ref, unable to checkout
This is a common issue for repositories created on GitHub after October 2020, when GitHub changed the default branch name from master to main.
Steps to Reproduce
-
Create a git repository locally with main as the default branch:
mkdir test-repo && cd test-repo
git init -b main
echo "test" > README.md
git add . && git commit -m "initial"
-
Add Keybase as a remote and push:
git remote add origin keybase://private/username/test-repo
git push -u origin main
-
Clone the repo to a new location:
cd /tmp
git clone keybase://private/username/test-repo test-clone
Expected Behavior
The repository should clone successfully with all files checked out on the main branch.
Actual Behavior
Cloning into 'test-clone'...
Initializing Keybase... done.
Syncing with Keybase... done.
Counting: done.
Cryptographic cloning: done.
warning: remote HEAD refers to nonexistent ref, unable to checkout
The .git directory is created but the working directory is empty.
Workaround
Manually specifying the branch works:
git clone --branch main keybase://private/username/test-repo
Root Cause Analysis
After examining the codebase, the issue stems from hardcoded references to master as the default branch:
-
go/kbfs/libgit/browser.go:75:
const masterBranch = "refs/heads/master"
-
go/kbfs/kbfsgit/runner.go - The list command returns a HEAD symref pointing to refs/heads/master, but when the actual branch is main, this reference doesn't exist.
-
The go-git.v4 library used (gopkg.in/src-d/go-git.v4) initializes repositories with HEAD pointing to refs/heads/master by default, with no option to configure this.
Suggested Fix
-
Detect the actual default branch from the repository instead of hardcoding master:
// Instead of:
const masterBranch = "refs/heads/master"
// Query the actual HEAD target:
func getDefaultBranch(repo *gogit.Repository) plumbing.ReferenceName {
ref, err := repo.Storer.Reference(plumbing.HEAD)
if err != nil {
return plumbing.ReferenceName("refs/heads/main")
}
return ref.Target()
}
-
Update the HEAD symref in the list command to point to the actual branch that exists, not a hardcoded master.
-
Consider upgrading to go-git/v5 which supports InitOptions.DefaultBranch for better default branch configuration.
Environment
- Keybase client version: (latest)
- Git version: 2.x
- OS: Linux
Related Code
go/kbfs/libgit/browser.go - Default branch constant
go/kbfs/kbfsgit/runner.go - Git remote helper protocol handling
go/kbfs/libgit/repo.go - Repository initialization
Impact
This affects any user who:
- Creates repos on GitHub (which defaults to
main since Oct 2020)
- Uses modern git with
init.defaultBranch set to main
- Pushes existing repos with
main as the default branch to Keybase
Given GitHub's dominance and the industry shift to main, this will affect an increasing number of users over time.
Git clone fails with "remote HEAD refers to nonexistent ref" when default branch is not
masterDescription
When cloning a Keybase git repository where the default branch is
main(or any branch other thanmaster), the clone succeeds but no files are checked out. Git reports:This is a common issue for repositories created on GitHub after October 2020, when GitHub changed the default branch name from
mastertomain.Steps to Reproduce
Create a git repository locally with
mainas the default branch:Add Keybase as a remote and push:
Clone the repo to a new location:
cd /tmp git clone keybase://private/username/test-repo test-cloneExpected Behavior
The repository should clone successfully with all files checked out on the
mainbranch.Actual Behavior
The
.gitdirectory is created but the working directory is empty.Workaround
Manually specifying the branch works:
Root Cause Analysis
After examining the codebase, the issue stems from hardcoded references to
masteras the default branch:go/kbfs/libgit/browser.go:75:go/kbfs/kbfsgit/runner.go- Thelistcommand returns a HEAD symref pointing torefs/heads/master, but when the actual branch ismain, this reference doesn't exist.The
go-git.v4library used (gopkg.in/src-d/go-git.v4) initializes repositories with HEAD pointing torefs/heads/masterby default, with no option to configure this.Suggested Fix
Detect the actual default branch from the repository instead of hardcoding
master:Update the HEAD symref in the
listcommand to point to the actual branch that exists, not a hardcodedmaster.Consider upgrading to
go-git/v5which supportsInitOptions.DefaultBranchfor better default branch configuration.Environment
Related Code
go/kbfs/libgit/browser.go- Default branch constantgo/kbfs/kbfsgit/runner.go- Git remote helper protocol handlinggo/kbfs/libgit/repo.go- Repository initializationImpact
This affects any user who:
mainsince Oct 2020)init.defaultBranchset tomainmainas the default branch to KeybaseGiven GitHub's dominance and the industry shift to
main, this will affect an increasing number of users over time.