52 lines
2.0 KiB
Python
52 lines
2.0 KiB
Python
|
|
"""代码版本号:解析挂载进容器的 .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())
|