尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于Git提交记录自动生成日报周报的Python脚本实践

基于Git提交记录自动生成日报周报的Python脚本实践 “今天的进度写一下下班前发群里。”这句看似普通的要求可能是很多程序员一天中最不想面对的时刻。不是因为你没干活而是因为你在脑子里快速回溯一天的工作时发现能说出来的东西远没有你以为的多修了两个 Bug、调了一个接口、开会开到下午四点、还有一个需求没写完。然后你打开聊天框开始把事实加工成一封 200 字的“汇报文学”。问题出在哪里出在很多团队把“进度”当成一种临场回忆而不是一种日常沉淀的数据。开发者的代码提交、分支合并、需求关闭这些动作本身就在产生进度信息但它们散落在 Git 日志、项目管理工具和聊天记录里到需要汇报时又重新靠人脑去汇总一遍。这篇文章要讲的是如何把“今天的进度”从一项靠记忆和作文能力完成的任务变成一套基于 Git 提交记录自动生成的工程产物。我会从提交信息规范讲起再给出一份可直接运行的 Python 脚本让你能用一条命令生成当天的 Markdown 日报、一周的汇总统计以及可直接导入 Excel 的 CSV 数据。读完你能直接在自己的电脑上跑通这套流程并且知道在实际团队里推广时最容易踩哪些坑。1. 为什么“今天的进度”总是写不好先想一个问题如果你负责的功能已经用 Git 提交了几十个 commit为什么让你写“今天做了什么”的时候你还是会卡住原因是“写代码”和“写进度”是两套完全不同的思维活动。写代码时你面对的是具体的技术问题专注点在函数、接口、数据流上写进度时你要做的是从时间维度回放自己的一天把零散的改动归类、概括、翻译成别人能看懂的语言。这个转换过程有真实的认知成本而且发生在一天最疲惫的时刻。更麻烦的是很多团队的进度汇报没有统一格式。有人按“做了什么”写有人按“遇到了什么困难”写有人写成了流水账有人写成了邀功文学。管理者其实很难从这些文本里判断真实进展而开发者又觉得写这些浪费时间。双方都觉得对方有问题。但换个角度看每个开发者一天真正交付的东西其实已经写进了 Git 历史里。你改动了哪些文件、提交了多少次、提交信息写的是什么、对应哪个需求分支这些都是客观存在的数据。问题不在于“今天没有进度”而在于“进度从未被结构化采集每次都要重新加工”。所以我更倾向的判断是进度管理的核心矛盾不是人不够勤快而是信息的产生和消费之间缺了一条自动化管道。开发者在写 commit message 的时候实际上已经在做一次轻量级的进度记录只需要把它变成规范和工具就能在汇报时省掉大量回忆和整理的时间。2. 核心思路让 Git 提交记录成为进度的事实来源这套方案的基本思想是把 Git 提交记录当作开发进度的唯一事实来源然后用脚本把它转换成日报、周报和统计表。为什么选 Git 提交记录作为事实来源有三个理由。第一它无法抵赖。代码改动在 Git 里有完整的哈希记录和历史时间线比人脑回忆可靠得多。第二它本来就有时间信息。每次提交都有 author 和 commit 时间天然适合按天、按周聚合。第三它包含了语义信息。只要你给 commit message 规定格式提交信息本身就是在给代码变更打标签比如“修复了什么”“新增了什么”“重构了什么”。一个开发者的日变化轨迹其实是这样的早晨拉分支上午写代码提交时写下feat: 增加订单导出功能下午修 Bug提交时写下fix: 修复金额精度丢失问题。这些 commit message 连起来就是当天最真实的开发记录。为了让机器能处理我们还需要一个四层模型层次内容说明第一层Commit Message原子变更的描述是源数据第二层标签与类型type(scope): subject例如 feat、fix、docs第三层周期聚合按天/人/需求汇总成日报、周报第四层复盘与度量统计类型分布、提交频率、任务完成度如果前面的 commit message 不遵守规范后面的脚本解析就是空谈。所以这套方案的第一个落地动作不是写脚本而是先统一提交规范。3. 环境准备与前置条件这套工具的运行时依赖非常轻适合在任何开发者机器上使用。本文示例以通用方式演示版本号请以你实际环境为准。操作系统Windows / macOS / Linux 均可。Windows 建议在 Git Bash 或 PowerShell 下执行。Git2.23 及以上版本即可git log的常用参数在旧版本也基本可用。Python3.8 及以上版本使用标准库subprocess、datetime、collections不需要安装第三方包。代码仓库一个已经用 Git 管理的项目仓库或者一个专门用于记录每日工作的“进度仓库”。如果不想使用 Python也可以用 Shell、Node.js 或 Go 实现同样的逻辑核心思路是调用git log拿到结构化提交数据再按类型聚合。选择 Python 只是因为它写起来直观跨平台也方便。验证环境是否可用可以执行以下命令git --version python --version在项目根目录执行git log --oneline -5如果能正常输出最近 5 条提交说明环境没问题。4. 第一步统一提交规范让 commit 从源头可解析要让脚本准确解析“今天做了什么”每条提交信息应该符合下面的格式type(scope): subject示例feat(order): 增加订单导出功能 fix(pay): 修复金额精度丢失问题 docs(readme): 补充部署说明 test(cart): 增加购物车单元测试 refactor(auth): 拆分登录校验逻辑 chore: 升级依赖版本常用类型及含义如下类型含义日报展示建议feat新功能新增了……fixBug 修复修复了……docs文档变更更新了文档……refactor重构不改行为重构了……test测试相关补充/调整了测试……chore构建、依赖、杂项完成……维护事项style格式调整调整了代码风格perf性能优化优化了……性能这里真正容易踩坑的地方是如果没有 scope也不要强求。scope 是为了快速定位模块小型项目完全可以不写直接写fix: 修复登录时密码校验失败的问题。解析脚本要兼容“有 scope”和“无 scope”两种格式。在项目根目录创建.gitmessage模板文件内容如下# 提交信息模板示例 # type(scope): subject # # 常用类型 # feat: 新功能 # fix: Bug 修复 # docs: 文档变更 # refactor: 重构 # test: 测试 # chore: 构建/依赖/杂项 # # 示例 # feat(order): 增加订单导出功能然后设置 Git 使用该模板git config commit.template .gitmessage这样每次执行git commit时编辑器会自动带上提示模板降低团队成员的记忆成本。还可以配置一个带类型校验的提交命令减少低级错误。例如在.bashrc或.zshrc中增加一个函数# 快速提交示例格式: gc feat 增加订单导出功能 gc() { if [ $# -ne 2 ]; then echo 用法: gc type \subject\ return 1 fi git add -A git commit -m $1: $2 }对于团队项目更规范的做法是引入 commitlint husky在提交时直接拦截不合法格式。但这部分依赖 Node.js 工具链不在本文的必选范围内。个人使用阶段用模板加 alias 就足够。需要明确提交规范不是目的自动化解析才是目的。如果提交信息不统一后面的脚本能统计到的就只有“提交次数”无法告诉你“今天完成了什么类型的工作”。5. 第二步编写日报生成脚本下面给出一个可直接运行的 Python 脚本。它的作用是读取 Git 历史中某一天的提交记录按类型分组生成一份 Markdown 日报。文件路径daily-report.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- 基于 Git 提交记录生成开发日报。 用法: python daily-report.py # 生成今天的日报 python daily-report.py 2025-06-10 # 生成指定日期的日报 import subprocess import sys from datetime import date, datetime from collections import OrderedDict # 类型与中文展示名 TYPE_LABELS OrderedDict([ (feat, 新增功能), (fix, Bug 修复), (perf, 性能优化), (refactor, 代码重构), (docs, 文档变更), (test, 测试补充), (chore, 维护事项), (style, 样式调整), (build, 构建相关), (ci, 持续集成), (other, 其他), ]) def run_git_log(target_date: str) - str: 获取指定日期的 git 提交信息按提交时间倒序。 start f{target_date} 00:00:00 end f{target_date} 23:59:59 cmd [ git, log, --since, start, --until, end, --prettyformat:%h|%an|%s, --date-order, ] result subprocess.run(cmd, capture_outputTrue, textTrue, encodingutf-8) if result.returncode ! 0: raise RuntimeError(fgit log 执行失败: {result.stderr}) return result.stdout.strip() def parse_commit_line(line: str): 解析一行提交记录返回 (hash, author, message)。 hash_val, author, message line.split(|, 2) return hash_val, author, message.strip() def classify_message(message: str) - str: 从 commit message 中解析类型。 if : in message: prefix message.split(:, 1)[0].strip() # 兼容 feat(order) 这种带 scope 的写法 if ( in prefix: prefix prefix.split((, 1)[0] if prefix in TYPE_LABELS: return prefix return other def format_items(items): 将同类型提交格式化为 markdown 列表。 lines [] for hash_val, author, message in items: # 去掉类型前缀让日报更简洁 display message if : in message: display message.split(:, 1)[1].strip() lines.append(f- [{hash_val}] {display}{author}) return lines def generate_markdown(target_date: str) - str: raw run_git_log(target_date) if not raw: return f# {target_date} 开发日报\n\n当天没有提交记录。\n grouped OrderedDict((key, []) for key in TYPE_LABELS.keys()) for line in raw.splitlines(): hash_val, author, message parse_commit_line(line) type_key classify_message(message) grouped[type_key].append((hash_val, author, message)) md_lines [f# {target_date} 开发日报, ] total sum(len(v) for v in grouped.values()) md_lines.append(f提交总数{total} 次) md_lines.append() for type_key, label in TYPE_LABELS.items(): items grouped[type_key] if not items: continue md_lines.append(f## {label}{len(items)}) md_lines.extend(format_items(items)) md_lines.append() return \n.join(md_lines) def main(): if len(sys.argv) 1: target_date sys.argv[1] datetime.strptime(target_date, %Y-%m-%d) else: target_date date.today().isoformat() content generate_markdown(target_date) filename fdaily-report-{target_date}.md with open(filename, w, encodingutf-8) as f: f.write(content) print(f日报已生成: {filename}) print(content) if __name__ __main__: main()这段脚本的逻辑并不复杂关键点有三个第一通过git log --since --until过滤出某一天的提交而不是简单用“最近 24 小时”。因为开发者经常早上 9 点提交昨天的收尾代码如果按 24 小时窗口统计时间边界就会错乱。第二解析 commit message 时兼容了feat: xxx和feat(order): xxx两种格式。只要冒号前的单词属于 TYPE_LABELS 列表就算解析成功不支持的格式统一归为“其他”。第三输出的是 Markdown 文件方便直接粘贴到企业微信、钉钉、飞书或者内部 Wiki。Markdown 是团队协作中最通用的格式也比纯文本有结构感。如果你想把日报直接输出到终端而不是文件也可以把main()里写文件的部分注释掉。无论如何先跑通一次再改细节。6. 第三步生成周报汇总与 CSV 统计日报解决了“今天做了什么”的问题但管理者通常还要看“这一周整体节奏如何”。周报不需要像日报那样逐条列出提交而是要体现结构和趋势。继续用 Python 写一个周报脚本读取过去 7 天的提交记录统计各类型提交的数量、活跃天数、涉及人数并生成 CSV 文件用于 Excel 分析。文件路径weekly-report.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- 基于 Git 提交记录生成周报汇总。 用法: python weekly-report.py # 生成最近 7 天的周报 python weekly-report.py 2025-06-10 # 以指定日期为结束日期统计前 6 天 import subprocess import sys import csv from datetime import date, datetime, timedelta from collections import OrderedDict, Counter TYPE_LABELS OrderedDict([ (feat, 新增功能), (fix, Bug 修复), (perf, 性能优化), (refactor, 代码重构), (docs, 文档变更), (test, 测试补充), (chore, 维护事项), (style, 样式调整), (build, 构建相关), (ci, 持续集成), (other, 其他), ]) def get_week_range(end_date: str): 返回从 end_date-6 到 end_date 的日期列表。 end datetime.strptime(end_date, %Y-%m-%d).date() start end - timedelta(days6) return start, end, [start timedelta(daysi) for i in range(7)] def run_git_log_in_range(start: str, end: str) - str: cmd [ git, log, --since, f{start} 00:00:00, --until, f{end} 23:59:59, --prettyformat:%ad|%h|%an|%s, --dateformat:%Y-%m-%d, --date-order, ] result subprocess.run(cmd, capture_outputTrue, textTrue, encodingutf-8) if result.returncode ! 0: raise RuntimeError(fgit log 执行失败: {result.stderr}) return result.stdout.strip() def classify_message(message: str) - str: if : in message: prefix message.split(:, 1)[0].strip() if ( in prefix: prefix prefix.split((, 1)[0] if prefix in TYPE_LABELS: return prefix return other def main(): if len(sys.argv) 1: end_date sys.argv[1] datetime.strptime(end_date, %Y-%m-%d) else: end_date date.today().isoformat() start, end, day_list get_week_range(end_date) raw run_git_log_in_range(start.isoformat(), end.isoformat()) type_counter Counter() author_counter Counter() day_counter Counter() rows [] for line in raw.splitlines(): parts line.split(|, 3) if len(parts) 4: continue day_str, hash_val, author, message parts type_key classify_message(message) type_counter[type_key] 1 author_counter[author] 1 day_counter[day_str] 1 rows.append([day_str, hash_val, author, message]) # 输出 CSV 明细 csv_filename fweekly-detail-{start}-{end}.csv with open(csv_filename, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([日期, 提交哈希, 作者, 提交信息]) writer.writerows(rows) # 输出周报摘要到 Markdown md_lines [ f# 开发周报{start} ~ {end}, , f- 提交总数{len(rows)} 次, f- 活跃天数{len(day_counter)} 天, f- 参与人数{len(author_counter)} 人, , ## 按类型统计, , | 类型 | 数量 |, | --- | --- |, ] for type_key in TYPE_LABELS.keys(): cnt type_counter.get(type_key, 0) if cnt 0: md_lines.append(f| {TYPE_LABELS[type_key]} | {cnt} |) md_lines.append() md_lines.append(## 按作者统计) md_lines.append() md_lines.append(| 作者 | 提交数 |) md_lines.append(| --- | --- |) for author, cnt in author_counter.most_common(): md_lines.append(f| {author} | {cnt} |) md_filename fweekly-report-{start}-{end}.md with open(md_filename, w, encodingutf-8) as f: f.write(\n.join(md_lines)) print(f周报已生成: {md_filename}) print(fCSV 明细已生成: {csv_filename}) if __name__ __main__: main()注意 CSV 写入时使用了utf-8-sig编码这是为了让 Excel 直接打开时中文不乱码。这个小细节在 Windows 环境下尤其重要。周报汇总里最值得关注的是“活跃天数”。如果一个成员一周 7 天只有 2 天有提交可能是需求周期长、提交习惯不好也可能是确实在划水。它不能直接说明绩效但能辅助回顾。这个指标的价值在于发现问题而不是做评判。7. 运行方式与效果验证脚本写完后建议先用一个有历史提交的仓库做一次验证。假设今天是 2025 年 6 月 10 日执行python daily-report.py 2025-06-10预期会生成daily-report-2025-06-10.md内容大致如下# 2025-06-10 开发日报 提交总数5 次 ## 新增功能2 - [a1b2c3] 增加订单导出功能张三 - [d4e5f6] 增加批量导入接口李四 ## Bug 修复2 - [g7h8i9] 修复金额精度丢失问题张三 - [j0k1l2] 修复登录态过期后跳转异常王五 ## 文档变更1 - [m3n4o5] 补充部署说明李四如何判断脚本运行成功看三点脚本退出码为 0无异常输出。生成的 Markdown 文件存在且提交总数与git log手动查询的结果一致。分类符合预期。如果某条提交被分到“其他”说明 commit message 的类型前缀没写对需要回去检查。之后可以运行周报python weekly-report.py预期生成两个文件weekly-report-2025-06-04-2025-06-10.md和对应的 CSV。打开 CSV如果中文不乱码说明utf-8-sig生效了。如果想每天自动生成日报可以把脚本加入定时任务。以 Linux/macOS 的 crontab 为例每天 18:30 生成当天日报30 18 * * * cd /path/to/your/repo python /path/to/daily-report.py /path/to/report-cron.log 21Windows 用户可以在“任务计划程序”里创建基本任务触发器选“每天”操作填 Python 解释器路径和脚本路径。8. 常见问题与排查思路问题现象可能原因排查方式解决方案git log输出为空当天确实没有提交或日期参数格式错误手动执行 git log 加相同日期参数检查日期格式是否为 YYYY-MM-DD若仓库在--since时间之后才有提交调整日期某些提交被归为“其他”commit message 没写类型前缀或使用了自定义类型查看原始提交信息git log --prettyformat:%s统一规范如有定制类型在 TYPE_LABELS 中补充映射中文乱码编码不一致检查终端和文件编码统一使用 UTF-8CSV 使用 utf-8-sig 编码多行 commit message 解析异常--prettyformat只保留主题行但部分提交有 body查看完整提交信息git show hash脚本默认只取 subject如需正文内容需扩展解析逻辑时间边界不对使用了错误的时区或日期窗口用git log --format%ad对比时间确认--since/--until使用本地时间如需按作者时间而非提交时间改参数合并导致统计虚高merge 提交也被计入查看提交记录中是否有 Merge 行在 git log 增加--no-merges参数未推送的本地提交计入脚本统计的是本地仓库历史确认统计预期这是正常行为如只需已推送提交可加origin/main..HEAD过滤两人共用账号导致统计不准Git user.name 配置相同查看提交者信息git log --prettyformat:%an为每个成员单独配置 user.name / user.email关于安全提醒这条一定要记住。提交信息中不要写敏感信息比如账号密码、Token、密钥或者客户内部数据。因为 Git 历史是持久化数据即使删掉旧提交也可能残留在 reflog 或远端历史中。这套脚本本身只是读取 git log并不修改任何 Git 数据相对安全但输入的原始数据如果包含敏感内容风险在源头。9. 最佳实践与工程建议这套方案能跑通很容易真正难的是长期坚持。以下几条建议来自我在实际项目中的观察按优先级排序。第一提交信息要按“逻辑单位”提交不要按时间堆砌。一次提交只做一件事fix: 修复登录校验的 Token 过期判断就是一次提交。不要出现“提交一下改动杂七杂八”的情况否则类型统计和回溯定位都会失真。第二每天结束前花两分钟整理提交。不需要天天跑脚本但至少执行一次git status和git log --oneline确认今天的工作都被合理记录。如果发现某个改动忘了提交趁当天补上不要等到第二天再补。第三日报自动生成后仍然需要人工写一句“结论”。脚本只能告诉你做了什么不能告诉你事情做得顺不顺利。我建议的格式是自动生成的清单 一句人工总结比如“协议字段已联调完成明天开始适配客户端”。这样既保住了数据真实性又保留了人的判断。第四不要为了统计好看而拆分提交。有人为了让“提交次数”好看把一次改动硬拆成五次提交。这是典型的指标化反噬。提交次数只是参考维度不是 KPI。如果团队真的需要考核工作量也应该结合需求完成数、代码评审意见、线上故障数等综合评估而不是只看 commit 数量。第五脚本要放在仓库之外或者使用独立的进度仓库。如果你把这套工具脚本直接提交到业务项目里容易污染业务仓库的统计结果。更推荐的做法是单独建一个work-log仓库用来记录日常工作的提交或者把脚本放在~/.local/bin目录下对所有项目通用。第六与研发流程工具结合会更有效。如果公司使用 Jira、禅道、飞书、Teambition 之类的工具可以在 commit message 里加上需求编号例如feat(ORDER-123): 增加订单导出功能。这样就能从 Git 提交反查到需求卡片实现从需求到代码的完整追踪。业界把这个模式叫做“可追溯提交”比单独的进度文档要可靠得多。第七从个人推广到团队时先说服一两个人试点。直接要求整个团队用提交规范抵触情绪大概率会很大。更好的路径是先自己用两周生成几份好看的日报在周会上展示“原来提交记录能自动形成进度报告”让同事看到收益再逐步推广。规范从来不是靠命令落地的而是靠工具让遵守规范的人更省力。10. 总结与后续方向把“今天的进度”写清楚本质上不是文笔问题而是工程问题。开发者的每一天都由数十次代码变更组成这些变更有精确的时间戳和语义描述它们已经是最好的进度记录。你需要做的只是定一套提交规范写一个不到 150 行的解析脚本然后把精力留给真正需要人的判断的地方。本文通过一个可运行的 Python 脚本演示了从 Git 提交记录到日报、周报、CSV 统计的完整链路。你可以直接复制代码到本地验证也可以根据自己的项目情况调整 TYPE_LABELS、日期窗口、输出格式。这里没有复杂的架构没有新增服务所有东西都建立在 Git 本身的能力之上这也是它容易被采纳的原因。下一步值得深入的方向有三个第一把提交信息里的需求编号解析出来与项目管理系统打通形成自动更新的需求状态。第二给脚本增加增量报告逻辑记录“连续提交天数”帮助自己复盘节奏是否健康。第三结合代码评审数据把合并请求的评审耗时也纳入周报从提交到合入的完整链路让进度记录更完整。最后提醒一句工具可以帮你生成报告但没法替你判断“今天做得怎么样”。留出两分钟看一遍自动生成的日报比让脚本自动发到群里更有价值。长期积累之后你会发现自己对项目的感知能力和对时间的掌控能力都会比靠记忆写日报的时候好很多。建议把这套脚本收藏下来周末找一个小仓库试跑一次再决定要不要用到日常工作中。
返回列表