git log 是提取结构化 commit 数据的唯一可靠方式,应使用 --pretty=format 配合 \x00 分隔符、时间范围过滤、--no-merges 及 --no-color,并在 go 中用 cmd.output() 获取后按 \x00 解析,再按作者和模块聚合排序。

用 git log 提取原始 commit 数据,别碰 git show 或 git cat-file
Git 周报的核心是结构化 commit 记录,不是渲染单个提交详情。git log 是唯一可靠入口,它支持格式化输出、时间范围过滤和分页控制;而 git show 会触发对象解析,遇到损坏引用或浅克隆时直接 panic,git cat-file 更底层、无时间/作者聚合能力。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
--pretty=format:"%H|%an|%ae|%ad|%s"控制字段分隔,避免空格/换行干扰后续解析(%ad默认带时区,建议加--date=iso8601-strict统一格式) - 用
--since="2024-04-01" --until="2024-04-07"精确限定周区间,别依赖--weeks—— 它按提交时间戳算“自然周”,和你发周报的周一不一致 - 加
--no-merges过滤掉 merge commit,除非你明确要统计合入行为
Go 里用 exec.Command 跑 git log,别用 os/exec 的管道链
初学者常把 git log | grep 拆成两个 exec.Command 再 pipe,这在 Go 里极易卡死:子进程未读完 stdout 就退出,管道缓冲区满后阻塞整个命令。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有过滤逻辑放在
git log命令内完成,比如用--author="^.*@company\.com$"正则匹配邮箱,而不是起grep - 用
cmd.Output()获取完整输出,再用strings.SplitLines解析 —— 简单、可控、无竞态 - 必须设
cmd.Dir为项目根目录(不是当前工作目录),否则git log找不到 repo - 错误检查不能只看
err != nil,还要检查cmd.ProcessState.ExitCode()——git log无匹配时返回 1,但输出为空,这不是异常
解析 commit 行时,strings.Split 分隔符必须和 git log --pretty 严格一致
如果 --pretty 用 "%H|%an|%ae|%ad|%s",那代码里必须用 strings.Split(line, "|");若中间某字段含 |(比如提交信息里写了 “fix: add support for | operator”),就会错位解析 —— 这是高频翻车点。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 改用
git log --pretty='format:%H%x00%an%x00%ae%x00%ad%x00%s',用 ASCII\x00作分隔符(commit message 几乎不可能含 \x00) - 解析时用
bytes.Split处理Output()返回的[]byte,比strings.Split更安全 - 跳过空行和 header 行(
git log在某些终端下可能输出 ANSI 颜色字符,加--no-color彻底禁用)
生成周报文本时,别硬拼 HTML 或 Markdown,先用纯文本结构对齐数据粒度
很多新手一上来就写 fmt.Fprintf(w, "<h3>%s</h3>", author),结果发现作者重复、日期乱序、同一人多个模块混在一起 —— 根子在于没做数据归类。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 先用
map[string][]Commit按作者聚合,再用map[string][]Commit按模块(如pkg/auth、cmd/server)二次分类,模块名从%s开头提取(正则^(pkg|cmd|internal)/[^\s]+) - 排序只做两层:作者名升序、每个作者下的 commit 按时间倒序(
SortStable+ 自定义Less) - 最后才用简单字符串拼接生成段落,比如
fmt.Sprintf("- %s (%s)\n", c.Subject, c.Hash[:7]),留到下一步再转 Markdown
真正麻烦的是路径识别和模块划分规则 —— Git 不记录“这个 commit 属于哪个功能模块”,全靠人工约定。如果团队没统一前缀规范(如 auth: login timeout fix),光靠正则切分路径容易漏判。这点得和同事对齐,不是代码能解决的。










