Analyze all commits within a specified time range in the current git repository and generate a structured work retrospective report. Suitable for any content managed by git, such as code, documents, design, research, etc.
When to Use
Triggered when the user requests the following operations:
- "Do a retrospective" / "What did I do today" / "Work summary"
- "review commits" / "git review" / "daily review"
- "What did I do this week" / "Work from the last 3 days" / "retrospective"
- Any request involving reviewing git commit history and performing analysis
Phase 0: Parse input — determine the time range
Determine the analysis time range based on user input:
Default: yesterday 22:00 to the current time (covers work sessions that cross midnight)
Natural language mapping:
| User input | --after | --before |
|---|---|---|
| Today / today | Today 00:00 | now |
| Yesterday / yesterday | Yesterday 00:00 | Yesterday 23:59 |
| This week / this week | This Monday 00:00 | now |
| Last N days / last N days | N days ago 00:00 | now |
| Specific date (e.g., February 20) | That day 00:00 | That day 23:59 |
| Date range (e.g., 2/20-2/23) | Start date 00:00 | End date 23:59 |
| Default (unspecified) | Yesterday 22:00 | now |
Use the date command to calculate the specific timestamp and convert it to a format usable by git log (e.g., 2026-02-22T22:00:00)。
Phase 1: Data collection
Pre-check: First run git rev-parse --is-inside-work-tree to confirm the current directory is a git repository. If not, inform the user and stop.
Pull the latest code: Run git pull to ensure the analysis is based on the latest commit history. If the pull fails (network issues, conflicts, etc.), ignore the error and continue with the subsequent steps; do not retry.
Execute the following 5 commands in order (local operations, no need for parallelization):
1. Full commit history
git log --after="{after}" --before="{before}" --format="%H|%an|%ai|%s|%b|||" --name-status
If the result is empty,all subsequent steps must stop immediately. Do not try to expand the time range, do not look for the most recent commits, and do not adjust parameters on your own to continue the analysis. Just:
- Inform the user that there are no commits within that time range
- Show the times of the 5 most recent commits to help the user choose an appropriate range
- Suggest that the user specify a time range (e.g., "retrospective for yesterday", "retrospective for 2/22", "last 3 days")
- Wait for the user's next instruction
2. Commit statistics
git log --after="{after}" --before="{before}" --stat --format="%H %s"
3. Overall change statistics for the time period
git diff --stat $(git log --after="{after}" --before="{before}" --format="%H" | tail -1)^..$(git log --after="{after}" --before="{before}" --format="%H" | head -1)
If there is only one commit, use git show --stat {hash} instead.
4. Branch information
git branch -a --sort=-committerdate | head -20
5. Current unfinished work
git status --short && echo "---STASH---" && git stash list
6. Personal records for the day (optional)
Check whether the repository has a notes/daily_notes/ directory and the corresponding daily record files (naming format:{YEAR}H{1|2}-daily-notes.md, e.g., 2026H1-daily-notes.md):
find notes/daily_notes -name "*-daily-notes.md" 2>/dev/null | head -5
If the file is found, extract all record blocks involving dates within the time range. For each target date (format YYYY-MM-DD), perform:
# 提取该日期的记录块(从日期标题到下一个日期标题前)
awk '/^### {YYYY-MM-DD}/{f=1;next} /^### [0-9]{4}-[0-9]{2}-[0-9]{2}/{f=0} f' notes/daily_notes/{FILE}
If the file does not exist, or there is no record for the specified date, skip this step; it does not affect subsequent analysis.
Phase 2: Seven-Dimension Analysis
Based on the collected data, complete the following analyses one by one.
Dimension 0: Records of the Day (if any)
Execute this dimension only when records were collected in Phase 1, Step 6.
- Fully display the original personal records for that date (preserve indentation and checkbox states)
- Mark the status of each item:
[x]Completed /[ ]Not completed /[-]No corresponding commit - Cross-compare with git commits:
- In the records,
[x]Can corresponding commits be found in the commits for the item(s)? - Which commits are not mentioned in the records (possibly temporary fixes or extra work)?
- Which planned items in the records have no corresponding commits (not completed or to be continued tomorrow)?
- In the records,
Dimension 1: Work Summary
- Group commits by logical theme (rather than simply arranging them by time)
- Summarize each group of work in narrative language, explaining what was done and why
- Attach a commit timeline table:
| 时间 | Hash (短) | 提交信息 |
Dimension 2: Distribution of Change Types
Classify changes by file suffix and path into the following types, and count the number of files and line changes for each type:
| Type | Matching Rule |
|---|---|
| Code | .go, .py, .js, .ts, .java, .rs, .c, .cpp, .swift, .kt etc. |
| Test | Path contains test/spec/_test, or file name contains test/spec |
| Documentation | .md, .txt, .rst, .adoc, .doc |
| Configuration | .yaml, .yml, .json, .toml, .ini, .env, Dockerfile, Makefile |
| Design/Research | Path contains design/research/rfc/proposal/audit/review |
| Dependencies | go.mod, go.sum, package.json, package-lock.json, requirements.txt, Cargo.toml, Gemfile |
| Other | Files that match none of the above |
Output the classification table and pie-chart-style proportions.
Dimension 3: Work Rhythm
- Draw the commit timeline (represented in text, such as one cell per hour)
- Identify Flow Sessions: consecutive commits with an interval < 30 minutes are considered the same session
- Statistics: first commit time, last commit time, total span, number of sessions, longest session, longest interval
- If there is only 1 commit, skip the rhythm analysis and only record the commit time
Dimension 4: Commit Practice Assessment
Score commit habits on a 1-5 scale:
| Assessment Item | 5-point Standard | 1-point Standard |
|---|---|---|
| Message Quality | Clearly describes what + why | Vague or meaningless (such as "update", "fix") |
| Granularity | Each commit is an independent logical unit | Giant commits mixing multiple unrelated changes |
| Conventional Commits | Follows type(scope): description |
No conventions at all |
Give the score for each item, good examples (from actual commits), and examples that can be improved.
Dimension 5: Technical Decision Identification
Scan the change content and identify the following types of technical decisions:
- New dependency introduction: newly added items in dependency files
- Architecture change: New directory structure, new modules, interface changes
- Refactoring: Large-scale file renames/moves, function signature changes
- Security-related: Changes involving auth, token, secret, permission
- API changes: Modifications to routes, endpoints, schema
List the specific commit and impact assessment for each item. If no technical decisions are identified, briefly explain.
Dimension 6: Completeness check
Check in checklist format:
- Are there uncommitted changes (
git status) - Is there stashed work in the stash
- Does the newly added code contain
TODO/FIXME/HACK/XXXcomments - Do the newly added code files have accompanying test files (check whether files with the same name
_testexist)
Give each item a Pass/Warning/Info marker and specific content.
Dimension 7: Improvement suggestions
Based on the analysis results of the above 6 dimensions, give 3-5 actionable improvement suggestions. Each suggestion needs to:
- Cite specific analysis data as evidence
- Propose clear action items
- Explain the expected effect
Phase 3: Output report
Output the final report in the following HTML format. Use inline CSS to ensure good display in both browsers and Feishu:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Git 工作复盘 — {repo} {date}</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; max-width: 860px; margin: 0 auto; padding: 20px; color: #1a1a1a; background: #f8f9fa; }
.report { background: #fff; border-radius: 12px; padding: 32px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); }
h1 { font-size: 24px; border-bottom: 3px solid #0d7377; padding-bottom: 12px; margin-bottom: 4px; }
h2 { font-size: 17px; color: #0d7377; margin-top: 28px; border-left: 4px solid #0d7377; padding-left: 10px; }
h3 { font-size: 14px; color: #444; margin-top: 14px; }
.meta { color: #666; font-size: 13px; margin-bottom: 16px; }
.summary { background: #e0f7f7; border-radius: 8px; padding: 16px; font-size: 15px; margin: 16px 0; }
.summary ol { margin: 8px 0 0 0; padding-left: 20px; }
.summary li { margin: 4px 0; }
table { width: 100%; border-collapse: collapse; margin: 12px 0; font-size: 14px; }
th { background: #f1f3f4; text-align: left; padding: 10px 12px; font-weight: 600; border-bottom: 2px solid #ddd; }
td { padding: 8px 12px; border-bottom: 1px solid #eee; vertical-align: top; }
tr:hover td { background: #f8f9fa; }
.mono { font-family: "SFMono-Regular", Consolas, monospace; font-size: 12px; color: #555; }
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 12px; font-weight: 500; }
.tag-pass { background: #e8f5e9; color: #2e7d32; }
.tag-warn { background: #fff3e0; color: #e65100; }
.tag-info { background: #f5f5f5; color: #616161; }
.timeline { font-family: "SFMono-Regular", Consolas, monospace; font-size: 13px; background: #f8f9fa; padding: 12px 16px; border-radius: 6px; overflow-x: auto; white-space: pre; }
.stars { color: #f5a623; letter-spacing: 2px; }
.suggestion { background: #f3f8ff; border-left: 3px solid #0d7377; padding: 10px 14px; margin: 8px 0; border-radius: 0 6px 6px 0; }
.suggestion strong { display: block; margin-bottom: 4px; }
.checklist { list-style: none; padding: 0; }
.checklist li { padding: 6px 0; border-bottom: 1px solid #f0f0f0; font-size: 14px; }
ul, ol { padding-left: 20px; }
li { margin: 5px 0; line-height: 1.6; }
code { background: #f1f3f4; padding: 1px 5px; border-radius: 3px; font-size: 12px; font-family: "SFMono-Regular", Consolas, monospace; }
.daily-notes { background: #fafafa; border: 1px solid #e8e8e8; border-radius: 8px; padding: 14px 18px; font-size: 13px; white-space: pre-wrap; font-family: inherit; line-height: 1.7; }
.daily-notes .done { color: #2e7d32; }
.daily-notes .pending { color: #888; }
.match-table td:first-child { width: 60px; text-align: center; }
</style>
</head>
<body>
<div class="report">
<h1>Git 工作复盘</h1>
<div class="meta">{时间范围} | 仓库: <strong>{repo}</strong> | {提交数} commits | {文件变更数} files changed | <span style="color:#2e7d32">+{新增行}</span> <span style="color:#c62828">-{删除行}</span></div>
<!-- 仅当存在当日记录时输出此 section,否则完全省略 -->
<h2>0. 当日记录</h2>
<div class="daily-notes">{当日个人记录原文,保留原始缩进和 checkbox}</div>
<h3>计划 vs 实际对比</h3>
<table class="match-table">
<tr><th>状态</th><th>记录条目</th><th>对应 Commit</th></tr>
<tr><td><span class="tag tag-pass">✓ 已提交</span></td><td>...</td><td class="mono">abc1234</td></tr>
<tr><td><span class="tag tag-warn">○ 未提交</span></td><td>...</td><td>—</td></tr>
<tr><td><span class="tag tag-info">+ 额外</span></td><td>记录未提及的 commit</td><td class="mono">def5678</td></tr>
</table>
<div class="summary">
<strong>核心发现</strong>
<ol>
<li>...</li>
<li>...</li>
<li>...</li>
</ol>
</div>
<h2>1. 工作总结</h2>
<p>{叙述式总结:按逻辑主题分组说明做了什么、为什么做}</p>
<h3>提交时间线</h3>
<table>
<tr><th>时间</th><th>Hash</th><th>提交信息</th></tr>
<tr><td>HH:MM</td><td class="mono">abc1234</td><td>...</td></tr>
</table>
<h2>2. 变更类型分布</h2>
<table>
<tr><th>类型</th><th>文件数</th><th>占比</th><th>增删行数</th></tr>
<tr><td>代码</td><td>...</td><td>...%</td><td>+... -...</td></tr>
<tr><td>测试</td><td>...</td><td>...%</td><td>+... -...</td></tr>
<tr><td>文档</td><td>...</td><td>...%</td><td>+... -...</td></tr>
<tr><td>配置</td><td>...</td><td>...%</td><td>+... -...</td></tr>
<tr><td>其他</td><td>...</td><td>...%</td><td>+... -...</td></tr>
</table>
<p>{分析说明}</p>
<h2>3. 工作节奏</h2>
<table>
<tr><th>指标</th><th>数值</th></tr>
<tr><td>首次提交</td><td>...</td></tr>
<tr><td>末次提交</td><td>...</td></tr>
<tr><td>总跨度</td><td>...</td></tr>
<tr><td>Flow Sessions</td><td>... 个</td></tr>
<tr><td>最长 Session</td><td>...</td></tr>
<tr><td>最长间隔</td><td>...</td></tr>
</table>
<div class="timeline">{时间线可视化,用 ASCII 字符表示,如每格代表一小时}</div>
<h2>4. 提交实践评估</h2>
<table>
<tr><th>评估项</th><th>评分</th><th>说明</th></tr>
<tr><td>Message 质量</td><td><span class="stars">★★★★☆</span></td><td>...</td></tr>
<tr><td>提交粒度</td><td><span class="stars">★★★☆☆</span></td><td>...</td></tr>
<tr><td>Conventional Commits</td><td><span class="stars">★★★★★</span></td><td>...</td></tr>
</table>
<p><strong>好的示例:</strong> <code>feat(auth): add JWT refresh token rotation</code></p>
<p><strong>可改进:</strong> <code>fix</code> → 改为 <code>fix(module): describe what was fixed</code></p>
<h2>5. 技术决策</h2>
<ul>
<li><strong>新依赖引入</strong>: ... (<code>abc1234</code>)</li>
<li><strong>架构变更</strong>: ... (<code>def5678</code>)</li>
</ul>
<h2>6. 完成度检查</h2>
<ul class="checklist">
<li><span class="tag tag-pass">Pass</span> 未提交改动: 工作区干净</li>
<li><span class="tag tag-warn">Warning</span> Stash 暂存: ...</li>
<li><span class="tag tag-info">Info</span> TODO/FIXME: ...</li>
<li><span class="tag tag-pass">Pass</span> 测试配套: ...</li>
</ul>
<h2>7. 改进建议</h2>
<div class="suggestion"><strong>1. {建议标题}</strong>{具体内容}(证据:{引用分析数据})</div>
<div class="suggestion"><strong>2. {建议标题}</strong>...</div>
<div class="suggestion"><strong>3. {建议标题}</strong>...</div>
</div>
</body>
</html>
HTML filling rules:
- Replace the placeholders in the template with actual data, delete comments
- Use
★(filled) and☆(empty) for star ratings, 5 points=★★★★★ - Completeness labels: Pass=
tag-pass(green), Warning=tag-warn(orange), Info=tag-info(gray) - Draw the timeline visualization with monospaced characters, each cell represents one hour, use
█for cells with commits, and· - Ensure the HTML is complete and can be opened directly in a browser
Save the report as git-review-{date}.html to the output/ subdirectory of the current working directory (use the current directory if none exists), where {date} is the current date (e.g. 2026-02-23)。
After saving the HTML, use Chrome headless to convert to PDF:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--headless --disable-gpu --no-sandbox \
--print-to-pdf="$(pwd)/output/git-review-{date}.pdf" \
--no-pdf-header-footer \
"file://$(pwd)/output/git-review-{date}.html"
If Chrome is unavailable, use the alternative:
npx -y md-to-pdf "$(pwd)/output/git-review-{date}.html"
Finally output two files:
output/git-review-{date}.html— HTML versionoutput/git-review-{date}.pdf— PDF version (for sending via Feishu)
Edge Cases
- No record for the day:
notes/daily_notes/does not exist or no matching heading for the specified date, skip dimension 0 and report section 0, the other dimensions are unaffected - Multi-day range containing records for multiple days: Extract each day's record block in turn, display them merged in the report, in reverse chronological order
- No commits: After Phase 1 step 1 detects an empty result,immediately terminate the process——show the 5 most recent commit times for reference, prompt the user to respecify the range. Do not expand the time range on your own or continue to subsequent Phases
- Single commit: Generate the report normally, but skip the session analysis of dimension 3 (work rhythm), simplifying it to only recording the commit time
- Non-git repository: Phase 1 pre-check fails, prompt the user that the current directory is not a git repository
- Binary files: Only marked as binary in the file list, skip line count statistics, do not attempt diff analysis
- Extra-large time range (>100 commits): Analyze normally, but when grouping by topic in dimension 1, perform a higher-level summarization to avoid an overly long report