DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

git branch -d 删除了尚未合入 HEAD 的分支

git branch -d 会优先检查上游,可能删除尚未合入 HEAD 的分支。分别核对主线和上游的祖先关系,筛选清理候选,并在保留配置与 reflog 副本后处理旧上游阻止删除的情况。

清理本地分支时,即使用的是小写 -d,也可能看到这样的警告,随后分支仍被删除:

warning: deleting branch 'feature-demo' that has been merged to
         'refs/remotes/origin/feature-demo', but not yet merged to HEAD

反过来,分支已经合入当前 HEAD,却可能被拒绝删除:

warning: not deleting branch 'feature-demo' that is not yet merged to
         'refs/remotes/origin/feature-demo', even though it is merged to HEAD
error: The branch 'feature-demo' is not fully merged.

这两种结果来自同一个判断规则:git branch -d 优先检查待删除分支是否已合入它的上游;没有设置上游时才检查 HEAD。设置了上游不等于设置了主分支,它往往是远程的同名功能分支。因此,“已经推送”可能满足删除条件,却不代表已经合入主线。

下面处理普通本地仓库中的这两条警告,使用当前 Git 提供的引用和祖先检查命令。feature-demo、main、origin 和备份名称都是示例。不同 Git 版本的提示文字可能不同;上游引用已失效、仓库历史不完整或引用无法解析时,应先修复检查条件,不要把错误当成“已合并”。

将上游与要保留的主线分别列出来

先核对上游配置与目标提交:

git branch -vv
git rev-parse --symbolic-full-name 'feature-demo@{upstream}'
git rev-parse --verify refs/heads/feature-demo
git rev-parse --verify refs/heads/main

第二条若输出 refs/remotes/origin/feature-demo,就说明删除检查所用的上游不是本地 main。若没有上游,该命令会报错,应结合第一条确认配置,不要继续照搬上游检查。

本地的远程跟踪引用是上次同步得到的记录,不是服务器的实时查询。需要以远程现状判断时,先正常执行对应远程的 fetch 并确认成功,再重新检查引用。同步失败不能当作远程没有新增提交。

显式比较功能分支与本地主线,可以避免当前检出位置影响判断:

git merge-base --is-ancestor refs/heads/feature-demo refs/heads/main

这条命令通常不输出文字,应检查它的退出状态:0 表示功能分支尖端是主线的祖先,1 表示不是,其他非零值表示检查出错。在 POSIX shell 中,可紧接着用 echo $? 查看,不能在中间先执行另一条命令。

若还要核对删除警告中的上游,单独比较:

git merge-base --is-ancestor refs/heads/feature-demo 'feature-demo@{upstream}'

两次结果不同,就能解释为什么 HEAD 与上游给出相反的删除判断。若你的清理目标是远程主线,可将第一条比较的第二个参数换成经过同步和确认的 refs/remotes/origin/main;不要仅因当前分支叫 main 就假定它已追上服务器。

只清理合入主线的分支,先筛选再逐个处理

停止把未经筛选的 git branch 输出直接交给 xargs git branch -d。默认列表带有当前分支标记,其他工作树正在使用的分支也可能有标记;这些文字不适合作为直接删除的输入。

可以先生成只含分支名的候选列表:

git branch --merged refs/heads/main --format='%(refname:short)'

它按明确指定的主线筛选,不会因为待删分支已推送到同名上游就入选。列表仍可能包含 main、长期维护分支和正在使用的分支,所以这里只查看候选,不自动批量删除。删除前暂停会改动这些引用的其他任务,并重新核对单个目标。

如果祖先检查返回 1,保留该分支,先确认它的工作是否仍需合并。不要改用大写 -D 来让清理脚本继续运行。祖先关系检查的是提交历史,不能用它断言两边文件内容完全不同;经过压缩合并或变基后,需要另外审查工作是否已经被等价保留。

如果祖先检查返回 0,可以尝试正常的 git branch -d feature-demo。但筛选通过不保证删除通过:原有上游的检查仍会执行,所以还可能出现开头第二条警告。

已合入 main,但旧上游阻止删除

先判断这个上游是否仍然有用。如果该分支仍负责向它提交工作,应保留关系并处理缺失提交,不要为了清理列表强行撤销配置。

若分支确已结束使用,主线已保留它的全部历史,而且只需要删除本地名称,可以先保留配置和提交的副本。使用尚不存在的备份名称:

git branch -c feature-demo saved-feature-demo

-c 会复制分支及其配置和 reflog。备份创建失败就停止;备份仍在本地,不是独立磁盘备份,也不保存未提交文件。使用没有 -c 选项的旧版 Git 时,先保留分支并升级工具,不要临时改成强制删除。

确认工作目录修改已妥善保存,且 main 是预期的本地保留分支,再逐条操作:

git switch main
git merge-base --is-ancestor refs/heads/feature-demo HEAD

只有切换成功、第二条返回 0,才继续:

git branch --unset-upstream feature-demo
git branch -d feature-demo

每条成功后再执行下一条。撤销的是这个即将删除的本地分支的上游关系,不改服务器分支;此后小写 -d 使用当前 HEAD 做合并检查。如果仍然失败,保留现场与备份,按实际错误处理。分支被其他 worktree 使用时,也不能用删除 Git 管理文件来解除占用。

这条路径不需要 -D。如果只是上游配置写错而分支还要继续开发,应修正上游并继续使用该分支,无需进入删除流程。

验证结果及恢复本地名称

删除完成后确认目标名称消失、备份仍在:

git branch --list feature-demo saved-feature-demo
git branch -vv

本地删除不会删除服务器上的同名分支。备份保留期间,不要将它又纳入自动清理。

如果要恢复,且原名尚未被其他工作重新使用,可以从备份复制回来:

git branch -c saved-feature-demo feature-demo

它保留备份,并恢复副本中的提交指向、配置与 reflog;创建后核对上游是否仍适用。若分支已经被误删且事先没有备份,可先依据终端删除输出中的提交 ID、现有远程跟踪引用或仍保留的其他 reflog 查找提交。不要执行立即清理对象的操作,也不要承诺一定能从已删除分支自己的 reflog 恢复:删除分支时,其 reflog 也会被删除。