1. Introduction

The ubiquitous Git versioning system is a way to organize the process of development, writing, and general data change into manageable chunks. One of the main units of a Git repository is the commit. It provides a snapshot of the repository state at a given time. Further, a branch, contrary to its name, represents a single commit by giving it a name. This is similar to the function of a Git tag but extends that with more functionality.

In this tutorial, we explore the limitations of Git branch and tag naming. First, we explore Git names in general. After that, we turn to the restrictions that Git imposes on reference (ref) names, such as those for branches and tags. Finally, we check additional considerations during ref naming.

We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.2.15 and Git 2.39.2. Unless otherwise specified, it should work in most POSIX-compliant environments.

2. Git Names

Each commit has a commit identifier. However, some commits are more important than others:

  • milestones
  • features
  • versions
  • experiments
  • tests

That’s why these types of commits can get special names in the form of Git tags, branch names, or other refs (references).

Let’s check all references of an example repository via the show-ref subcommand:

$ git show-ref
6d0264be17baa5e2c0525e5f72e15098156f140d refs/heads/branch1
3b34787f960ce7f140a4a55fb649bf1745c397ff refs/heads/branch2
467173b6e09077c07daad32315f9fa1b661bd675 refs/heads/branch3
ade5f229cc37c52689a4e43c42025c9fd62fca76 refs/heads/master
ae0d1f5879bcfcb771ce1435956934c7e38aec5a refs/tags/base

In this case, we see the main master branch reference (ref) and three other branches. In addition, there’s one tag called base.

However, Git restricts what these names can contain based on what they refer to.

3. Git Branch and Tag Reference Naming Rules

The rules according to which we can name branches and tags are part of the Git documentation.

3.1. Separators and Structure

Just like UNIX paths, a / forward slash is the way to separate components within a ref:

ref/heads/branch1

However, there are several restrictions to the use of slashes:

  • at least one forward slash must be present in any ref unless –allow-onelevel is used
  • slashes can’t be part of names
  • if we don’t employ –normalize, multiple consecutive slashes are also forbidden

This way, we can build a hierarchy, since refs also exist as part of the filesystem:

$ tree .git/refs/
.git/refs/
├── heads
│   ├── branch1
│   ├── branch2
│   ├── branch3
│   └── master
└── tags
    └── base

3 directories, 5 files

Here, we can see the subdirectories and structure under the refs directory.

3.2. No . Dot Prefix or .lock Postfix

Still, the components on either side of a slash can’t begin with a . dot or end with .lock.

Effectively, this avoids two potential sources of confusion:

  • hidden *.*-prefixed UNIX files
  • actual .lock files

While these restraints are anchored, some character combinations can’t occur anywhere in the ref name.

3.3. Forbidden Sequences and Characters

Mainly to avoid problems with parsing as well as confusion between a ref and special shell functionality, there are a number of sequences that are considered invalid anywhere in a ref:

  • ..
  • @{
  • Delete (\x7f) and any characters before space (\x20), i.e., ASCII control characters
  • Space
  • ~ tilde
  • ^ caret
  • : colon
  • ? question mark
  • * asterisk (with –refspec-pattern, a single * is allowed as a wildcard)
  • [ open bracket
  • *\* backslash

In short, the above restrictions avoid problems in notations like branch1..branch2, ^branch1, and parent operations like ~ and ^. Similarly, : colons are sometimes separators between source and destination refs, while @{ is a way to access reflog entry.

3.4. Forbidden Names

Although the ref itself can contain the @ at sign, refs cannot be named with just the @ character in many git versions. \

Naturally, special refs like HEAD aren’t valid custom ref names.

4. Shell Considerations

Although not officially documented as problematic, some names and characters cause issues in Git refs due to the nature of the calling context.

In particular, including shell characters that require escaping within double quotes can lead to unexpected results.

For instance, we might want to include an angle bracket in a tag name:

$ git tag more>changes 601fea3

Of course, without single quotes around more>changes, we tag 601fea3 but with more. The rest of the tag name creates the changes file via redirection.

Similarly, using dollar signs can interpolate strings as variable values:

$ git tag dollar$bills 601fea3

In this case, if the $bills variable doesn’t exist, we just tag the commit with dollar. Otherwise, the tag might be completely different.

Finally, path length restrictions apply to refs as well.

5. Summary

In this article, we explored naming in Git.

In conclusion, although the reference names are structured just like a typical UNIX filesystem, there are some additional restrictions that apply to them.