首页
/ Spec Kit Git 扩展中的 speckit.git.validate:功能分支命名校验机制解析

Spec Kit Git 扩展中的 speckit.git.validate:功能分支命名校验机制解析

2026-09-04 19:12:42作者:昌雅子Ethen

在 Spec Kit 的规格驱动开发(Spec-Driven Development)流程中,每个功能对应一个带编号前缀的 Git 分支和一个 specs/ 目录。Git 扩展提供的 speckit.git.validate 命令负责回答一个关键问题:当前分支是否遵循了预期的功能分支命名约定,以及它是否还能找到与之对应的规格目录。读完本文,你将掌握该命令的两类命名规则(顺序编号与时间戳)、完整的校验执行流程、非 Git 环境下的降级策略,以及它在 Bash / PowerShell / Python 三套实现中的底层正则逻辑。

命令定位与基本职责

speckit.git.validate 是 Git Branching Workflow 扩展注册的五个命令之一,其声明见 extension.yml

provides:
  commands:
    - name: speckit.git.validate
      file: commands/speckit.git.validate.md
      description: "Validate current branch follows feature branch naming conventions"

该命令的完整行为规范定义在 speckit.git.validate.md 中。需要说明的是,扩展文件 extension.ymlrequires.tools 声明 gitrequired: false——也就是说 Git 是可选依赖,命令必须能在没有 Git 的环境中优雅降级(后文详述)。

它与扩展内其他命令的关系是:speckit.git.feature 按约定创建分支,speckit.git.validate 在流程中校验分支,speckit.git.commit 在各核心命令前后自动提交,speckit.git.remote 探测远端用于 GitHub 集成,speckit.git.initialize 初始化仓库。完整命令清单见 Git 扩展 README

前置检查:Git 可用性探测

校验的第一步是确认 Git 可用。按规范文档,执行:

git rev-parse --is-inside-work-tree 2>/dev/null

如果 Git 不可用(未安装或当前目录不是 Git 仓库),命令不报错、不中断,而是输出一条警告并跳过校验:

[specify] Warning: Git repository not detected; skipped branch validation

这条警告文案并非随意指定——它在三套平台实现中是逐字一致的。从源码看,Bash 实现的 check_feature_branch()git-common.sh 中,当 has_git_repo != "true" 时正是向 stderr 打印这句话后 return 0(视为通过):

check_feature_branch() {
    local raw="$1"
    local has_git_repo="$2"

    # For non-git repos, we can't enforce branch naming but still provide output
    if [[ "$has_git_repo" != "true" ]]; then
        echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2
        return 0
    fi
    ...
}

Python 孪生实现 git_common.pycheck_feature_branch() 同样在非 Git 仓库时打印相同警告并返回 True,保证三种运行环境行为对齐(这一点由 test_git_extension.py 等测试覆盖)。而 has_git() 的探测逻辑本身要求三重条件同时满足:.git 目录/文件存在、git 可执行文件在 PATH 中、rev-parse --is-inside-work-tree 返回 0(见 git-common.shgit_common.py)。

校验规则:两种功能分支命名模式

获得当前分支名的方式是:

git rev-parse --abbrev-ref HEAD

规则要求:分支名的最后一个路径段(final path segment)必须以以下两类特征前缀之一开头

1. 顺序编号(Sequential)

  • 模式:[0-9]{3,}-,即至少 3 位数字加连字符
  • 示例:001-feature-name042-fix-bug1000-big-featurejdoe/web/008-guided-tour

注意数字位数没有上限,4 位、5 位编号(如 1234-feature-name)同样合法——源码中的错误提示文案 001-feature-name, 1234-feature-name, ... 也印证了这一点(见 git-common.sh)。

2. 时间戳(Timestamp)

  • 模式:[0-9]{8}-[0-9]{6}-,即 8 位日期 + 6 位时间 + 连字符
  • 示例:20260319-143022-feature-namejdoe/web/20260319-143022-feature-name

命名空间前缀是允许的

两个示例中都出现了 jdoe/web/... 这种带路径前缀的形式。这是因为 Git 扩展支持 monorepo 场景下的 branch_template(如 {author}/{app}/{number}-{slug}),生成 jdoe/web/008-guided-tour 这类分支名;校验规则因此只看“最后一段路径”。这一点在扩展 README 的配置说明中有明确记载:

# Optional branch name template. Leave empty for the default "{number}-{slug}".
# Supported tokens: {author}, {app}, {number}, {slug}; {slug} must not appear
# before {number}, and the final path segment must start with {number}-.
# Example for monorepos: "{author}/{app}/{number}-{slug}"
branch_template: ""

配置存储位置为 .specify/extensions/git/git-config.yml,模板/前缀的完整参数说明见 git-config 模板README 配置章节

源码中的“畸形时间戳”排除逻辑

规范文档给出的是简化规则,而三套实现中还包含一条防御性细节:顺序模式必须排除“畸形时间戳”。以 Python 实现 git_common.py 为例:

# Accept sequential prefix (3+ digits) but exclude malformed timestamps:
# 7-or-8 digit date + 6-digit time with no trailing slug.
is_sequential = bool(
    re.match(r"^[0-9]{3,}-", feature_segment)
    and not re.match(r"^[0-9]{7}-[0-9]{6}-", feature_segment)
    and not re.fullmatch(r"[0-9]{7,8}-[0-9]{6}", feature_segment)
)
is_timestamp = bool(re.match(r"^[0-9]{8}-[0-9]{6}-", feature_segment))

它把两种情况排除在“顺序编号”之外:

  1. [0-9]{7}-[0-9]{6}- 开头——7 位“日期”是坏掉的时间戳(日期应为 8 位),不应被误判成合法的 7 位顺序编号;
  2. 整段恰好是 [0-9]{7,8}-[0-9]{6}(没有后续 slug)——这是“被截断的时间戳”,例如裸的 20260319-143022

Bash 版本在 git-common.sh 中用完全对应的三条正则表达同一意图,PowerShell 版本 Test-FeatureBranchgit-common.ps1 中用 $hasMalformedTimestamp 变量实现。三者注释均写明“Logic aligned with the ... twin”,即有意保持跨平台语义一致。

单段命名空间的剥离:effective branch name

另一个实现细节值得注意。在取“最后路径段”之前,三套实现都会先调用一个 effective_branch_name 变换:如果分支名恰好是 a/b 两段(每段不含斜杠),则剥掉第一段——典型场景是 gitflow 风格的 feat/004-name004-name(见 git-common.sh 的注释与 git_common.py 的 docstring)。但注意其边界:只有恰好两段时才剥离,像 jdoe/web/008-guided-tour(三段)保持原样,然后取最后一段 008-guided-tour 参与匹配。从源码结构看,这是一种对常见分支命名生态(gitflow 等)的兼容性处理,避免 feat/001-x 这类分支被误判为非功能分支。

执行流程与输出契约

校验命中与未命中时,规范文档规定了明确的输出契约,便于其他 Agent 或脚本机器解析。

命中功能分支

若分支匹配任一模式,输出:

✓ On feature branch: <branch-name>

随后检查 specs/ 下是否存在对应的规格目录:

  • 顺序分支:查找 specs/<prefix>-*,其中 prefix 为编号数字部分,忽略分支命名空间前缀
  • 时间戳分支:查找 specs/<prefix>-*,其中 prefix 为 YYYYMMDD-HHMMSS 部分,同样忽略命名空间前缀。

结果二选一:

✓ Spec directory found: <path>
⚠ No spec directory found for prefix <prefix>

第二个输出是警告而非错误——分支合法但规格目录缺失,常见于分支刚创建、specify 流程尚未产出的情况。

未命中功能分支

若不在功能分支上(例如还在 mainmaster),输出两行:

✗ Not on a feature branch. Current branch: <branch-name>
Feature branches should be named like: 001-feature-name, 20260319-143022-feature-name, or <namespace>/001-feature-name

对照源码实现,Bash/PowerShell/Python 三者在失败分支写入 stderr 的正是这两行(Python 版本多列出了 1234-feature-name 示例):

if not is_sequential and not is_timestamp:
    print(f"ERROR: Not on a feature branch. Current branch: {raw}", file=sys.stderr)
    print(
        "Feature branches should be named like: 001-feature-name, "
        "1234-feature-name, 20260319-143022-feature-name, or "
        "<prefix>/001-feature-name",
        file=sys.stderr,
    )
    return False

(见 git_common.py。)

优雅降级:SPECIFY_FEATURE 环境变量兜底

规范文档的“Graceful Degradation”一节定义了无 Git 场景下的兜底路径:

  1. 检查 SPECIFY_FEATURE 环境变量;
  2. 若已设置,则用该值替代分支名,按同样的命名模式校验;
  3. 若未设置,则输出警告并跳过校验。

SPECIFY_FEATURE 并非凭空出现,而是扩展创建分支流程写入的环境变量。从源码看,create-new-feature-branch 的三套实现都会在成功建分支后把它设成新分支名:PowerShell 直接执行 $env:SPECIFY_FEATURE = $branchNamecreate-new-feature-branch.ps1),Bash/Python 则在 stderr 打印持久化提示 # To persist: export SPECIFY_FEATURE=...create-new-feature-branch.shcreate_new_feature_branch.py)。由此可以推断:SPECIFY_FEATURE 是“会话级”的分支标记——即使后续在非 Git 目录(或 CI 的浅检出等受限环境)中运行流程,validate 仍能基于该标记完成命名一致性检查,而不是硬性失败。

这与整个扩展的降级哲学一致,Git 扩展 README 的 Graceful Degradation 一节概括为:

  • 规格目录照常创建于 specs/ 下;
  • 分支创建被跳过并给出警告;
  • 分支校验被跳过并给出警告(即本文命令的行为);
  • 远端探测返回空结果。

安装、禁用与验证路径

在目标项目(注意是已 specify init 的业务项目,而非本仓库)中启用该命令:

# 安装内置 git 扩展(无需网络)
specify extension add git

# 禁用 / 重新启用
specify extension disable git
specify extension enable git

命令模板由扩展注册时安装到项目的命令目录;本仓库中的权威源文件即 speckit.git.validate.md。若只想阅读行为定义而不安装,直接打开该文件即可——它就是 Agent 执行时遵循的完整行为规范(frontmatter 中的 description 与正文的 Prerequisites / Validation Rules / Execution / Graceful Degradation 四节构成命令契约)。

行为测试集中在 test_git_extension.py,其中包含“模板渲染出的最终路径段必须能通过校验”(Templates must render a final path segment that validation accepts)与“配置模板必须包含 {number} 才能生成可校验分支”等断言,从测试角度保证了分支创建侧与分支校验侧的正则契约不会漂移;另有 test_git_extension_python_parity.py 同目录下的 Python 对等测试用于保证三语言实现一致。

小结:规则速查

输入 是否通过 输出
001-feature-name 通过 ✓ On feature branch: ... + spec 目录检查
jdoe/web/008-guided-tour 通过(命名空间被忽略) 同上
20260319-143022-feature-name 通过 同上
feat/004-name 通过(两段名先剥前缀) 同上
20260319-143022(无 slug 的裸时间戳) 不通过 ✗ Not on a feature branch...
main / master 不通过 同上,并附命名建议
非 Git 目录 + SPECIFY_FEATURE 已设 按该值校验 依赖取值
非 Git 目录 + 未设 跳过 [specify] Warning: Git repository not detected; skipped branch validation

speckit.git.validate 的设计要点可以概括为:规则宽松到覆盖命名空间与两种编号策略,实现严格到排除畸形时间戳,失败路径永远给出可操作的提示而非硬错误。它是 Git 扩展把“分支名 ↔ 规格目录”这一 SDD 核心不变量落到运行时的守门人。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384