8

I was using branches with slashes for some time, but suddenly found that I can't create them in some circumstances

$ git init
Initialized empty Git repository in /home/dimskraft/tests/git-slash-branch/.git/

$ git checkout -b my-branch
Switched to a new branch 'my-branch'

$ git status
On branch my-branch

No commits yet

nothing to commit (create/copy files and use "git add" to track)

$ git checkout -b my-branch/sub-branch
Switched to a new branch 'my-branch/sub-branch'

$ touch myfile.txt
$ git add myfile.txt 
$ git commit -m "added myfile.txt"
[my-branch/sub-branch (root-commit) 9be5cc5] added myfile.txt
...

$ git checkout -b my-branch/sub-branch/aaa
fatal: cannot lock ref 'refs/heads/my-branch/sub-branch/aaa': 'refs/heads/my-branch/sub-branch' exists; cannot create 'refs/heads/my-branch/sub-branch/aaa'

$ git status
On branch my-branch/sub-branch
nothing to commit, working tree clean

Why and is it possible to overcome?

Dims
  • 47,675
  • 117
  • 331
  • 600
  • https://stackoverflow.com/search?q=%5Bgit%5D+fatal%3A+cannot+lock+ref+exists+cannot+create – phd Mar 03 '20 at 12:13
  • Note that an "orphan branch" doesn't actually exist until there are commits on it, so it *is* possible to create `b/sub` while on the orphan branch `b`. Creating a commit while on orphan branch `b` causes branch `b` to actually exist (no longer be an orphan branch), after which Git forbids `b/sub`. Git is programmed to forbid this so that it won't get itself in trouble later, even though there are *some* cases where it *could* work. – torek Mar 03 '20 at 16:26
  • Git needs to stop storing branch names in simple OS files, to fix this and other issues, but the Git developers don't seem to have much interest in fixing these. – torek Mar 03 '20 at 16:27
  • This is not a duplicate of https://stackoverflow.com/q/2527355/ but rather of https://stackoverflow.com/q/22630404/. – fuenfundachtzig Oct 06 '22 at 14:16

1 Answers1

6

Because a branch named a/b/c is stored in a file named refs/heads/a/b/c, which means that refs/heads/a/b is a directory. But if there is also a branch named a/b, then refs/heads/a/b must be a file, storing that branch.

Both things can't be true — at least on the systems Git runs on, you can only have one object on a filesystem with a given name, and it can't be both a directory and a file. So you can't have one branch with a name that is a prefix of another branch's name, when the first character they don't share is a slash.

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • Git could store branch named `a/b` EITHER in a file `a/b` OR in a file `a/b.file` IF a directory `a/b` exists. – Dims Mar 03 '20 at 08:21
  • @Dims except `a/b.file` is a valid branch name :) Yes, Git could have made a different design choice that would avoid the conflict, but it didn't. – hobbs Mar 03 '20 at 08:32
  • So, answer to second part of my question is "impossible"? – Dims Mar 03 '20 at 11:40
  • You can try putting a suffix "-" or "/-" behind every single branch. I found that it works but didn't account for linux filesystem constraints, if they matter. Pls lemme know if what I suggested is good practice – Beast Feb 28 '23 at 07:03