You can auto-generate a standup report from git history using git log with date and author filters, a shell script to format the output, and optionally a cron job to deliver it before your meeting starts. This eliminates the daily ritual of reconstructing yesterday's work from memory and produces a report grounded in what actually happened in the codebase.
Why This Matters
The daily standup has a simple premise: each person shares what they did, what they plan to do, and what is blocking them. In practice, the "what I did" part is the weakest link. Developers answer from memory, which is unreliable after a full night of sleep and a morning of context-switching. The result is vague updates like "worked on the backend" or "continued with the ticket" that give the team no actionable information.
Git history is an objective record. Every commit has a timestamp, an author, a branch, and a message. It does not forget, it does not emphasize the dramatic bug over the three steady feature commits, and it does not conflate Tuesday's work with Wednesday's. A script that reads this history and formats it into a standup report is more accurate than your memory and takes zero mental effort to produce.
The limitation is that git history only captures code changes. It misses code reviews, architecture discussions, debugging sessions that ended without a commit, and operational work. A complete standup solution combines git automation with either a brief manual supplement or continuous IDE-based activity tracking.
Short Answer
Create a script that runs git log --since="yesterday" --author="$(git config user.name)" --format="- %s" across your repositories, formats the output with project headers, and optionally posts it to Slack via webhook. Run it manually before standup or schedule it with cron. For a fully automated standup report that includes coding time and non-commit work, use an IDE plugin like CodeClocker.
Step-by-Step
1. Query Git History for Yesterday's Work
The foundation of every git-based standup report is a filtered log query. This version handles the Monday edge case and outputs clean commit messages.
#!/bin/bash
# git-standup: query yesterday's commits (or Friday's on Monday)
AUTHOR="$(git config user.name)"
DOW=$(date +%u)
if [ "$DOW" -eq 1 ]; then
SINCE="last friday"
LABEL="Friday-Sunday"
else
SINCE="yesterday"
LABEL="Yesterday"
fi
echo "**$LABEL:**"
git log --since="$SINCE" --author="$AUTHOR" \
--format="- %s" --reverse --all 2>/dev/null
Key flags: --reverse puts commits in chronological order (oldest first), which reads naturally. --all includes commits on feature branches that have not been merged yet, so your work-in-progress shows up even if it has not hit main.
Output on a Tuesday morning:
**Yesterday:**
- Add database migration for notification preferences
- Implement preference validation middleware
- Write unit tests for preference constraint checks
- Fix timezone offset in preference sync scheduler
2. Aggregate Across Multiple Repositories
Most developers work across two or more repos in a day. This script scans a parent directory of projects and assembles a unified standup report.
#!/bin/bash
# multi-repo-standup: scan all repos for yesterday's commits
AUTHOR="$(git config user.name)"
DOW=$(date +%u)
[ "$DOW" -eq 1 ] && SINCE="last friday" || SINCE="yesterday"
found=0
for repo in ~/projects/*/; do
[ -d "$repo/.git" ] || continue
commits=$(git -C "$repo" log --since="$SINCE" --author="$AUTHOR" \
--format="- %s" --reverse --all 2>/dev/null)
if [ -n "$commits" ]; then
project=$(basename "$repo")
echo "**$project:**"
echo "$commits"
echo ""
found=1
fi
done
[ "$found" -eq 0 ] && echo "No commits found since $SINCE."
Output:
**payment-api:**
- Add idempotency key support for charge requests
- Fix race condition in concurrent refund processing
- Update Stripe webhook signature validation
**admin-portal:**
- Add refund status column to transaction list view
- Implement bulk refund action with confirmation dialog
Five commits across two repos. That is a complete "what I did" section: "Yesterday I added idempotency keys and fixed a concurrency bug in the payment API. On the admin side, I added the refund status display and bulk refund action."
3. Add Context with Diff Stats
Sometimes the team lead or scrum master wants to understand the scope of changes, not just the commit messages. Adding diff stats gives a quantitative view of each commit's impact.
#!/bin/bash
AUTHOR="$(git config user.name)"
DOW=$(date +%u)
[ "$DOW" -eq 1 ] && SINCE="last friday" || SINCE="yesterday"
echo "## Standup Report - $(date '+%A, %B %d')"
echo ""
git log --since="$SINCE" --author="$AUTHOR" --reverse --all \
--format="%n### %s%n%nBranch: %D | %ar" --stat 2>/dev/null | \
sed 's/^ / /'
Output:
## Standup Report - Tuesday, April 22
### Add idempotency key support for charge requests
Branch: feature/idempotency | 18 hours ago
src/handlers/charge.go | 45 ++++++++++++--
src/middleware/idempotent.go | 82 +++++++++++++++++++++++++
src/store/idempotency.go | 63 +++++++++++++++++++
3 files changed, 186 insertions(+), 4 deletions(-)
### Fix race condition in concurrent refund processing
Branch: fix/refund-race | 16 hours ago
src/handlers/refund.go | 12 ++++++----
src/handlers/refund_test.go | 38 ++++++++++++++++++++
2 files changed, 46 insertions(+), 4 deletions(-)
This level of detail is more than most standups need, but it is valuable for sprint reviews, handoffs, and situations where someone needs to understand the actual scope of your changes.
4. Auto-Post to Slack with a Webhook
For async standup workflows, the report should post itself to your team's Slack channel before the standup window opens. This script generates the report and sends it via a Slack incoming webhook.
#!/bin/bash
# slack-standup: auto-post standup report to Slack
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
AUTHOR="$(git config user.name)"
DOW=$(date +%u)
[ "$DOW" -eq 1 ] && SINCE="last friday" || SINCE="yesterday"
# Build the "yesterday" section
yesterday=""
for repo in ~/projects/*/; do
[ -d "$repo/.git" ] || continue
commits=$(git -C "$repo" log --since="$SINCE" --author="$AUTHOR" \
--format="- %s" --reverse --all 2>/dev/null)
if [ -n "$commits" ]; then
project=$(basename "$repo")
yesterday+="*${project}:*\n${commits}\n\n"
fi
done
[ -z "$yesterday" ] && yesterday="(no commits)\n"
# Assemble the message
message="*Standup - $(date '+%A %b %d')*\n\n"
message+="*Yesterday:*\n${yesterday}"
message+="*Today:*\n- (update manually)\n\n"
message+="*Blockers:*\n- None"
# Post to Slack
curl -s -X POST "$WEBHOOK_URL" \
-H 'Content-type: application/json' \
-d "{\"text\": \"${message}\"}" > /dev/null
5. Schedule with Cron for True Automation
Add the script to your crontab so the report generates and posts without any manual trigger.
# Run standup report at 8:50 AM on weekdays (Mon-Fri)
50 8 * * 1-5 /usr/local/bin/slack-standup.sh
This posts to Slack ten minutes before a typical 9 AM standup. You review the auto-generated "yesterday" section, fill in the "today" plan, and update blockers if needed. The cognitive load drops from "reconstruct my entire previous day" to "review an accurate summary and add a plan."
6. Fill the Gaps with IDE Activity Tracking
Git history captures commits. It does not capture the three-hour debugging session that ended with a one-line fix, the two pull requests you reviewed, the architecture meeting that changed the direction of a feature, or the pairing session where your teammate drove and committed from their machine.
For developers whose non-commit work represents a significant portion of the day, an IDE plugin like CodeClocker provides the missing layer. It tracks active development sessions, links them to the projects and branches being worked on, and records the actual time spent coding. The daily digest it produces includes both the commits and the coding hours behind them. Combined with the git history, this gives a standup report that reflects the full picture: what was delivered, how long it took, and which projects consumed the day.
Example
Here is the end-to-end workflow for a developer named Alex on a Wednesday morning.
8:50 AM: The cron job runs. It scans three repos and finds commits in two of them.
Auto-generated Slack post:
*Standup - Wednesday Apr 23*
*Yesterday:*
*search-service:*
- Implement fuzzy matching for product name search
- Add search result ranking by relevance score
- Fix encoding issue in Unicode search queries
- Write performance benchmarks for search index
*deployment-config:*
- Update search-service Helm chart for new environment variables
*Today:*
- (update manually)
*Blockers:*
- None
8:55 AM: Alex opens Slack, reviews the auto-generated post, and edits it:
*Standup - Wednesday Apr 23*
*Yesterday:*
*search-service:*
- Implement fuzzy matching for product name search
- Add search result ranking by relevance score
- Fix encoding issue in Unicode search queries
- Write performance benchmarks for search index
*deployment-config:*
- Update search-service Helm chart for new environment variables
Also reviewed PR #289 (catalog import refactor) and paired with
Priya on her first Elasticsearch integration for ~1 hour.
*Today:*
- Search pagination and infinite scroll implementation
- Deploy search-service to staging
*Blockers:*
- Waiting on DevOps to provision the staging Elasticsearch cluster
(asked in #infra yesterday, no response yet)
What the automation handled: Five commits across two repos, correctly grouped by project, in chronological order. This took zero recall effort.
What Alex added manually: The PR review, the pairing session, the plan for today, and the blocker. These took about 60 seconds to type because the hard part (remembering the coding work) was already done.
What an IDE tracker would have added: "4.8 hours active coding yesterday (search-service: 3.6h, deployment-config: 0.3h, catalog-service: 0.9h during pairing)." This confirms the work and makes the pairing session visible without Alex having to remember it.
Common Mistakes
1. Not using --all to include feature branches. By default, git log only shows commits reachable from HEAD. If you switched branches mid-day or your feature branch has not been merged, those commits will not appear. Always include --all in standup queries, or explicitly name the branches you worked on.
2. Treating the auto-generated report as the complete report. The script handles the "what I did" section for coding work. It cannot generate your plan for today or identify your blockers. Those require human input. The goal is to eliminate the memory-dependent part, not the thinking part.
3. Running the script against stale local clones. If your cron job runs against local repos that have not been fetched recently, it might miss commits you pushed from another machine. Add git -C "$repo" fetch --quiet before the log query if you work from multiple devices.
4. Posting raw commit messages to a non-technical channel. If your standup channel includes product managers, designers, or executives, raw commit messages like "fix: handle nil pointer in OrderService.validateTransition" will confuse rather than inform. For mixed audiences, summarize clusters of related commits into plain-language descriptions: "Fixed a crash in the order processing flow."
5. Ignoring the weekend gap on Mondays. This is the most common bug in standup scripts. --since="yesterday" on Monday means Sunday, which returns nothing for most developers. Always check the day of the week and use --since="last friday" on Mondays. The scripts in this article handle this automatically.
FAQ
Can I use this with GitHub Actions instead of cron?
Yes. Create a scheduled workflow that checks out your repos, runs the git log query, and posts to Slack via the GitHub Actions Slack integration. This avoids needing a personal machine running at 8:50 AM and works well for teams that already use GitHub Actions for CI/CD. The trade-off is that you need to grant the workflow access to all repos you want included.
How do I handle monorepos where I only work in certain directories?
Add a path filter to the git log command: git log --since="yesterday" --author="$AUTHOR" -- services/search/ libs/common/. This scopes commits to only the directories you care about. You can map directories to project names in your script for cleaner output.
What if my team uses conventional commits?
Conventional commit prefixes (feat:, fix:, chore:, refactor:) make auto-generated reports better because the message type is machine-readable. You can group by prefix in your script: features at the top, fixes next, then chores. This produces a structured report that reads almost like release notes.
Does this work for remote teams across timezones?
Yes, but adjust the --since window to match your standup schedule rather than literal "yesterday." If your team's async standup window opens at 9 AM UTC and you are in UTC+5, your "yesterday" might need to be --since="18 hours ago" to capture a full day's work aligned with the team's cadence.
Can I generate a standup report for the whole team?
Remove the --author filter and group the output by author name using --format="%an|%s". This produces a team-wide summary. For teams of five or more, consider using a tool that formats and delivers individual reports automatically rather than maintaining a complex shell script.
Final Recommendation
Start with the single-repo script today and run it manually before tomorrow's standup. If it saves you the usual 60 seconds of "what did I do yesterday" head-scratching, expand to the multi-repo version and add a shell alias. If your team does async standups in Slack, set up the webhook integration and schedule it with cron.
The ceiling for git-only standup reports is the same as for all git-based reporting: commits are a subset of developer activity. Code reviews, debugging without commits, pairing, meetings, and operational work are invisible. For teams where accountability and accurate activity tracking matter, pair the automated git report with an IDE-based tool that captures the full development session. The git script handles the "what," the IDE tracker handles the "how long," and you spend your standup talking about what matters: the plan and the blockers.
Related Reading
- How to Turn Git Commits into a Daily Standup Summary
- How to Create a Weekly Report from Git Commits
- How to Generate a Timesheet from Git Commits
- Automating Developer Timesheets: Why Manual Time Entry Fails
Auto-generate standup reports from your actual development activity
CodeClocker tracks your coding sessions in real-time, links them to commits and branches, and produces daily digests you can share at standup or post to Slack automatically.
Start Free Trial