Are you sure branch labs does not already exist (as in this thread)?
You can't have both a file, and a directory with the same name.
You're trying to get git to do basically this:
% cd .git/refs/heads
% ls -l
total 0
-rw-rw-r-- 1 jhe jhe 41 2009-11-14 23:51 labs
-rw-rw-r-- 1 jhe jhe 41 2009-11-14 23:51 master
% mkdir labs
mkdir: cannot create directory 'labs': File exists
You're getting the equivalent of the "cannot create directory" error.
When you have a branch with slashes in it, it gets stored as a
directory hierarchy under .git/refs/heads.
Note that labs must not be an existing branch, as ddruganov points out in the comments:
git switch -c 19023-commerce/19033-commerce-view 19023-commerce
# Fails with:
fatal: cannot lock ref 'refs/heads/19073-commerce-view/99999-test-branch':
'refs/heads/19073-commerce-view' exists;
cannot create 'refs/heads/19073-commerce-view/99999-test-branch'
As explained in "git push: refs/heads/my/subbranch exists, cannot create":
- If branch
b exists, no branch named b/anything can be created.
- Likewise, if branch
dev/b exists, dev/b/c cannot be created.
This is a git internal limitation.
2025 update -- reftable backend (Git 3.0) and slash names
As noted by Guildenstern in the comments, Git 2.45+ can store refs with the reftable backend, which the project plans to make the default for new repos in Git 3.0.
I mentioned reftable in March 2024 with "How git branches and tags are stored in disks?"
Even under reftable, Git still rejects directory/file conflicts in reference names for interoperability: you cannot have both labs and
labs/feature at the same time. The error you will see is along the lines of:
fatal: cannot lock ref 'refs/heads/labs/feature':
'refs/heads/labs' exists; cannot create 'refs/heads/labs/feature'
As noted in reftable man page, "Directory/file conflicts" section, this behavior matches the files backend and is retained deliberately for compatibility with peers, like git-init --ref-format, git-rev-parse --show-ref-format, and git refs migrate: No matter which you pick with those 3 commands, trying to create labs/feature when labs exists fails with the same D/F (Directory/File) error, by design. The option only selects the storage engine; it does not relax ref-naming invariants.
Network protocols and hosting services do not expose "which backend I store refs with"; they just exchange ref names. If reftable allowed labs and labs/feature to co-exist, pushing to a peer on the files backend would fail or behave inconsistently. So Git enforces the same D/F rule at creation/update time for both backends to keep pushes/fetches and migrations predictable.
To check your backend:
git rev-parse --show-ref-format # 'files' or 'reftable'
.git/refs/headsie if you dogit checkout -b feature/123then inside yourprojectRootFolder/.git/refs/headsdirectory you'll see a directory named:featurewhere inside that directory you'll see a branch named123. Later if you create anotherfeature/124then inside thefeaturedirectory, you'll see a branch named124