316

I'm pretty sure I saw somewhere in a popular Git project the branches had a pattern like "feature/xyz".

However when I try to create a branch with the slash character, I get an error:

$ git branch labs/feature
error: unable to resolve reference refs/heads/labs/feature: Not a directory
fatal: Failed to lock ref for update: Not a directory

Same problem for (my initial attempt):

$ git checkout -b labs/feature

How does one create a branch in Git with the slash character?

1
  • 1
    FWIW anything before the slash will generate a directory under .git/refs/heads ie if you do git checkout -b feature/123 then inside your projectRootFolder/.git/refs/heads directory you'll see a directory named: feature where inside that directory you'll see a branch named 123. Later if you create another feature/124 then inside the feature directory, you'll see a branch named 124 Commented Feb 14, 2019 at 16:03

8 Answers 8

307

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'
Sign up to request clarification or add additional context in comments.

15 Comments

Thanks for the in depth reply.. Interstingly I tried git branch foo/bar (which worked); then git branch -d foo/bar, but I see that the foo/ directory (now empty) still exists! EDIT: and it is replaced as soon as I do "git branch foo". All is well.
@faB: wicked... but not unexpected: you deleted bar (in the 'foo' namespace), but not foo (which could serve as a namespace for other branch or be a branch itself)
This doesn’t really matter, but git doesn’t change its stance even when you call pack-refs, so it’s going out of its way to protect you from this.
To summarize the answer: You can have slashes in branch names. OP already had a labs branch and tried to create labs/feature, which git balked at.
@duozmo so whats the solution? how do i specify that i branched from some specific reference branch?
|
137

It is possible to have hierarchical branch names (branch names with slash). For example in my repository I have such branch(es). One caveat is that you can't have both branch 'foo' and branch 'foo/bar' in repository.

Your problem is not with creating branch with slash in name.

$ git branch foo/bar
error: unable to resolve reference refs/heads/labs/feature: Not a directory
fatal: Failed to lock ref for update: Not a directory

The above error message talks about 'labs/feature' branch, not 'foo/bar' (unless it is a mistake in copy'n'paste, i.e you edited parts of session). What is the result of git branch or git rev-parse --symbolic-full-name HEAD?

1 Comment

Thanks, sorry about the confusion, I first wrote a foo/bar example, but paste error message from my actual test. Will not do it again :) And sorry also for my mistake, indeed I had a "labs" branch already.
70

I forgot that I had already an unused labs branch. Deleting it solved my problem:

git branch -d labs
git checkout -b labs/feature

Explanation:

Each name can only be a parent branch or a normal branch, not both. Thats why the branches labs and labs/feature can't exists both at the same time.

The reason: Branches are stored in the file system and there you also can't have a file labs and a directory labs at the same level.

Comments

42

Sometimes that problem occurs if you already have a branch with the base name.

I tried this:

git checkout -b features/aName origin/features/aName

Unfortunately, I already had a branch named features, and I got the exception of the question asker.

Removing the branch features resolved the problem, the above command worked.

Comments

2

Branch name is case sensitive and so if there are folders created in Azure by your release manager, folder names should match exactly. Learned it hard way raising it with manager.

Comments

1

In case someone has this issue where they're not able to checkout to a branch for eg: features/23 because it says branch features exists, but you cannot find it on Github - it might be that you have a local branch named features which is causing it.

Delete the local branch with git branch -D features and then you should be able to checkout with git checkout features/23 and it should work as expected.

1 Comment

Yes git checkout gives an error saying that a branch features exists if you try to checkout features/23. The solution that you already have a branch named features is already provided by the error message. This doesn’t tell us anything new.
0

just had the same issue, but i could not find the conflicting branch anymore.

in my case the repo had and "foo" branch before, but not anymore and i tried to create and checkout "foo/bar" from remote. As i said "foo" did not exist anymore, but the issue persisted.

In the end, the branch "foo" was still in the .git/config file, after deleting it everything was alright :)

Comments

0

I do this from Visual Studio Git Changes

As previously mentioned. I made the misstake of creating a dev branch. main dev

thinking that later I could just call them dev/somebranchname.

Solution was to delete dev and then create the dev/somebranchname. Next dev branch will be called dev/nextbranchname. This integrates very well with Visual Studio where dev becomes a folder view and the branches line up after that

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.