"""代码版本号:解析挂载进容器的 .git 文件取短哈希,不需要 git 二进制。 ## 为什么要有它 计划快照要带代码版本,复盘时才知道某天的候选单是哪一版规则算出来的。桥镜像是 python:3.11-slim、没装 git,freeze.py 里调 git 命令的取法在容器里恒为 unknown (155 上 data/frozen/2026-09-01/manifest.json 实测)。仓库根挂在 /app,.git 目录随之 挂进来,直接读它就够了(2026-09-02 拍板:解析 .git 文件,不走宿主传环境变量)。 读法:.git/HEAD 是 "ref: refs/heads/<分支>" 就去读对应的 refs 文件;refs 文件不存在 (打包过)就在 .git/packed-refs 里找那一行;HEAD 本身就是裸哈希(游离头)直接用。 任何一步失败返回 "unknown",绝不抛错——版本号缺失不该让计划断产。 """ from __future__ import annotations from pathlib import Path def _read(p: Path) -> str | None: try: return p.read_text(encoding="utf-8").strip() except OSError: return None def git_short_rev(repo_root: str | Path | None = None, length: int = 7) -> str: roots = [Path(repo_root)] if repo_root else [Path("/app"), Path(__file__).resolve().parent] for root in roots: git = root / ".git" head = _read(git / "HEAD") if not head: continue if head.startswith("ref:"): ref = head.split(":", 1)[1].strip() sha = _read(git / ref) if not sha: packed = _read(git / "packed-refs") or "" for line in packed.splitlines(): parts = line.split() if len(parts) == 2 and parts[1] == ref: sha = parts[0] break else: sha = head if sha and len(sha) >= length and all(c in "0123456789abcdef" for c in sha[:length]): return sha[:length] return "unknown" if __name__ == "__main__": print(git_short_rev())