-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
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
mainas 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-repoRoot 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- 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:// 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
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
- Keybase client version: (latest)
- Git version: 2.x
- OS: Linux
Related Code
go/kbfs/libgit/browser.go- Default branch constantgo/kbfs/kbfsgit/runner.go- Git remote helper protocol handlinggo/kbfs/libgit/repo.go- Repository initialization
Impact
This affects any user who:
- Creates repos on GitHub (which defaults to
mainsince Oct 2020) - Uses modern git with
init.defaultBranchset tomain - Pushes existing repos with
mainas 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.