[Git] ブランチを作成する際にcannot lock refと怒られて失敗することがある

ブランチを作成する際にfatal: cannot lock refと怒られる原因と対処法について紹介します。
2023.06.26

こんにちは。サービス部の武田です。

Gitを使用しているとブランチの作成は意識しなくても指が勝手に動くのではないでしょうか。さてそんなブランチ作成ですが、作成に失敗した経験はありますか?

たとえば次のようにブランチを作ってみます。何の問題もありません。

$ git switch -c feature/aaa/bbb
Switched to a new branch 'feature/aaa/bbb'

ところがある環境だとこのコマンドは失敗します。具体的には次のようなエラーメッセージが出ます。

$ git switch -c feature/aaa/bbb
fatal: cannot lock ref 'refs/heads/feature/aaa/bbb': 'refs/heads/feature/aaa' exists; cannot create 'refs/heads/feature/aaa/bbb'

ちなみにすでに存在するブランチ名で作成しようとすると次のようなメッセージが出ます。そのため上記のエラーはこれとは原因が異なります。

$ git switch -c feature/aaa
fatal: a branch named 'feature/aaa' already exists

今回の原因

このエラーを再現するには、まずfeature/aaaブランチを作成し、その後でfeature/aaa/bbbブランチを作成しようとします。

$ git switch -c feature/aaa
Switched to a new branch 'feature/aaa'

$ git switch -c feature/aaa/bbb
fatal: cannot lock ref 'refs/heads/feature/aaa/bbb': 'refs/heads/feature/aaa' exists; cannot create 'refs/heads/feature/aaa/bbb'

Gitではfeature/aaaのようにブランチ名に / が含まれている場合、内部的にrefs/heads/の下に同名のディレクトリを作成します。

実際に確認してみると、たしかにディレクトリが作成されています。

$ ls .git/refs/heads/*
.git/refs/heads/main

.git/refs/heads/feature:
aaa

さてこの状態でfeature/aaa/bbbブランチを作成しようとすると、やはりディレクトリを作成しようとしますが、すでに存在します。Gitでは、このケースではエラーとなってしまいます。

対応策

前提としてすでにfeature/aaaブランチが存在するのであれば、接頭辞としてfeature/aaa/は使用できません。しかしブランチの派生元として、わかりやすい名前にしたいという場合もあるでしょう。そこで、私の場合はfeature/aaa__bbbのようなブランチ名にすることで解決しています。

まとめ

あまりブランチの作成でエラーになることはないので、はじめて目にするとびっくりしてしまいますね。原因を知っていれば対処は難しくありません。普段から運用しやすい命名規則を作っておくとよいですね。