DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Git 创建分支报 cannot lock ref:已有分支占用了名称前缀

Git 创建 feature/login 时提示 feature 已存在,属于分支名称前缀冲突。用完整引用定位,保留旧分支选择新名字,或通过本地改名释放前缀,并核对提交与回退。

创建 feature/login 时,如果 Git 输出下面这种错误,重复执行命令通常没有用:

fatal: cannot lock ref 'refs/heads/feature/login': 'refs/heads/feature' exists; cannot create 'refs/heads/feature/login'

错误指出了冲突双方:仓库里有一个本地分支叫 feature,新分支却要使用 feature/ 作为名称前缀。这里需要调整分支命名,不应仅看到 lock 就去删除锁文件。

本文处理的是创建本地分支时,报错同时包含 exists; cannot create,且两条引用存在上述前缀关系的情况。.lock: File exists、权限不足、引用损坏和大小写冲突需要另外判断。示例中的 feature、feature/login、feature-base 都是占位名称,应按实际错误替换。

斜杠合法,已有完整分支名不能同时当作前缀

feature/login 和 feature/logout 可以作为两个同级分支名。发生冲突的是 feature 与 feature/login:前者已经是一个完整引用,后者又要求在它下面创建另一条引用。反过来,已经有 feature/login 时,再创建 feature 也会遇到同类问题。

使用文件方式存储松散引用时,可以把它理解为同一个路径不能既是文件又是目录。不过排查时应查看 Git 的引用,而不是只看 .git/refs/heads 目录。引用还可能被打包存储,没找到同名文件并不能证明分支不存在;也不应通过手动改目录或编辑 packed-refs 来绕过冲突。

分支名中的斜杠表达命名层次,不表示提交的父子关系。即使从 feature 的提交创建新分支,也不需要把它命名成 feature/某个名字。新分支从哪里开始,由创建命令的起点参数决定。

按报错中的完整引用确认冲突

在发生错误的本地仓库里查看:

git branch -vv
git show-ref --verify refs/heads/feature
git branch --list 'feature/*'

show-ref --verify 要求匹配完整引用路径。若输出提交 ID 和 refs/heads/feature,就确认了短名称已经被占用。最后一条命令列出同一前缀下的本地分支;显式写 --list,避免把过滤模式误当成创建分支的参数。

如果输出与错误不符,先确认当前仓库、报错时间以及是否有其他进程在改引用。不要对着另一个仓库的列表直接删除分支。git branch -vv 也能帮助核对上游及关联工作区信息;分支正在其他 worktree 使用时,先协调对应工作区的操作。

完整路径尤其重要。refs/heads/origin/feature 是名称中包含 origin/ 的本地分支,refs/remotes/origin/feature 才属于远程跟踪引用。两者不因显示名称相近就能互相替代。本文后面的改名步骤只处理 refs/heads/;若错误发生在 fetch 或服务端 push 阶段,不要机械照搬。

保留旧分支,给新分支换一个不冲突的名字

不必改变既有命名时,可以保留 feature,给新分支换名。例如确定从当前提交开始:

git branch feature-login HEAD

这只创建本地分支,不会切换工作区。执行前确认 HEAD 就是需要的起点;如果真正需要从已有 feature 分支开始,应明确指定:

git branch feature-login feature

上面两条是互相替代的选择,不要顺序执行。feature-login 也必须是可用名称;若提示它已存在,先查看该分支,不要追加强制参数覆盖。

这条路径不删除引用,也不移动已有分支指向的提交。创建后核对新分支即可,不需要垃圾回收或清理远程引用。

必须保留 feature/ 命名空间时,先改短分支名

如果团队约定新分支统一叫 feature/login 这类名称,就需要让现有短分支 feature 改用另一个不冲突的名字。先记录原分支提交 ID,并确认新名字没有被使用:

git show-ref --verify refs/heads/feature
git branch --list feature-base 'feature-base/*'

保留第一条的提交 ID,后面用来核对。第二条如果有输出,应另外选名。暂停会同时修改该仓库引用的任务,并确认没有其他工作区依赖旧名称后,再执行:

git branch -m feature feature-base
git branch feature/login feature-base

第一条成功后才执行第二条。小写 -m 会改分支名,并随同迁移该分支的配置和 reflog;不要换成强制覆盖目标分支的大写 -M。第二条明确从改名后的分支创建 feature/login,不会因为当前恰好处于其他分支而选错起点。

改名只处理本地分支。已经推送的远程分支、CI 配置、脚本和协作者的检出名称需要单独协调;本地成功不代表服务端的同名冲突也消失了。这里只需解决本地命名问题时,不要顺手删除远程分支。

核对提交没有移动,并保留回退路径

采用改名方案后检查:

git show-ref --verify refs/heads/feature-base
git show-ref --verify refs/heads/feature/login
git branch -vv

刚创建完成、还没有新提交时,前两条的提交 ID 应与操作前记录的 feature 一致。确认列表中的上游关系符合预期;改名保留了配置,也意味着原有上游未必会自动变成你希望的新远程名称。

若要恢复旧命名,不能在 feature/login 仍存在时直接把 feature-base 改回 feature。可以先把新分支也改成不占用 feature/ 前缀的名称,在确认目标名称可用且没有其他 feature/* 分支后再恢复:

git branch -m feature/login feature-login
git branch -m feature-base feature

同样逐条确认成功再继续。这种回退保留新分支及其后来产生的提交,不必用强制删除来腾位置。

只有确认某条旧分支已不再需要,才另行评估删除。对明确的名称前缀冲突,先改名就能保留引用;直接删除 .git 下的文件、运行立即清理对象的命令,或反复尝试强制操作,都没有解决命名规则本身,还会增加恢复成本。