Triar PRs
Objetivo
Transformar um backlog de PRs abertos em um conjunto de mesclagens enviadas em uma única sessão focada. Produzir um plano rastreável e retomável (<VERSÃO>_PR_TRIAGE.md) e, em seguida, executá-lo — fazendo rebase quando necessário, mesclando em lotes seguros e isolados, aplicando follow-ups pós-mesclagem e fechando PRs substituídos ou parcialmente aplicáveis com crédito aos seus autores.
Esta habilidade se complementa com draft-release-notes e release-bump: trie primeiro, depois escreva as notas de lançamento contra o novo main, e então faça o corte do lançamento.
Quando usar
- Antes de um lançamento menor ou maior, quando 10+ PRs abertos se acumularam.
- Quando você quer desbloquear a mesclagem sem perder a narrativa do que está sendo integrado.
- Quando você sabe que não pode revisar profundamente todos os PRs, mas precisa integrar o subconjunto crítico rapidamente.
Pré-requisitos
- CLI
ghautenticada no repositório. - Uma árvore de trabalho dedicada para revisão de PR (evitar contaminar o
maincom checkouts de branches de contribuidores). - Clareza sobre a versão alvo — o documento de triagem é nomeado a partir dela (ex.:
0.4.0_PR_TRIAGE.md).
Fluxo de trabalho
1. Configurar uma árvore de trabalho isolada para revisão de PR
git worktree list # verifique se há alguma antiga primeiro
git worktree prune
git worktree add ../voicebox-pr-review -b pr-review-<VERSÃO> main
Mantenha a árvore de trabalho principal para trabalho de preparação de lançamento (rascunhos de changelog, follow-ups diretos no main). Mantenha a árvore de trabalho de revisão para gh pr checkout — cada checkout move o HEAD para um branch de contribuidor, o que você não quer fazer na árvore de trabalho principal.
2. Coletar metadados de cada PR aberto
gh pr list --state open --limit 50 --json \
number,title,author,isDraft,mergeable,mergeStateStatus,files,additions,deletions,reviewDecision,statusCheckRollup,maintainerCanModify \
--jq '.[] | {num: .number, title, author: .author.login, mergeable, state: .mergeStateStatus, canModify: .maintainerCanModify, changes: "+\(.additions)/-\(.deletions)", files: [.files[].path]}'
Você deseja, para cada PR:
- Tamanho (
+adições/-deleções) - Estado de mesclagem (
CLEAN,UNSTABLE,DIRTY= conflitos,UNKNOWN= GitHub ainda computando) - Se edições de mantenedor são permitidas no branch (necessário depois se você fizer rebase para o autor)
- Caminhos de arquivos tocados (ajuda a identificar sobreposições entre PRs)
UNKNOWN é comum logo após um push para o main — apenas tente a mesclagem e veja.
3. Classificar em camadas
Classifique cada PR exatamente em um balde:
Camada 1 — Mesclar: pequenos, mescláveis, corrigem um bug real, CI limpo, baixo custo de revisão. Correções de uma linha, relaxamentos de dependência, endurecimento de segurança direcionado. Esses são os ganhos fáceis.
Camada 2 — Candidato, revisar: tamanho médio (50-200 linhas), toca mais área de superfície, parece sólido, mas precisa de uma leitura mais atenta. Novas funcionalidades voltadas para o usuário que se encaixam na direção do produto.
Substituir: a correção ou funcionalidade já está coberta por algo mesclado. Feche com um comentário apontando para o PR substituto. Verifique cuidadosamente — "título semelhante" não é prova; compare os diffs reais.
Adiar para o próximo lançamento: grandes funcionalidades, conflitos sujos, PRs em rascunho, qualquer coisa que toque no pipeline de lançamento de forma que introduza risco. Não mescle isso em uma speedrun — eles precisam de foco dedicado.
4. Escrever o documento de triagem
Crie <VERSÃO>_PR_TRIAGE.md na raiz da árvore de trabalho de revisão de PR. Estrutura:
# <Repo> <VERSÃO> — Triagem de PR
Documento de trabalho para rastrear quais PRs abertos serão integrados em <VERSÃO>. Apagar após o corte do lançamento.
Última atualização: <DATA>
## Progresso
**Camada 1: 0 / N mesclados**
**Camada 2: 0 / M tratados**
**Triagem de substituição: pendente**
---
## Mesclar para <VERSÃO> — correções críticas de bugs
| PR | Status | Tamanho | O que corrige | Por que é essencial |
|---|---|---|---|---|
| [#123](url) | [ ] | +5/-0 | ... | ... |
## Candidato forte — precisa de uma revisão rápida
| PR | Status | Tamanho | Resumo |
|---|---|---|---|
## Fechar como substituído
| PR | Status | Motivo |
|---|---|---|
## Adiar para <PRÓXIMA_VERSÃO>
- [#xxx](url) ... — motivo
---
## Ordem de ataque
1. Fechar PRs substituídos (comentários de uma linha)
2. Mesclar camada 1 em lotes livres de dependências — verifique se os caminhos de arquivo não se sobrepõem
3. Revisar camada 2 individualmente
4. Reexecutar `draft-release-notes` para capturar tudo
5. Executar `release-bump`
O cabeçalho Progresso é a parte mais importante — é seu placar e permite que você retome de forma limpa se a sessão for interrompida.
5. Executar o loop — por PR
Para cada PR na lista da camada 1 / camada 2:
a. Fazer checkout na árvore de trabalho de revisão:
cd ../voicebox-pr-review
git checkout pr-review-<VERSÃO> # resetar para base neutra
gh pr checkout <N>
b. Ler o commit real, não main..HEAD:
git show HEAD # as alterações reais do PR
git show --stat HEAD # arquivos tocados + contagem de linhas
NÃO revise via git diff main..HEAD se o branch do PR for mais antigo que o main. Esse diff inclui todos os commits que foram para o main após o fork do PR como linhas - (deleção). Um PR de 3 linhas pode parecer uma reversão de 700 linhas. Esta é a maneira mais fácil de julgar mal um PR.
c. Avaliar preocupações: correção, escopo, interação com trabalho já mesclado, compatibilidade de versão (ex.: não se pode usar uma API que requer uma versão de dependência que ainda não fixamos).
d. Fazer rebase se o branch estiver atrás do main:
git fetch origin main
git rebase origin/main
Isso é essencial antes de fazer squash-merge. O squash do GitHub computa diff(cabeça-do-PR, base-de-mesclagem) — em um branch desatualizado, esse diff inclui reverter todos os commits intermediários. O rebase move a base-de-mesclagem para frente, para que o squash fique limpo.
e. Se edições de mantenedor forem permitidas, enviar o rebase de volta para o fork do contribuidor:
git remote add <autor> https://github.com/<autor>/<repo>.git
git fetch <autor> <branch> # obter a ref primeiro
git push <autor> HEAD:<branch> --force-with-lease
Isso mantém a UI de PR do GitHub sincronizada com o estado rebasado e torna a mesclagem limpa do lado do GitHub.
f. Mesclar:
gh pr merge <N> --squash
g. Atualizar o documento de triagem — marque a caixa de seleção como ✅ merged <sha> (use o SHA curto de gh pr view <N> --json mergeCommit --jq '.mergeCommit.oid[0:7]'). Atualize o cabeçalho de Progresso.
6. Agrupar pequenas correções
PRs com ≤5 linhas de alteração, CI limpo, caminhos de arquivo não sobrepostos e intenção obviamente correta (ex.: relaxamento de dependência de uma linha, adição de variável de ambiente, correção de caminho de importação) podem ser mesclados em um único loop sem a cerimônia de revisão por PR:
for pr in 425 384 416 429; do
echo "=== Mesclando PR $pr ==="
gh pr merge $pr --squash
done
Verifique depois se cada um foi integrado corretamente:
for pr in 425 384 416 429; do
gh pr view $pr --json state,mergeCommit --jq "{pr: $pr, state, sha: .mergeCommit.oid[0:7]}"
done
7. Follow-ups pós-mesclagem
Às vezes, vale a pena mesclar um PR apesar de um problema menor conhecido (ex.: mapa de tipos incompleto, limpeza de sentinela desatualizada). Não bloqueie a mesclagem; aplique o follow-up como um branch normal + PR logo em seguida:
cd <árvore-de-trabalho-principal>
git pull --ff-only origin main
git checkout -b fix/<nome-curto>
# editar...
git commit -m "fix(<área>): <linha única>"
git push -u origin fix/<nome-curto>
gh pr create --title "..." --body "Follow-up de #<N>. ..."
Registre ambos os SHAs no documento de triagem (✅ merged <sha-do-pr> + follow-up <pr>).
Exceção de direto-ao-main: apenas sob uma política explícita e com escopo definido (ex.: "speedrun de lançamento"). Não use como padrão.
8. Substituir: fechar com um comentário creditando
gh pr close <N> --comment "Fechando — substituído por #<M> mesclado, que integrou <breve descrição>. Obrigado!"
Verifique os diffs primeiro — "título semelhante" não é suficiente. Se o PR estiver parcialmente substituído (o diagnóstico está certo, mas apenas metade das alterações ainda são necessárias), faça uma aplicação parcial.
9. Padrão de aplicação parcial
Quando um PR tem alterações valiosas e questionáveis agrupadas:
cd <árvore-de-trabalho-principal>
git pull --ff-only origin main
# Cherry-pick de arquivos específicos do branch do PR
git checkout <sha-do-commit-do-pr> -- <arquivo1> <arquivo2>
# Revisar as alterações em stage, ajustar conforme necessário
git diff --cached
# Aplicar edições cirúrgicas em arquivos que você não quer substituir em massa
# (ex.: o arquivo do PR é anterior a um commit recente no main que você precisa preservar)
# Commitar com um trailer creditando o autor original
git commit -m "$(cat <<'EOF'
<assunto>
<corpo explicando o que foi mantido vs. descartado>
Co-Authored-By: <autor> <[email protected]>
EOF
)"
git push ... # branch + PR, a menos que sob a exceção de direto-ao-main
Em seguida, feche o PR com um comentário explicando o que foi aplicado e o que foi descartado, referenciando o SHA do commit.
10. Manter o documento atualizado
Cada mesclagem, cada fechamento, cada follow-up → atualize <VERSÃO>_PR_TRIAGE.md. O documento é seu registro da sessão. Se você for interrompido e retomar amanhã, o documento é a única fonte da verdade para "onde estou."
11. Quando a triagem estiver concluída
- Cada PR no documento tem um status final (✅ merged / ✅ closed / deferred)
- Cabeçalho de Progresso mostra N/N para cada camada
- A próxima habilidade a executar é
draft-release-notes(para regenerar[Unreleased]contra o novo main), depoisrelease-bump
Você pode deletar o documento de triagem após o lançamento ser enviado, ou mantê-lo no histórico de versões como um registro.
Armadilhas
main..HEADem um branch desatualizado mente. Ele mostra tudo que o main ganhou desde a divisão do branch como deleções. Sempre revise viagit show HEADpara o commit real do PR.- Fazer squash-merge em um branch sem rebase reverte trabalho intermediário. O squash computa
diff(cabeça-do-PR, base-de-mesclagem). O rebase move a base-de-mesclagem para frente. mergeable=UNKNOWNé transitório — o GitHub está recomputando após um push. Apenas tente a mesclagem.- A ordem das rotas importa (FastAPI e similares):
DELETE /history/faileddeve ser registrado antes deDELETE /history/{id}, ou o caminho parametrizado consumirá"failed"como um ID. -weak_frameworkdo Apple substitui-frameworkpara o mesmo framework, independentemente da ordem — use viacargo:rustc-link-arg=-Wl,-weak_framework,Namequando uma dependência faz link rígido de algo opcional.- Pisos de versão de dependência restringem o que você pode aplicar. Antes de aceitar uma renomeação de argumento como
torch_dtype=→dtype=, verifique se o pino de versão mínima suporta. Às vezes, a ação correta é cherry-pick da metade do PR. - Tipos de áudio
!Sendcomocpal::Streamnão podem cruzar pontos deawaitouspawn_blocking. Às vezes, uma espera síncrona "não ideal, mas correta" é a melhor correção disponível; sinalize, mas não bloqueie. - Builds noturnas do PyTorch não são enviáveis para lançamentos — não determinísticas, podem regredir entre execuções. Se um PR sugerir mudar para a noturna para corrigir um problema de GPU, prefira
TORCH_CUDA_ARCH_LIST=...+PTXou aguarde suporte estável.
Referência de comandos canônicos
# Metadados em massa de PRs
gh pr list --state open --limit 50 --json number,title,author,mergeable,mergeStateStatus,additions,deletions,maintainerCanModify,files
# Visualização detalhada de um único PR
gh pr view <N> --json body,author,headRefName,baseRefName,mergeable,maintainerCanModify,files,statusCheckRollup
# O commit real, não o diff branch-vs-main
git show HEAD
git show --stat HEAD
gh pr diff <N>
# Rebase do branch do contribuidor no main atual
git fetch origin main && git rebase origin/main
# Enviar rebase de volta para o fork do contribuidor (maintainerCanModify=true necessário)
git remote add <autor> https://github.com/<autor>/<repo>.git
git fetch <autor> <branch>
git push <autor> HEAD:<branch> --force-with-lease
# Mesclar
gh pr merge <N> --squash
# Confirmar SHA da mesclagem para o documento de triagem
gh pr view <N> --json state,mergeCommit --jq '{state, sha: .mergeCommit.oid[0:7]}'
# Fechar substituído
gh pr close <N> --comment "Fechando — substituído por #<M> mesclado. Obrigado!"
Notas
- Nunca revise um branch desatualizado via
main..HEAD. Esta é a linha mais importante desta habilidade. - O documento de triagem é o estado da sessão. Perdeu o documento, perdeu a sessão. Atualize-o após cada ação.
- Credite os contribuidores mesmo em aplicações parciais. Use trailers
Co-Authored-By:e comentários de fechamento que linkem para o commit aplicado. - Não deixe o perfeito ser inimigo do entregue. Uma correção que vai de "quebrado" para "funciona com um pequeno problema conhecido" é uma melhoria estrita. Sinalize o problema, abra um follow-up, mescle a correção.