Como Automatizei Meus Stand-ups Diários com Um Script que Lê Git Logs (E Economizo 25 Minutos Por Reunião)
Todo dia de manhã, mesma cena: 9h03, a call do stand-up abre. Alguém compartilha a tela do Jira. Quatro pessoas falam por 2 minutos cada. A quinta pessoa fala por 12 minutos sobre um bug que ninguém entendeu. Vinte e sete minutos depois, você volta pro código com a sensação de que poderia ter lido um email.
E se eu te dissesse que eu substituí essa reunião por um script de 80 linhas em Bash que lê meu Git log, organiza por projeto e gera um relatório formatado — pronto pra colar no Slack ou no email do time? Hoje eu vou te mostrar como automatizei meus stand-ups diários e economizo em média 25 minutos por reunião.

O Problema: Stand-ups Que Devoram Tempo
Vamos ser sinceros: a maioria dos stand-ups diários é um desperdício coletivo. A intenção é boa — alinhar o time, identificar bloqueios, criar accountability. Mas na prática, viram um ritual onde cada pessoa tenta lembrar o que fez ontem enquanto os outros fingem prestar atenção.
Eu trabalhava num time distribuído com 7 devs. Nosso stand-up levava em média 32 minutos. Três vezes por semana. Isso dá 1h36 por semana em stand-ups. Por ano? Mais de 80 horas só em atualizações de status.
O pior: eu percebi que eu passava os primeiros 5 minutos de cada stand-up tentando lembrar o que eu tinha feito. Literalmente abrindo o Git log no terminal enquanto a pessoa anterior falava. Se eu já estava consultando o Git, por que não automatizar isso?
A Ideia: Git Log Como Fonte de Verdade
O insight foi simples: seus commits já contam a história do que você fez. Cada mensagem de commit é um registro de atividade. O Git já armazena tudo — timestamps, arquivos modificados, mensagens descritivas. Só faltava alguém pra conectar os pontos.
Então eu construí um pipeline de três etapas:
- Coleta: um script que extrai commits do último período útil (ontem ou desde o último stand-up)
- Classificação: agrupa os commits por projeto/repo e categoriza (feature, fix, refactor, docs)
- Formatação: gera um relatório em Markdown pronto pra colar no Slack, Teams ou email
E o bônus que eu não esperava: o script me ajudou a perceber quando eu estava fazendo commits genéricos do tipo “fix bug” ou “update”. Me forçou a escrever mensagens melhores.
Conventional Commits: O Pré-Requisito Que Muda Tudo
Antes do script funcionar direito, eu precisei adotar um sistema que já usava pra produtividade: Conventional Commits. Se você não conhece, é um padrão de mensagens de commit que começa com um prefixo:
feat: adiciona validação de CPF no formulário de cadastro
fix: corrige race condition no pool de conexões
refactor: extrai lógica de parsing para módulo separado
docs: atualiza README com instruções de deploy
chore: atualiza dependências do projeto
test: adiciona testes de integração para API de pagamentos
Com esse padrão, o script consegue classificar automaticamente o tipo de trabalho. E a beleza é que, se você já usa ferramentas de automação, provavelmente já tem um hook de commit que valida isso.
O Script: standup-report.sh
Vamos ao que interessa. Aqui está o script completo, com comentários linha a linha:
#!/usr/bin/env bash
# standup-report.sh — Gera relatório de stand-up a partir do Git log
# Uso: ./standup-report.sh [repo_path] [horas_atras]
REPO_PATH="${1:-.}"
HOURS_AGO="${2:-24}"
OUTPUT_FORMAT="${3:-markdown}" # markdown, slack, plain
# Cores para terminal
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
cd "$REPO_PATH" || { echo "Repositório não encontrado: $REPO_PATH"; exit 1; }
# Verifica se é um repositório Git
if [ ! -d ".git" ]; then
echo "Não é um repositório Git: $REPO_PATH"
exit 1
fi
SINCE=$(date -d "$HOURS_AGO hours ago" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || \
date -v-${HOURS_AGO}H '+%Y-%m-%d %H:%M:%S')
REPO_NAME=$(basename "$(git rev-parse --show-toplevel 2>/dev/null || echo 'unknown')")
echo "========================================="
echo "📋 STAND-UP REPORT — $REPO_NAME"
echo "📅 Período: desde $SINCE"
echo "========================================="
echo ""
# Extrai commits do período
COMMITS=$(git log --author="$(git config user.name)" \
--since="$SINCE" \
--pretty=format:'%h|%s|%ai' \
--no-merges 2>/dev/null)
if [ -z "$COMMITS" ]; then
echo "nenhum commit encontrado desde $SINCE."
echo ""
echo "💡 Dica: use 'standup-report.sh . 48' para os últimos 2 dias"
exit 0
fi
# Classificação por tipo (Conventional Commits)
declare -A CATEGORIES
declare -A CATEGORY_EMOJI
CATEGORY_EMOJI=(
["feat"]="✨"
["fix"]="🐛"
["refactor"]="♻️"
["docs"]="📝"
["test"]="🧪"
["chore"]="🔧"
["style"]="💄"
["perf"]="⚡"
["other"]="📦"
)
TOTAL_COMMITS=0
TOTAL_ADDITIONS=0
TOTAL_DELETIONS=0
while IFS='|' read -r hash msg date; do
TYPE="other"
[[ "$msg" =~ ^([a-z]+)(\(.+\))?: ]] && TYPE="${BASH_REMATCH[1]}"
CATEGORIES["$TYPE"]+="$hash|$msg|$date\n"
((TOTAL_COMMITS++))
# Conta linhas modificadas
STATS=$(git diff-tree --no-commit-id --numstat -r "$hash" 2>/dev/null | \
awk '{ add += $1; del += $2 } END { print add, del }')
read -r adds dels <<< "$STATS"
TOTAL_ADDITIONS=$((TOTAL_ADDITIONS + ${adds:-0}))
TOTAL_DELETIONS=$((TOTAL_DELETIONS + ${dels:-0}))
done <<< "$COMMITS"
# Relatório por categoria
for cat in feat fix refactor test docs chore perf style other; do
if [ -n "${CATEGORIES[$cat]}" ]; then
emoji="${CATEGORY_EMOJI[$cat]:-📦}"
case $cat in
feat) label="Features" ;;
fix) label="Bug Fixes" ;;
refactor) label="Refactors" ;;
test) label="Tests" ;;
docs) label="Documentação" ;;
chore) label="Manutenção" ;;
perf) label="Performance" ;;
style) label="Estilo" ;;
*) label="Outros" ;;
esac
echo -e "${emoji} ${label}:"
echo -e "${CATEGORIES[$cat]}" | while IFS='|' read -r c_hash c_msg c_date; do
[ -z "$c_hash" ] && continue
echo " • $c_msg (${c_hash})"
done
echo ""
fi
done
# Resumo estatístico
echo "========================================="
echo -e "📊 Resumo:"
echo " Commits: $TOTAL_COMMITS"
echo " Linhas adicionadas: +$TOTAL_ADDITIONS"
echo " Linhas removidas: -$TOTAL_DELETIONS"
echo " Arquivos modificados: $(git diff --stat HEAD~$TOTAL_COMMITS..HEAD 2>/dev/null | tail -1 | awk '{print $1}')"
echo "========================================="
O script é deliberadamente simples. Sem dependências externas. Sem Python, sem Node. Só Bash e Git — ferramentas que todo dev já tem instaladas.
Integração com Slack e Teams
Gerar o relatório no terminal é só metade da diversão. A outra metade é enviar automaticamente pro canal do time. Para isso, eu criei um wrapper que formata a saída em blocos do Slack:
#!/usr/bin/env bash
# standup-slack.sh — Envia stand-up report para o Slack via webhook
SLACK_WEBHOOK="${SLACK_STANDUP_WEBHOOK:?Defina SLACK_STANDUP_WEBHOOK no .bashrc}"
REPO_PATH="${1:-.}"
# Gera o report em texto plano
REPORT=$(./standup-report.sh "$REPO_PATH" 24 plain)
# Conta commits por tipo
FEAT_COUNT=$(echo "$REPORT" | grep -c "^feat" || echo 0)
FIX_COUNT=$(echo "$REPORT" | grep -c "^fix" || echo 0)
# Monta payload do Slack
PAYLOAD=$(cat <<EOF
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "☀️ Stand-up Automático — $(date +%d/%m/%Y)"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*O que fiz nas últimas 24h:*\n\`\`\`${REPORT}\`\`\`"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "✨ ${FEAT_COUNT} features · 🐛 ${FIX_COUNT} fixes · Gerado automaticamente"
}
]
}
]
}
EOF
)
curl -s -X POST "$SLACK_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "$PAYLOAD" > /dev/null
echo "✅ Stand-up enviado pro Slack!"

Cronjob: O Stand-up Que Se Escreve Sozinho
Agora a parte que realmente transforma isso em automação: um cronjob que roda antes do horário do stand-up. Meu stand-up era às 9h. O cronjob roda às 8h55:
# crontab -e
# Gera e envia stand-up report às 8:55 de segunda a sexta
55 8 * * 1-5 /home/user/scripts/standup-slack.sh /home/user/projects/api >> /tmp/standup.log 2>&1
Resultado: quando a call do stand-up abre às 9h, meu relatório já está no canal do Slack. Todo mundo lê em 30 segundos. A reunião que levava 32 minutos agora leva 7 — só pra discutir bloqueios reais, que é o que importa.
E se você já automatizou seu time blocking com scripts, pode integrar o stand-up report no seu bloco de manhã. Tudo flui junto.
Multi-Repo: Quando Você Trabalha em Vários Projetos
A maioria dos devs trabalha em mais de um repositório. Eu tinha 3 projetos ativos. A solução foi um wrapper que itera sobre todos os repos:
#!/usr/bin/env bash
# standup-multi.sh — Agrega stand-up de múltiplos repositórios
REPOS=(
"$HOME/projects/api-backend"
"$HOME/projects/web-frontend"
"$HOME/projects/shared-libs"
"$HOME/projects/infra-terraform"
)
FULL_REPORT=""
for repo in "${REPOS[@]}"; do
if [ -d "$repo/.git" ]; then
REPO_REPORT=$(standup-report.sh "$repo" 24 plain)
if [ -n "$REPO_REPORT" ] && [ "$REPO_REPORT" != "nenhum commit encontrado."* ]; then
REPO_NAME=$(basename "$repo")
FULL_REPORT+="\n📁 $REPO_NAME:\n$REPO_REPORT\n"
fi
fi
done
if [ -z "$FULL_REPORT" ]; then
echo "nenhuma atividade nos últimos 24h. Dia tranquilo. 🌴"
else
echo -e "$FULL_REPORT"
fi
Esse wrapper vira o comando principal. Ele varre todos os diretórios de projeto, coleta commits de cada um e monta um relatório unificado. Quando eu chego de manhã e digito standup-multi.sh, recebo um panorama completo de tudo que fiz em todos os projetos.
O Que Aprendi Sobre Meus Hábitos de Código
Depois de 3 meses usando o script, os dados revelaram padrões que eu não enxergava:
- Terça é meu dia de fix: 40% dos meus commits de segunda são “feat”, mas terça sempre tem pico de “fix”. Clássico: código novo na segunda, bugs na terça.
- Eu subestimo refactoring: achava que refatorava bastante. Os dados mostravam que apenas 8% dos meus commits eram refactor. Agora é um KPI pessoal — tento manter acima de 15%.
- Sexta à tarde é zona morta: depois das 15h de sexta, meus commits são quase todos “chore” e “docs”. Aceitei isso e parei de lutar contra.
- Commits grandes = problemas: quando um commit toca mais de 15 arquivos, quase sempre introduz bug no dia seguinte. Agora eu splito proativamente.
🧗 Perrengue do Olivetto:
Uma segunda-feira, o script reportou 47 commits num dia. Quarenta e sete. Eu achei que tinha sido produtivo. Na verdade, eu tinha feito um rebase maluco que duplicou o histórico. O script estava contando commits que tecnicamente não existiam mais. Moral da história: sempre filtre por
--no-mergese confira oreflogantes de confiar cegamente nos números. Automatizar é ótimo, mas validar a automação é essencial.
Bônus: Hook Pre-Commit Para Mensagens Melhores
Como bônus, o script te força a escrever commits melhores — porque ninguém quer ver “update” num relatório que vai pro Slack do time inteiro. Mas se você quiser garantir isso no nível do Git, um hook commit-msg simples:
# .git/hooks/commit-msg
MSG=$(cat "$1")
PATTERN="^(feat|fix|refactor|docs|test|chore|style|perf)(\(.+\))?: .{10,}"
if ! echo "$MSG" | grep -qE "$PATTERN"; then
echo "❌ Commit message inválida!"
echo ""
echo "Formato: tipo(escopo): descrição (mín 10 chars)"
echo "Tipos: feat, fix, refactor, docs, test, chore, style, perf"
echo ""
echo "Exemplo: feat(auth): adiciona login com 2FA via TOTP"
exit 1
fi
Esse hook recusa commits com mensagens vagas. Se você já usa dashboards de métricas pessoais, pode rastrear a evolução da qualidade dos seus commits ao longo do tempo.
Antes e Depois: Os Números
Depois de implementar o stand-up automatizado no meu time, medimos o impacto real:
- Duração média do stand-up: 32 min → 8 min (-75%)
- Tempo de preparação: 5 min tentando lembrar → 0 min (automático)
- Qualidade das atualizações: vagas e esquecidas → detalhadas com hashes de commit
- Adoção pelo time: 6 de 7 devs adotaram o script em 2 semanas
- Satisfação com stand-ups: de “perda de tempo” pra “momento útil de alinhamento”
A sétima pessoa? Ela prefere escrever manualmente. E tudo bem. A ideia não é forçar — é remover a fricção pra quem quer participar melhor.
Adaptando Pro Seu Contexto
O script que mostrei funciona pra devs que usam Git. Mas a filosofia se aplica a qualquer ferramenta:
- Se usa Jira: a API REST do Jira permite buscar issues atualizadas no período. Substitua o Git log por um
curlno Jira. - Se usa Trello: o mesmo. A API do Trello é amigável e retorna cards movidos entre lists.
- Se usa Linear: a GraphQL API do Linear é perfeita pra isso.
- Se usa Notion: mais complexo, mas as databases do Notion têm API de query por data.
O princípio é universal: sua ferramenta de trabalho já registra o que você faz. Use isso.
Próximos Passos
Se você curtiu a ideia, aqui vai um roadmap pra implementar hoje:
- Adote Conventional Commits — amanhã mesmo. É o pré-requisito pra tudo funcionar.
- Copie o script e adapte pro seu fluxo. Mude as categorias, ajuste as cores.
- Teste manualmente por uma semana antes de automatizar com cron.
- Adicione o webhook do Slack quando estiver confiante no output.
- Compartilhe com o time e veja quem adota naturalmente.
E se você quer ir além, dá pra integrar com IA para gerar resumos mais naturais — passar os commits por um modelo de linguagem que reescreve em português fluido. Mas isso é tema pra outro post.
E você? Qual reunião repetitiva você quer automatizar primeiro? Me conta nos comentários — ou melhor, me manda o script que você criou. A gente publica aqui. 😉
