guia prático · github

Pull Requests e Code Review no GitHub

Do primeiro commit até o merge, com as telas reais da interface atual e um repositório de verdade para acompanhar. Escrito para quem está entrando no mercado e precisa entender como esse processo funciona dentro de uma equipe.

17 de setembro de 2026 · Todas as capturas de tela foram feitas na interface atual do GitHub, a partir do repositório AffonsoPaulo/pr-and-code-review, criado especificamente para servir de exemplo.

Índice

Seção 1Por que Pull Requests e Code Review existem

Imagine a sua primeira semana em uma equipe. Você recebe uma tarefa pequena — um bug no checkout, digamos —, resolve em vinte linhas e quer ver aquilo funcionando em produção. Em um projeto pessoal, bastaria um git push na main. Em praticamente nenhuma equipe profissional é assim: o push direto na branch principal costuma estar bloqueado, e o caminho passa por um Pull Request.

Essa fricção é deliberada. A branch principal normalmente é a que vai para produção, direta ou indiretamente, e uma mudança que entra nela deixa de ser problema de quem escreveu para ser problema de todo mundo. O Pull Request é o ponto de controle antes disso acontecer: ele isola a sua mudança em um diff que dá para ler, dispara os testes automatizados, abre espaço para quem conhece aquela parte do sistema comentar e só libera o merge quando as condições combinadas pela equipe foram satisfeitas.

O efeito colateral mais subestimado é o registro. Daqui a seis meses, alguém vai rodar git blame em uma linha estranha, chegar no commit e, a partir dele, no Pull Request — e encontrar não só o que mudou, mas por que mudou, quem discordou e qual argumento venceu.

Código conta o como. O histórico de PRs é onde fica o porquê.

O caminho que uma tarefa percorre

O fluxo abaixo é o fio condutor deste guia. Cada etapa vai aparecer com a tela correspondente, na ordem em que acontece no dia a dia:

  1. Tarefa / issue
  2. Branch
  3. Commits
  4. Push
  5. Pull Request
  6. CI
  7. Code Review
  8. Ajustes
  9. Merge

Para não falar no abstrato, tudo acontece em um repositório de verdade: AffonsoPaulo/pr-and-code-review. É um módulo minúsculo em JavaScript que calcula o total de um carrinho de compras aplicando cupons de desconto. A tarefa que vamos acompanhar é a issue #1: um cupom inexistente derruba o checkout inteiro. A correção virou o Pull Request #3, e é dele que vêm quase todas as capturas deste artigo (AFFONSO, 2026).

No mercado

Nenhuma empresa usa exatamente o mesmo processo. Numa startup de cinco pessoas, um PR pode sair aberto e mergeado no mesmo dia com uma aprovação. Num banco, o mesmo PR pode precisar de duas aprovações, uma delas de um time específico, mais checagens de segurança e uma janela de deploy. O que não muda é a peça central: alguém propõe, alguém revisa, a máquina verifica, e só então o código entra.

Seção 2Antes do Pull Request: o mínimo de Git

Você não precisa dominar Git para entender Pull Requests, mas precisa de um punhado de conceitos. Esta seção cobre só o necessário para o resto do artigo fazer sentido.

Um repositório é a pasta do projeto junto com todo o seu histórico. Ele existe em dois lugares ao mesmo tempo: o repositório local, no seu computador, e o repositório remoto, hospedado no GitHub. git clone cria o local a partir do remoto, e a partir daí os dois vivem separados até você sincronizá-los de propósito com push e pull.

Um commit é uma fotografia do projeto em um instante, com autor, data, mensagem e um identificador (o SHA, aquele d16452f que aparece na interface). Commits encadeiam-se: cada um aponta para o anterior, e essa corrente é o histórico.

Uma branch é um ponteiro móvel para um commit dessa corrente. É por isso que criar uma branch é instantâneo e barato: não se copia nada, só se anota "a partir daqui, meus commits seguem por este caminho". A main é a branch principal — a versão oficial do projeto. Uma branch de feature é uma linha paralela onde você trabalha sem afetar a main enquanto a mudança não estiver pronta (CHACON; STRAUB, 2014).

Na prática, foram estes comandos que produziram a branch que o PR #3 propõe:

Terminal
# baixa o repositório remoto para a sua máquina (uma vez só)
git clone https://github.com/AffonsoPaulo/pr-and-code-review.git
cd pr-and-code-review

# parte sempre de uma main atualizada, senão você constrói em cima de código velho
git switch main
git pull

# cria a branch de trabalho e já muda para ela
git switch -c fix/1-cupom-invalido

# ... edita src/cupom.js ...

# seleciona o que entra no commit e registra a mudança
git add src/cupom.js
git commit -m "Ignora cupom inexistente ou expirado em vez de quebrar"

# publica a branch no GitHub; -u liga a branch local à remota
git push -u origin fix/1-cupom-invalido

git switch -c é a forma moderna de criar e trocar de branch; git checkout -b faz o mesmo e continua funcionando — você vai ver os dois por aí. O git add existe porque nem tudo que você editou precisa entrar no mesmo commit: ele é a chance de separar o que é a mudança de verdade do arquivo de teste que você sujou sem querer.

Dica

Nomes de branch curtos e previsíveis ajudam mais do que parece. Um padrão comum é tipo/numero-descricao, como fix/1-cupom-invalido ou feat/431-user-avatar: o tipo diz o que é, o número liga à tarefa e a descrição evita que você abra três branches e não lembre qual é qual.

Página de branches do repositório listando a branch padrão main e quatro branches de trabalho, com colunas de status dos checks, quantos commits estão atrás e à frente da main, e o Pull Request associado a cada uma.
A página de branches do repositório. Depois do push, a branch aparece aqui ao lado da main. Observe as colunas Behind e Ahead: quantos commits aquela branch está atrás e à frente da main. fix/1-cupom-invalido está 4 commits à frente e 1 atrás — e a coluna Pull request já liga cada branch ao PR correspondente.

Até aqui nada saiu do seu controle: os commits existem na sua máquina e, depois do push, também numa branch remota que ninguém está usando. O Pull Request é o passo seguinte — o momento em que você pede que esse trabalho seja incorporado à main. Se quiser exercitar esses comandos antes de seguir, o GitHub mantém cursos gratuitos que rodam dentro de repositórios de exercício (GITHUB, 2026m).

Seção 3O que é um Pull Request

Um Pull Request é um pedido formal para que os commits de uma branch sejam incorporados a outra. Ele não é uma operação do Git: é um objeto do GitHub, com número, título, descrição, comentários, revisões e resultado de checks automatizados, construído em volta da comparação entre duas branches (GITHUB, 2026f).

O nome vem de antes do GitHub. No fluxo original do Git, um colaborador publicava sua cópia do repositório e enviava ao mantenedor um pedido para que ele puxasse (pull) aquelas alterações — o comando git request-pull existe até hoje e gera exatamente esse texto (GIT, 2026). O GitHub transformou esse pedido em uma página com discussão, revisão e um botão de merge.

Commit, branch e Pull Request não são a mesma coisa

Conceito O que é Onde vive
Commit Uma mudança registrada no histórico, com mensagem e identificador. Git (local e remoto)
Branch Um ponteiro para o commit mais recente de uma linha de trabalho. Git (local e remoto)
Pull Request Uma proposta de integrar uma branch em outra, com discussão, revisão e checks. Só no GitHub

A consequência prática: apagar um Pull Request não apaga commits, e um PR fechado sem merge deixa os commits existindo na branch dele. Da mesma forma, o PR não "contém" código — ele aponta para duas branches e mostra a diferença entre elas a cada instante.

Branch de origem e branch de destino

Todo PR tem dois lados. A base é a branch de destino, para onde as mudanças vão — quase sempre a main. A compare (ou head) é a branch de origem, onde estão os seus commits. O GitHub calcula a diferença entre as duas e é essa diferença que as pessoas revisam.

Grafo de commits mostrando a branch fix/1-cupom-invalido saindo da main e voltando por um merge main branch de destino (base) fix/1-cupom-invalido branch de origem (compare) commits do seu trabalho merge ponto de partida
A branch de feature sai de um commit da main, recebe commits próprios e volta por um merge. Enquanto ela existe, a main continua andando — e é por isso que o GitHub recalcula o diff o tempo todo, comparando a sua branch com o estado atual da base.

O que acontece dentro do PR

Aberto o Pull Request, quatro coisas passam a acontecer no mesmo lugar. O GitHub mostra a comparação entre as branches, arquivo por arquivo. A automação roda os checks configurados no repositório e devolve o resultado ali. As pessoas convidadas fazem a revisão, comentando linhas específicas ou o PR como um todo. E, quando tudo o que a equipe exige está satisfeito, alguém aciona o merge.

Vale insistir num ponto que confunde quem está começando: o PR acompanha a branch. Todo commit novo que você empurrar para fix/1-cupom-invalido aparece automaticamente no PR #3, sem precisar abrir outro. É isso que torna o ciclo "revisa, ajusta, revisa de novo" possível — e é o assunto da seção 12.

Seção 4Criando um Pull Request na prática

O ponto de partida é uma tarefa. Em times que usam GitHub Issues, ela é uma issue; em times que usam Jira, Linear ou similares, é um ticket, e a issue talvez nem exista. O que importa é que exista um lugar onde está escrito o que precisa ser feito e por quê — no nosso caso, a issue #1, que descreve o TypeError lançado quando alguém digita um cupom inexistente.

Página da issue número 1 do repositório, com título, descrição explicando o erro, exemplo de reprodução em código e a label bug na barra lateral.
A issue que origina a tarefa. Ela descreve o que acontece, como reproduzir e o que era esperado — o mínimo para alguém conseguir trabalhar sem perguntar. Observe a barra lateral: labels, responsáveis e a seção Development, que já mostra o Pull Request vinculado. O selo Closed no topo apareceu sozinho quando o PR #3 foi mergeado, por causa do Closes #1 na descrição.

Com a branch criada e os commits feitos (o passo a passo está na seção 2), o git push publica a branch. É aí que o GitHub percebe que há trabalho novo e sugere o próximo passo (GITHUB, 2026j).

Página inicial do repositório com a faixa amarela indicando que a branch fix/1-cupom-invalido recebeu pushes recentes e o botão verde Compare and pull request.
Página inicial do repositório, logo após o push. A faixa amarela aparece por alguns minutos depois que uma branch recebe commits novos. Observe: o botão Compare & pull request é um atalho — ele leva direto ao formulário já com as branches preenchidas. Se a faixa sumiu, o caminho equivalente é a aba Pull requestsNew pull request.

Escolher base e compare

A primeira decisão da tela de criação é qual branch recebe o quê. A base é o destino, a compare é a origem. Inverter as duas é um erro comum e silencioso: o diff simplesmente aparece vazio ou com as mudanças ao contrário.

Barra de seleção de branches mostrando base main e compare fix/1-cupom-invalido, com a mensagem Able to merge.
Seletor de branches no topo do formulário. Os destaques marcam os dois seletores. Observe a mensagem Able to merge à direita: o GitHub já testou se as duas branches combinam sem conflito. Quando não combinam, essa mesma área avisa que haverá conflito — e o PR ainda pode ser aberto, mas não mergeado.

Título e descrição

O GitHub preenche o título sozinho a partir do nome da branch, e o resultado costuma ser ruim. "Fix/1 cupom invalido" não diz o que mudou nem o que deixou de acontecer. Esse campo é a primeira coisa que aparece na lista de PRs, nas notificações e no histórico depois do merge — vale o esforço de reescrever.

Formulário Open a pull request com o título preenchido automaticamente como Fix/1 cupom invalido e a descrição preenchida com o template do repositório.
Formulário recém-aberto. O título veio do nome da branch e a descrição veio do arquivo .github/pull_request_template.md do repositório. Observe: quando existe um template, o GitHub o carrega automaticamente. Os trechos entre <!-- --> são comentários de Markdown — servem de instrução para quem escreve e não aparecem no PR publicado.
Mesmo formulário com título descritivo, descrição completa em Markdown e a label bug aplicada na barra lateral.
O mesmo formulário, preenchido. Título específico, descrição seguindo o template e a label bug marcada na lateral. Observe a barra lateral: Reviewers, Assignees, Labels e a seção Development, que lembra de usar palavras-chave como Closes #1 para fechar a issue no merge.

Dica

Escrever Closes #1 na descrição cria um vínculo real: a issue aparece ligada ao PR e é fechada automaticamente quando o merge acontece. As palavras-chave aceitas são close, closes, closed, fix, fixes, fixed, resolve, resolves e resolved. O fechamento automático só vale quando o PR aponta para a branch padrão do repositório; para outra base, o link até existe, mas a issue não fecha sozinha (GITHUB, 2026o).

Reviewers e labels

Reviewers são as pessoas de quem você está pedindo revisão, e só é possível marcar quem tem acesso ao repositório: a lista mostra os colaboradores e os times disponíveis. Em uma equipe, esse campo costuma ser preenchido automaticamente pelo arquivo CODEOWNERS ou pela regra interna do time ("quem tocou nesse módulo por último revisa").

Menu Reviewers aberto, com o campo de busca de pessoas e o Copilot listado em Suggestions.
O menu de Reviewers. O campo de busca lista as pessoas e os times com acesso ao repositório — um Pull Request aceita até 15 reviewers. Observe que pedir revisão é um convite, não uma atribuição: quem foi marcado recebe a notificação, mas o PR continua avançando se outra pessoa revisar antes. O Copilot aparece entre as sugestões porque a revisão automática entra pelo mesmo caminho.

Labels não mudam nada tecnicamente — elas servem para filtrar. bug, enhancement, documentation e afins ajudam a responder perguntas como "quantos bugs entraram nesta semana" sem ler PR por PR. Use as que o repositório já tem; inventar labels novas por conta própria costuma atrapalhar mais do que ajudar.

Criar

O botão final tem duas opções, e a diferença entre elas importa: Create pull request abre o PR pronto para revisão e já solicita os code owners; Create draft pull request abre um rascunho, que não pede revisão e não pode ser mergeado enquanto estiver nesse estado.

Menu aberto ao lado do botão Create pull request, com as opções Create pull request e Create draft pull request e suas descrições.
As duas formas de criar o PR. O próprio menu explica a diferença: o rascunho "não solicita revisão dos code owners e não pode ser mergeado". Observe, abaixo, que o formulário já mostra os commits e o diff completo antes da criação — dá para revisar o próprio trabalho sem sair da página.
Pull Request número 3 criado, mostrando título, estado Open, abas Conversation, Commits, Checks e Files changed, a descrição renderizada e a barra lateral com a label bug e a issue vinculada.
O Pull Request #3, recém-criado. A descrição em Markdown virou texto formatado e a issue vinculada aparece em Development, na lateral. Observe a linha abaixo do título: "AffonsoPaulo wants to merge 2 commits into main from fix/1-cupom-invalido" — é a forma como o GitHub resume base e compare.

Erro comum

Abrir o PR e sair para almoçar sem olhar a aba Files changed. Boa parte dos comentários que um reviewer faria — o console.log esquecido, o arquivo de configuração local que entrou junto, a indentação bagunçada — você mesmo encontra lendo o próprio diff antes de pedir revisão.

Seção 5Como escrever um bom Pull Request

Quem revisa chega no seu PR sem contexto nenhum. Não sabe qual bug você estava perseguindo, não acompanhou a conversa no chat, não viu a tela quebrada. A descrição existe para reconstruir esse contexto — e a diferença entre um PR bem escrito e um PR jogado na fila é literalmente a diferença entre receber uma revisão hoje ou daqui a três dias.

Como não fazer

Título
fix bug
Descrição
(vazia)

O reviewer precisa abrir o diff, deduzir qual bug era, adivinhar se aquela mudança de indentação foi proposital e perguntar no chat como testar. Cada uma dessas perguntas é uma ida e volta de horas.

Como fazer

Título
Corrige queda do checkout ao
informar cupom inválido
Descrição
## Contexto
A issue #1 relata que o checkout
inteiro cai quando a pessoa digita
um cupom que não existe...

O título diz o efeito para quem usa o sistema. A descrição explica a causa, lista o que mudou, ensina a testar e admite o que ficou de fora.

O título merece atenção especial porque ele sobrevive ao PR. Com squash and merge, o título vira a mensagem do commit na main; em qualquer estratégia, ele é o que aparece na lista de PRs, no changelog e na busca. "Corrige queda do checkout ao informar cupom inválido" responde sozinho o que mudou. "fix bug" obriga a abrir o diff.

Um template que funciona

Colocar um arquivo .github/pull_request_template.md no repositório faz o GitHub preencher a descrição automaticamente a cada PR novo (GITHUB, 2026k). É o que acontece no repositório de exemplo, e o formulário da seção 4 mostra o resultado:

.github/pull_request_template.md
## Contexto

<!-- Por que essa mudança é necessária? O que estava acontecendo antes? -->

## O que foi alterado

-
-

## Como testar

1.
2.

## Riscos e pontos de atenção

<!-- O que pode quebrar? O que o reviewer deveria olhar com mais cuidado? -->

## Issue relacionada

Closes #

Cada seção resolve um problema concreto de quem revisa. O contexto evita a pergunta "por que estamos mexendo nisso?" e permite avaliar se a solução ataca a causa certa. A lista do que foi alterado dá um mapa do diff — quando alguém abre doze arquivos modificados, saber que dez deles são consequência mecânica de uma renomeação muda completamente o tempo de revisão. O como testar permite verificar de fato, em vez de só ler; e é onde ficam evidentes os casos que você não cobriu.

A seção de riscos é a que mais separa gente experiente de gente iniciante. Escrever "o cupom inválido agora falha em silêncio; quem chama não distingue 'não tinha cupom' de 'cupom recusado'" não enfraquece o PR — pelo contrário, mostra que você pensou no limite da sua própria solução e direciona a atenção do reviewer para onde ela rende mais. Foi exatamente esse parágrafo que gerou o comentário mais útil da revisão do PR #3.

Boa prática

Quando a mudança é visual, screenshots de antes e depois valem mais do que qualquer parágrafo. Quando é de API, um exemplo de requisição e resposta. Quando é de performance, o número antes e o número depois. O objetivo é sempre o mesmo: permitir que a pessoa avalie sem precisar rodar o projeto.

Vale lembrar que a descrição não substitui boas mensagens de commit, e vice-versa. A mensagem de commit explica uma mudança específica; a descrição do PR explica o conjunto. No PR #3, o commit 78c0e07 tem no corpo a justificativa da injeção da data — quem fizer git log daqui a um ano encontra o raciocínio sem precisar abrir o navegador.

Seção 6O que é Code Review

Code Review é a leitura crítica de uma mudança proposta por outra pessoa, antes que ela entre no código principal. A definição é simples; o que costuma estar errado é a expectativa. Quem começa imagina que revisar é caçar bugs, e conclui que não tem competência para revisar o código de alguém mais experiente. Caçar bugs é só uma das coisas que acontecem ali, e nem é a mais frequente.

Na prática, uma revisão responde a várias perguntas ao mesmo tempo. A solução resolve o problema que a tarefa descreve? O código vai ser compreensível daqui a seis meses, por alguém que não participou desta conversa? Existe algum caso de borda não tratado — nulo, lista vazia, timeout, concorrência? Os testes cobrem o comportamento novo ou só o caminho feliz? A mudança segue os padrões que este projeto já adota, mesmo quando eles não são os que você prefere? Há algo aqui com implicação de segurança — dado sensível em log, entrada não validada, permissão que ficou aberta?

Existe ainda um objetivo que não aparece em nenhum checklist e é talvez o mais valioso a longo prazo: espalhar conhecimento. Quando você revisa o módulo de pagamentos, você aprende o módulo de pagamentos. Times que revisam bem não têm aquela pessoa insubstituível que é a única capaz de mexer em determinada parte do sistema — e, quando ela sai de férias, o trabalho continua.

Code Review

Revisar não é aprovar ou reprovar uma pessoa. É avaliar uma proposta de mudança, com a hipótese de que quem escreveu tinha bons motivos e informações que você talvez não tenha. Um comentário que começa com "por que você optou por…" descobre mais coisa do que um que começa com "isso está errado".

O lado humano não é um detalhe. Um PR é trabalho de alguém, muitas vezes de vários dias, exposto publicamente para outras pessoas comentarem. Times onde a revisão é hostil produzem PRs defensivos, gigantes e raros — porque ninguém quer passar por aquilo com frequência. Times onde a revisão é específica, respeitosa e rápida produzem PRs pequenos e constantes, que é exatamente o que se quer.

Uma última distinção que economiza discussão: revisão não é controle de qualidade automatizado. Formatação, lint, tipos e testes são trabalho de máquina, e devem estar no CI (veja a seção 15). Reviewer humano que gasta a atenção apontando ponto e vírgula está fazendo mal o trabalho de duas pessoas: o dele e o do linter.

Seção 7Fazendo um Code Review no GitHub

A página de um Pull Request tem quatro abas principais, e cada uma responde a uma pergunta diferente (repositórios com recursos de segurança ligados podem exibir outras). Conversation traz a descrição, a linha do tempo de eventos e todos os comentários — é por onde se começa, para entender a intenção. Commits mostra os commits da branch, um a um. Checks traz o resultado detalhado da automação. Files changed é o diff, onde a revisão de fato acontece.

Comece pela descrição, não pelo código. Sem saber o que a mudança deveria fazer, você só consegue avaliar estilo. Depois passe à aba Commits se o PR for grande: commits bem separados contam a história na ordem em que o autor pensou, e revisar por etapas é mais fácil do que encarar trezentas linhas de uma vez.

Aba Commits do Pull Request listando quatro commits com mensagem, autor, horário, resultado dos checks e identificador de cada um.
A aba Commits do PR #3. Cada linha traz a mensagem, quem fez, o resultado dos checks naquele commit e o identificador. Observe o terceiro item, "Apply suggestion from @AffonsoPaulo", com a etiqueta Verified: ele foi criado pelo próprio GitHub ao aplicar uma sugestão de revisão, e por isso vem assinado.

Lendo o diff

Aba Files changed mostrando o diff de src/cupom.js com uma linha removida em vermelho e três adicionadas em verde, além da árvore de arquivos à esquerda e do contador zero de um visualizado.
Anatomia de um diff. Linhas com - em fundo avermelhado saíram; linhas com + em fundo esverdeado entraram. As duas colunas de números mostram a numeração antes e depois da mudança. Observe: 0 / 1 viewed e a caixa Viewed ao lado do arquivo. Marcar um arquivo como visto colapsa ele e ajuda a não se perder em PRs com muitos arquivos — se ele mudar depois, o GitHub desmarca sozinho.

O cabeçalho @@ -5,7 +5,9 @@ indica qual pedaço do arquivo está sendo mostrado: a partir da linha 5, sete linhas na versão antiga viraram nove na nova. Entre os blocos alterados o GitHub esconde o código que não mudou; clicar nas setas expande o contexto, o que costuma ser necessário para julgar se uma mudança faz sentido no fluxo em volta dela.

O ícone de engrenagem no topo permite alternar entre Unified (antes e depois intercalados) e Split (lado a lado), além de ignorar diferenças de espaço em branco — opção que salva a revisão de um PR cuja indentação inteira mudou.

Comentando em uma linha

Passar o mouse sobre uma linha do diff revela um botão azul de comentário na margem. Para comentar em várias linhas de uma vez, clique no número da primeira e arraste (ou use Shift + clique) até a última (GITHUB, 2026p).

Linha do diff com o cursor sobre ela, exibindo o botão azul de adicionar comentário na margem esquerda, destacado em vermelho.
O botão aparece só no hover. Ele fica na margem, entre o número da linha e o código. Observe que o comentário fica ancorado nessa linha específica — é isso que diferencia um comentário de revisão de um comentário geral no PR.
Caixa de comentário aberta sobre a linha 11 com um texto escrito e os botões Cancel, Comment e Start a review, este último destacado.
A caixa de comentário e a escolha que importa. Comment publica aquele comentário isolado na hora; Start a review guarda o comentário como pendente e inicia uma revisão. Prefira Start a review quando pretende deixar mais de um comentário: o autor recebe uma notificação com tudo junto, em vez de uma para cada comentário.
Aba Files changed com um comentário marcado como Pending e o botão Submit review indicando três comentários acumulados.
Comentários pendentes. A etiqueta Pending indica que aquele comentário ainda é visível só para você. O contador no botão Submit review mostra quantos estão acumulados. Observe a árvore de arquivos à esquerda, com o número de comentários por arquivo — útil para conferir se você cobriu tudo antes de enviar.

Enquanto a revisão está pendente, dá para editar e apagar os comentários à vontade. Nada disso chega ao autor antes de você clicar em Submit review e escolher o tipo da revisão — que é o assunto da próxima seção.

Threads e resolução

Cada comentário em linha vira uma thread: o autor responde abaixo, vocês conversam ali, e o assunto fica ancorado ao trecho de código que o originou. Quando o ponto está encerrado, alguém clica em Resolve conversation e a thread colapsa, tirando ruído da página sem apagar nada — o botão Show resolved reabre.

Thread de comentário na aba Conversation com a etiqueta Outdated, o comentário original, a resposta do autor citando o commit e o botão Resolve conversation.
Uma thread completa. Comentário, resposta do autor citando o commit que resolveu (78c0e07) e o botão para encerrar. Observe a etiqueta Outdated no cabeçalho: o código daquela linha mudou depois do comentário, então o GitHub avisa que o trecho citado não é mais o atual.

Atenção

Quem resolve a conversa, por convenção, é quem a abriu — ou o autor, depois de responder. Resolver o próprio comentário do reviewer sem responder nem corrigir é uma forma silenciosa de ignorar a revisão, e times percebem isso rápido. Alguns repositórios inclusive exigem todas as conversas resolvidas para liberar o merge (veja a seção 16).

Seção 8Approve, Comment e Request changes

Ao enviar a revisão, o GitHub pede que você escolha entre três opções. Elas não são variações de tom: cada uma tem um efeito diferente no estado do PR (GITHUB, 2026e).

Caixa de diálogo Finish your review com campo de texto e as três opções Comment, Approve e Request changes, as duas últimas desabilitadas com o aviso de que autores não podem aprovar o próprio PR.
A caixa Finish your review. O campo de texto no topo é o resumo da revisão; abaixo, a decisão; embaixo, a lista de comentários pendentes para conferência. Observe que Approve e Request changes estão desabilitados aqui, com a explicação "Pull request authors can't approve their own pull requests". Como este PR foi aberto pela mesma conta que está revisando, só a opção Comment ficou disponível.
Opção O que significa Efeito prático
Comment Feedback sem tomar posição sobre o merge. Não aprova nem bloqueia. Use para dúvidas, sugestões opcionais ou quando você revisou só uma parte.
Approve Na sua avaliação, a mudança está pronta para entrar. Conta como aprovação para as regras do repositório. É o que destrava o merge quando há exigência de revisões.
Request changes Há algo que precisa ser resolvido antes do merge. Bloqueia o merge em repositórios protegidos até que você (ou outra pessoa com acesso) reavalie.

Na prática, a fronteira entre Comment e Request changes é onde os times mais divergem. Um critério que funciona bem: use Request changes quando existe algo que você não aceitaria ver em produção — um bug, um vazamento de dado, uma regressão de comportamento. Para preferências de estilo, refatorações que você faria diferente ou ideias para depois, Comment comunica a mesma coisa sem parar a fila de ninguém.

Há também o Approve com ressalvas, que não é um botão e sim uma prática: aprovar e deixar um comentário dizendo "aprovo; só ajuste o nome daquela variável antes de mergear". Funciona bem em times pequenos e com confiança estabelecida, e mal em times onde ninguém lê o comentário depois da aprovação.

No mercado

As regras variam bastante. Alguns times tratam Request changes como normal e frequente; outros consideram um gesto forte, reservado a problemas sérios, e preferem resolver o resto conversando. Em muitos lugares existe a convenção de prefixar comentários opcionais com nit: (de nitpick) justamente para deixar claro que não bloqueiam. Pergunte qual é o costume do time nas primeiras semanas — é uma pergunta que ninguém acha ruim.

Seção 9Como escrever bons comentários de revisão

Um comentário útil costuma ter três partes: o que você observou, por que isso importa e o que você sugere. Comentários ruins normalmente têm só a primeira — e, muitas vezes, nem isso.

Pouco útil

Isso está errado.

O autor não sabe o que está errado, por que está errado nem o que fazer. A resposta provável é "errado como?", e vocês perderam um dia.

Útil

Esse trecho lança exceção quando user é null — acontece no fluxo de convite, em que o registro existe antes do usuário. Dá para validar antes de acessar user.id?

Observação concreta, cenário em que acontece e um caminho de solução. O autor consegue agir sem responder nada.

Deixar explícito o tipo do comentário economiza mais tempo do que qualquer outra convenção. Quando o autor abre dez comentários e não sabe quais bloqueiam, ele trata todos como bloqueantes — ou, pior, nenhum. Um prefixo curto resolve:

Categoria Exemplo de abertura Bloqueia?
Bug "Isso quebra quando a lista vem vazia: reduce sem valor inicial lança." Sim
Segurança "O token está indo para o log em catch. Dá para logar só o id?" Sim
Testes "O caminho de erro novo não tem teste — dá para cobrir o caso do cupom vencido?" Geralmente
Arquitetura "Essa regra está na camada de rota; o resto do projeto mantém regra no serviço." Depende
Performance "Essa consulta roda dentro do laço; com 500 itens são 500 idas ao banco." Depende
Legibilidade "d é data ou desconto? Um nome inteiro aqui ajudaria." Não
Dúvida "Por que 300ms e não o valor do config? Tem algum motivo que eu não conheço?" Não
Sugestão (nit) "nit: dá para trocar por Object.entries, mas do jeito que está funciona." Não

O comentário mais produtivo da revisão do PR #3 seguiu essa fórmula: apontou que new Date() dentro de estaValido prendia a regra ao relógio da máquina, explicou o cenário concreto em que isso morderia (o cupom BLACK25 vence em 30/11/2026) e propôs uma alternativa específica. O autor implementou sem precisar de uma única mensagem de ida e volta.

O tom também é técnico

"Você não entendeu o requisito" descreve a pessoa; "essa validação aceita datas futuras, e o requisito na issue pede só passadas" descreve o problema — e é o segundo que leva à correção. Perguntar quando você não tem certeza também evita gastar credibilidade à toa; não raro a resposta revela uma restrição real que você desconhecia.

Criticar o código e não a pessoa não é cortesia vazia: é precisão.

Reconhecer o que ficou bom parece supérfluo e não é. Um "boa, não tinha pensado em extrair essa função" custa uma linha, ensina outras pessoas que leem o PR e equilibra uma conversa que, por natureza, é uma lista de problemas.

Erro comum

Transformar a revisão em um pedido de reescrita completa porque você faria diferente. Se a solução do autor funciona, está testada e segue os padrões do projeto, "eu teria feito de outro jeito" não é motivo para bloquear. Guarde esse capital para quando houver um problema de verdade.

Seção 10Sugestões de código

Quando a mudança que você quer propor cabe em poucas linhas, o GitHub permite escrever o código exato em vez de descrevê-lo. É o recurso de suggested changes: dentro de um comentário em linha, um bloco de código marcado como suggestion vira uma proposta aplicável com um clique.

Markdown do comentário
O nome do teste não diz qual é a condição de "fora da validade"...

```suggestion
test('cupom vencido (VOLTASAS10, 28/02/2026) não aplica desconto', () => {
```

O conteúdo do bloco substitui exatamente as linhas comentadas. O botão de sugestão na barra da caixa de comentário já insere o bloco com a linha original preenchida — mais seguro do que digitar à mão, porque a indentação vem correta (GITHUB, 2026p).

Caixa de comentário aberta na linha 30 do arquivo de teste, com a explicação escrita e, abaixo, um bloco marcado como suggestion contendo a linha proposta.
A sugestão sendo escrita. Explicação primeiro, bloco de código depois — a ordem importa, porque é a explicação que diz ao autor se vale aplicar. Observe o botão Add review comment: como já havia uma revisão em andamento, o texto do botão mudou de "Start a review" para adicionar à revisão existente.
Comentário de revisão com um bloco Suggested change mostrando a linha antiga em vermelho e a sugerida em verde, e os botões Add to batch e Commit suggestions.
Como a sugestão aparece para o autor. O GitHub renderiza o bloco como um mini-diff, com a linha atual e a proposta. Observe os dois botões: Commit suggestions aplica agora; Add to batch acumula várias sugestões do PR para aplicar todas em um único commit — útil quando o reviewer deixou seis correções pequenas.
Modal Commit suggestions com o campo de mensagem preenchido automaticamente como Apply suggestion from at AffonsoPaulo e um campo de descrição estendida.
Aplicar gera um commit de verdade. A mensagem padrão credita quem sugeriu, e o commit entra na branch do PR como qualquer outro. Observe que isso significa que o CI roda de novo — aplicar cinco sugestões separadas dispara cinco execuções. Daí a utilidade do Add to batch.

Sugestões funcionam bem para correções pequenas e objetivas: um nome melhor, um typo em texto visível, uma condição invertida, um const no lugar de let. Funcionam mal quando a mudança envolve mais de um arquivo, exige contexto que não cabe em três linhas ou merece discussão — nesses casos, um comentário explicando o raciocínio rende mais do que um bloco de código pronto que o autor aplica sem entender.

Seção 11Recebendo um Code Review

Receber quinze comentários no primeiro PR assusta, e a leitura mais comum — "então meu código é ruim" — quase sempre está errada. Volume de comentários costuma dizer mais sobre o tamanho do diff e sobre a cultura do time do que sobre a qualidade do que você escreveu. Reviewers experientes comentam bastante porque conhecem o histórico do sistema, não porque estão procurando defeito.

O primeiro passo é ler tudo antes de responder qualquer coisa. Comentários isolados parecem exigências; lidos em conjunto, eles se organizam em três grupos: o que é bug ou risco real, o que é sugestão de melhoria e o que é dúvida. Esse é o grupo que define a ordem do seu trabalho.

Para cada comentário, existem basicamente três respostas legítimas. Você concorda e corrige — e aí responda dizendo em qual commit, como no exemplo do PR #3 ("Ajustado em 78c0e07"). Você concorda que é um problema, mas acha que ele não pertence a este PR — e aí explique, abra uma issue e cite o número; foi o que aconteceu com a issue #4. Ou você discorda — e aí apresente o motivo técnico, não a sua preferência.

Dica

Discordar é normal e esperado. O que muda o resultado é a forma: "não vou mudar" encerra a conversa; "considerei extrair isso, mas as duas chamadas têm ciclos de vida diferentes e a abstração ficaria vazando parâmetro — prefiro manter separado, o que você acha?" convida a pessoa a decidir junto. O guia de code review do Google recomenda exatamente essa ordem: buscar consenso com quem revisou antes de escalar, e nunca responder no calor do momento (GOOGLE, 2026a). Se o impasse continuar depois de duas trocas, leve para uma conversa síncrona: comentário de PR é péssimo meio para debate longo.

Quando terminar os ajustes, responda as threads, resolva as que ficaram encerradas e peça nova revisão. Na barra lateral, ao lado do nome de cada reviewer, existe um ícone de recarregar que dispara um novo pedido de revisão (GITHUB, 2026n) — mais eficaz do que esperar que a pessoa perceba sozinha que o PR mudou.

Boa prática

Responda todos os comentários, mesmo os que você só aceitou. Um emoji de joinha não conta: quem revisou precisa saber se você concordou, discordou ou não viu. Threads abertas sem resposta deixam o PR parado sem que ninguém saiba por quê.

Seção 12O que acontece quando chegam novos commits

O Pull Request não é uma fotografia da branch no momento em que foi aberto: ele aponta para a branch e acompanha o que acontece nela. Qualquer commit novo empurrado para fix/1-cupom-invalido aparece no PR #3 automaticamente, atualizando o diff, disparando o CI de novo e avisando quem está participando da conversa.

  1. PR aberto
  2. Comentário do reviewer
  3. Commit local
  4. git push
  5. PR atualizado
  6. CI roda de novo
  7. Nova revisão
Linha do tempo do Pull Request mostrando o evento AffonsoPaulo and others added 2 commits, com os dois commits listados e seus identificadores.
Como os commits novos aparecem na linha do tempo. O GitHub agrupa os pushes em eventos e lista os commits com seus identificadores. Observe o "and others": um dos commits foi criado pelo próprio GitHub ao aplicar a sugestão de código, então a autoria do push tem mais de uma pessoa envolvida.

Isso tem duas consequências práticas. A primeira: os comentários antigos não somem, mas podem receber a etiqueta Outdated quando o trecho citado deixa de existir na versão atual — o GitHub mantém o contexto histórico e sinaliza que ele envelheceu. A segunda: dependendo das regras do repositório, aprovações anteriores podem ser descartadas a cada push novo (a opção dismiss stale reviews, que veremos na seção 16), obrigando uma nova rodada de revisão.

Atenção

Evite git push --force em uma branch que já está em revisão. Reescrever o histórico quebra a âncora dos comentários existentes e faz o reviewer perder o rastro do que já tinha olhado. Se for inevitável — um rebase pedido pelo time, por exemplo — use --force-with-lease e avise no PR.

Seção 13Merge: as três estratégias

Com tudo aprovado e os checks verdes, resta escolher como os commits entram na branch de destino. O botão de merge tem um menu com as três estratégias que o GitHub oferece — e o repositório pode habilitar apenas algumas delas nas configurações.

Menu aberto no botão de merge com as opções Create a merge commit, Squash and merge e Rebase and merge, cada uma com sua descrição.
O menu de estratégias. As descrições do próprio GitHub já resumem o efeito de cada uma sobre os quatro commits deste PR. Observe, acima, a caixa de status: "All checks have passed" e "No conflicts with base branch". Só depois dessas duas condições o botão fica verde.
Comparação do histórico resultante de merge commit, squash and merge e rebase and merge Merge commit preserva os commits da branch e marca o ponto de junção Squash and merge um único commit novo; os originais ficam só na página do PR Rebase and merge os commits são recriados em sequência, sem ponto de junção
Os círculos vazios com o contorno de destaque são os commits da branch de feature; os cinzas, os que já estavam na main. No squash, os originais continuam existindo na página do PR, mas não no histórico da main.

Merge commit

Todos os commits da branch entram na main e um commit extra registra a junção. O histórico fica fiel ao que aconteceu: dá para ver que aqueles cinco commits foram feitos juntos, em uma branch, e integrados de uma vez. O custo é um grafo mais cheio — em um repositório movimentado, o git log vira uma trança difícil de ler.

Squash and merge

Todos os commits da branch viram um só na main. É uma escolha frequente em times de produto, porque o histórico da branch principal passa a ter uma entrada por mudança entregue, e não por passo intermediário — "wip", "ajusta teste", "corrige lint" desaparecem. Foi o que usamos no PR #3: quatro commits viraram e6e9ab2, com o título do PR e o número entre parênteses.

git log da main depois do squash
e6e9ab2 Corrige queda do checkout ao informar cupom inválido (#3)
8d3597a Configura CI, template de Pull Request e CODEOWNERS
519ddb2 Adiciona cálculo de subtotal e aplicação de cupom
cd28284 Cria estrutura inicial do projeto de exemplo

A contrapartida é perder o detalhe. Se um dos commits tinha uma explicação valiosa no corpo da mensagem, ela só continua acessível pela página do PR. Por isso o título e a descrição importam tanto quando o time usa squash: eles são o que sobra.

Rebase and merge

Os commits da branch são reaplicados um a um no topo da main, sem commit de junção. O histórico fica linear e preserva os commits individuais. Duas ressalvas documentadas pelo GitHub: os commits ganham identificadores novos (não são os mesmos objetos da sua branch local) e commits vazios são descartados (GITHUB, 2026d). É a estratégia preferida por times que cuidam do histórico com disciplina e fazem commits pequenos e autocontidos.

Estratégia Histórico Vantagem Desvantagem
Merge commit Ramificado, com ponto de junção Fiel ao que aconteceu; fácil reverter o conjunto Grafo poluído em repositórios movimentados
Squash Linear, um commit por PR Log limpo e legível; git bisect mais direto Perde os passos intermediários
Rebase Linear, todos os commits Detalhe preservado sem commit extra Reescreve identificadores; exige commits bem feitos

Depois do merge, o GitHub oferece Delete branch. Apagar é seguro: os commits já estão na main e a branch pode ser restaurada pela própria página do PR. Deixar branches mergeadas acumulando só torna a lista de branches inútil.

Pull Request com selo Merged, evento informando que o commit e6e9ab2 foi mergeado na main, e a caixa Pull request successfully merged and closed com o botão Delete branch.
PR #3 depois do merge. O selo roxo Merged substitui o Open, e a linha do tempo registra qual commit entrou na main. Observe o botão Revert: ele cria um PR novo desfazendo a mudança — o caminho recomendado quando algo dá errado em produção, porque mantém o histórico íntegro.

Seção 14Merge conflicts

Um conflito acontece quando o Git não consegue decidir sozinho como combinar duas mudanças. O caso clássico é duas branches editando as mesmas linhas do mesmo arquivo; também conta uma branch alterando um arquivo que a outra apagou (GITHUB, 2026b). Não é erro de ninguém: é o resultado normal de duas pessoas trabalharem em paralelo sobre o mesmo código.

No repositório de exemplo, o PR #7 propõe uma solução alternativa para a mesma issue #1 que o PR #3 já resolveu. Como ele saiu de uma main anterior ao merge e reescreveu exatamente as mesmas linhas, o GitHub não consegue integrar:

Caixa de status do Pull Request informando que a branch tem conflitos que precisam ser resolvidos, com o botão Resolve conflicts e o botão de merge desabilitado.
Um PR com conflito. O botão de merge fica desabilitado e o GitHub explica qual arquivo conflita. Observe que o PR continua aberto e revisável — conflito impede o merge, não a discussão.

Quando o conflito é simples, dá para resolver no próprio navegador. O editor mostra o arquivo com os marcadores que o Git insere:

Editor de conflitos do GitHub mostrando o arquivo cupom.js com os marcadores de conflito e os atalhos Accept current change, Accept incoming change e Accept both changes.
O editor de conflitos do GitHub. As duas versões aparecem separadas pelos marcadores, com atalhos para aceitar uma, outra ou as duas. Observe que aceitar um dos lados é só o começo: aqui, ficar com a versão da main significa descartar o CupomInvalidoError, que era o ponto do PR. Resolver conflito é uma decisão de projeto, não uma escolha mecânica.
Os marcadores, em texto
<<<<<<< fix/erro-explicito-cupom (Current change)
  if (cupom === undefined) {
    throw new CupomInvalidoError(codigo);
=======
  if (!cupom || !estaValido(cupom, hoje)) {
    return subtotal;
>>>>>>> main (Incoming change)

Entre <<<<<<< e ======= está a sua versão; entre ======= e >>>>>>>, a da branch de destino. Resolver significa deixar no arquivo o código final desejado e apagar os três marcadores — inclusive quando a resposta certa é uma terceira versão, diferente das duas.

Conflitos que envolvem vários arquivos ou exigem rodar os testes se resolvem melhor na máquina:

Terminal
git switch fix/erro-explicito-cupom
git fetch origin
git merge origin/main        # aqui o Git aponta os conflitos

# edite os arquivos, resolva os marcadores e rode os testes
npm test

git add src/cupom.js
git commit                   # a mensagem de merge já vem preenchida
git push

Boa prática

A melhor forma de lidar com conflitos é encurtar a janela em que eles podem nascer: PRs pequenos, revisados rápido e mergeados no mesmo dia raramente conflitam. Quando um PR precisa viver mais tempo, traga a main para dentro dele com frequência (git merge origin/main ou o botão Update branch na própria página) em vez de descobrir tudo de uma vez no final.

Atenção

Nem todo problema de integração aparece como conflito. No repositório de exemplo, o PR #5 adiciona um console.warn que lê cupom.percentual — o Git mesclou sem reclamar, porque as linhas não colidiam, mas o código resultante volta a quebrar com cupom inexistente. Quem pegou isso foi o CI, não o merge. É exatamente para esse tipo de caso que servem os checks automatizados.

Seção 15Checks, CI/CD e Pull Requests

Uma parte grande do que se verifica em um PR não precisa de gente. Compilar, rodar testes, checar formatação, verificar tipos, procurar dependência vulnerável — tudo isso é trabalho mecânico, repetitivo e que uma máquina faz melhor. É o papel da integração contínua: a cada push, um servidor baixa o código, executa um conjunto de verificações e devolve o resultado para dentro do Pull Request.

No GitHub, a ferramenta nativa para isso é o GitHub Actions. Um arquivo YAML dentro de .github/workflows/ descreve quando rodar e o que rodar (GITHUB, 2026l). O repositório de exemplo tem um workflow pequeno com dois jobs:

.github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  testes:
    name: Testes automatizados
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - name: Rodar a suíte de testes
        run: npm test

  lint:
    name: Análise estática
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - name: Verificar sintaxe dos módulos
        run: |
          for arquivo in $(find src test -name '*.js'); do
            node --check "$arquivo"
          done

O gatilho pull_request faz o workflow rodar a cada push em qualquer branch que tenha um PR aberto. Cada job vira um check no PR, identificado pelo nome definido no YAML — "Testes automatizados" e "Análise estática", no nosso caso.

  1. push
  2. PR atualizado
  3. CI executa
  4. checks reportam
  5. review
  6. aprovação
  7. merge

O resultado aparece na caixa de status, logo acima do botão de merge. Verde quando tudo passou; vermelho com o nome do job que falhou quando algo quebrou.

Caixa de status do Pull Request com All checks have passed, dois checks bem-sucedidos, No conflicts with base branch e o botão verde Merge pull request.
Tudo verde no PR #3. Duas condições precisam estar satisfeitas para o botão de merge ficar disponível: checks passando e ausência de conflito. Observe que os checks aparecem resumidos ("2 successful checks") e a seta à direita expande a lista com o resultado de cada um.
Caixa de status do Pull Request indicando Some checks were not successful, com o job Testes automatizados marcado como falho e o job Análise estática marcado como bem-sucedido.
Um check falhando no PR #5. A mudança daquele PR mesclou sem conflito, mas voltou a quebrar o caso do cupom inexistente — o teste pegou. Observe que os checks estão agrupados por resultado — "1 failing check" e "1 successful check" — e que o nome de cada um é um link para o log completo da execução, onde está a linha exata em que a suíte falhou.
Página de execução do GitHub Actions mostrando os jobs Testes automatizados e Análise estática, com a lista de passos executados e o tempo de cada um.
O detalhe da execução, na aba Actions. Cada passo do job pode ser expandido para mostrar a saída do comando. Observe o passo "Rodar a suíte de testes": é ele que executa o npm test definido no YAML. Quando um teste falha, é aqui que está a mensagem original.

Vale distinguir dois termos que aparecem na documentação. Checks são criados por GitHub Apps e pelo Actions, com log, anotações no diff e capacidade de re-execução. Commit statuses são o mecanismo mais antigo e simples, usado por serviços externos, que apenas marcam um commit como sucesso ou falha. Na interface do PR, os dois aparecem juntos na mesma lista (GITHUB, 2026h).

Por padrão, um check vermelho não impede o merge — ele só informa. Para que passe a impedir, ele precisa ser marcado como obrigatório nas regras do repositório, que é o assunto da próxima seção.

Erro comum

Reexecutar o check até ele passar sem investigar por quê. Teste que falha às vezes ("flaky") é um problema real do projeto, não um contratempo; ignorar é ensinar o time a desconfiar do CI, e um CI em que ninguém confia não protege nada.

Seção 16Branch protection e Rulesets

Nada do que foi descrito até aqui é obrigatório por padrão. Em um repositório recém-criado, qualquer pessoa com acesso de escrita pode dar git push direto na main e pular o processo inteiro.

Proteção de branch é o combinado da equipe transformado em algo que a plataforma cobra.

O GitHub tem hoje dois mecanismos para isso, e os dois continuam funcionando. As branch protection rules são o modelo clássico: uma regra por padrão de branch, visível apenas para quem administra. Os rulesets são o modelo mais novo e mais flexível: podem ser empilhados (várias regras valendo sobre a mesma branch, sempre prevalecendo a mais restritiva), podem ser ligados e desligados sem serem apagados, e são visíveis para qualquer pessoa com acesso ao repositório — o que ajuda quem está começando a entender por que o merge está bloqueado (GITHUB, 2026c), (2026g).

Em Settings → Rules → Rulesets, um ruleset define três coisas: quais branches ele atinge, em que modo está (ativo, desativado ou apenas avaliando) e quais regras aplica.

Tela Settings, seção Rulesets, listando o ruleset Proteção da main com quatro regras de branch.
Onde as regras ficam. Settings → Rules → Rulesets lista os rulesets do repositório, com o resumo de cada um: aqui, quatro regras valendo sobre uma branch. Observe que essa tela é legível por qualquer pessoa com acesso ao repositório — uma das diferenças em relação às branch protection rules clássicas, visíveis só para quem administra.
Tela de configuração de um ruleset chamado Proteção da main, com status Active, alvo Default branch e a lista de regras, entre elas Require a pull request before merging e Require status checks to pass marcadas.
O ruleset do repositório de exemplo. Alvo: a branch padrão. Status: Active. Regras marcadas: exigir Pull Request antes do merge, exigir status checks, impedir exclusão e bloquear force push. Observe a Bypass list, no topo: é onde se define quem pode furar a fila (uma equipe de plantão, um bot de release). Deixá-la vazia significa que a regra vale para todo mundo, inclusive para quem administra o repositório.

As regras que mais aparecem no dia a dia de uma equipe são estas (GITHUB, 2026i):

Regra O que passa a acontecer
Require a pull request before merging Push direto na branch protegida é recusado. Toda mudança passa por um PR.
Required approvals Define o número mínimo de aprovações. Uma costuma bastar; times maiores ou código crítico às vezes exigem duas.
Dismiss stale reviews Cada push novo invalida as aprovações anteriores, forçando nova revisão do que mudou.
Require review from Code Owners Exige aprovação de quem é dono dos arquivos tocados, conforme o CODEOWNERS.
Require conversation resolution Bloqueia o merge enquanto houver thread de revisão não resolvida.
Require status checks to pass Escolhe quais checks são obrigatórios. Falhou, não mergeia.
Require branches to be up to date Obriga a branch a incorporar a base antes do merge, para que o CI teste a combinação real.
Block force pushes Impede reescrita de histórico na branch protegida.

O efeito no PR é imediato e explícito. Depois de ativar o ruleset no repositório de exemplo, o PR #5 passou a mostrar exatamente o que falta:

Caixa de status mostrando checks marcados como Required, o aviso de branch desatualizada com o botão Update branch, a mensagem Merging is blocked porque falta uma aprovação, e o botão de merge desabilitado.
Um merge bloqueado por regra. Três coisas mudaram em relação à mesma tela antes do ruleset. Observe: as etiquetas Required ao lado de cada check; o aviso This branch is out-of-date with the base branch com o botão Update branch, efeito da exigência de branch atualizada; e a mensagem Merging is blocked — At least 1 approving review is required by reviewers with write access. O botão de merge está desabilitado.

No mercado

É por isso que, na empresa, você não vai conseguir "só empurrar rapidinho na main". A proteção é o que garante que todo código em produção passou por revisão e por testes, e é também o que torna auditável responder "quem aprovou esta mudança?" — pergunta rotineira em setores regulados. Quando há uma emergência real, o caminho é a bypass list ou uma exceção registrada, não desligar a regra.

Seção 17CODEOWNERS

Em um repositório com trinta pessoas e duzentos diretórios, ninguém sabe de cabeça quem precisa revisar o quê. O arquivo CODEOWNERS resolve isso: ele associa padrões de arquivo a pessoas ou times, e o GitHub passa a solicitar a revisão automaticamente quando um PR toca esses arquivos.

O arquivo pode ficar em .github/, na raiz do repositório ou em docs/ — o GitHub procura nessa ordem e usa o primeiro que encontrar (GITHUB, 2026a). A sintaxe lembra a do .gitignore, com o dono listado na mesma linha do padrão:

.github/CODEOWNERS
# Dono padrão de tudo que não tiver regra mais específica
*                       @AffonsoPaulo

# Regras de negócio do carrinho
/src/                   @AffonsoPaulo

# Pipeline e configuração de repositório
/.github/               @AffonsoPaulo
Arquivo CODEOWNERS aberto no GitHub, com a faixa verde informando que o arquivo é válido e as onze linhas do conteúdo.
O arquivo aberto no GitHub. A faixa verde no topo — "This CODEOWNERS file is valid" — é a validação automática da sintaxe. Observe: quando há erro de padrão ou um dono sem acesso de escrita, essa mesma faixa aparece em vermelho apontando a linha problemática. Vale conferir depois de editar.

Em um repositório de equipe, as linhas normalmente apontam para times:

*                       @minha-org/plataforma
*.tsx                   @minha-org/front-end
/infra/                 @minha-org/sre
/src/pagamentos/        @minha-org/pagamentos @ana-silva
/docs/                  @minha-org/tech-writers

A regra de precedência é a que mais confunde: a última linha que casa com o arquivo é a que vale. No exemplo acima, um arquivo /src/pagamentos/cartao.tsx não pertence ao time de front-end, apesar da extensão — a linha de pagamentos vem depois e sobrepõe. Por isso a convenção de escrever do mais genérico para o mais específico.

Três detalhes que economizam tempo de depuração. O arquivo precisa existir na branch de destino do PR para valer — adicioná-lo na sua branch de feature não surte efeito naquele mesmo PR. Os donos listados precisam ter acesso de escrita ao repositório; quem não tem é silenciosamente ignorado. E Pull Requests em rascunho não acionam a solicitação automática: ela acontece quando o PR sai de draft.

Sozinho, o CODEOWNERS apenas sugere reviewers. Combinado com a regra Require review from Code Owners da seção 16, ele passa a ser obrigatório — e é essa combinação que garante que ninguém altere o módulo de cobrança sem que o time de cobrança olhe.

Seção 18Draft Pull Requests

Um Draft Pull Request é um PR marcado explicitamente como incompleto. Ele mostra o diff, roda o CI e aceita comentários como qualquer outro, mas não pode ser mergeado e não solicita revisão dos code owners enquanto estiver nesse estado (GITHUB, 2026f).

Caixa de status de um Pull Request em rascunho, com a mensagem This pull request is still a work in progress, Draft pull requests cannot be merged, o botão Ready for review e o botão de merge desabilitado.
A caixa de status de um rascunho. Os checks rodaram e passaram, não há conflito — e mesmo assim o merge está desabilitado, por escolha do autor. Observe o botão Ready for review: é ele que promove o rascunho a PR normal e dispara os pedidos de revisão. O caminho inverso, Convert to draft, fica no canto direito da página.

O uso mais comum é pedir opinião cedo, quando a decisão de arquitetura ainda dá para mudar. Abrir um rascunho com o esqueleto da solução e escrever na descrição "ainda falta X e Y; queria opinião sobre a abordagem antes de continuar" é muito mais barato do que descobrir, com o trabalho pronto, que o caminho era outro. No repositório de exemplo, o PR #6 está assim: a normalização do código do cupom funciona, mas falta o teste e falta decidir se a normalização pertence a essa camada.

O rascunho também serve para abrir o PR logo no começo da tarefa, apenas para que o time veja que aquilo está em andamento e o CI comece a rodar desde cedo — nesse caso ele funciona como um sinal de "estou trabalhando nisto", sem consumir a atenção de ninguém.

Dica

Rascunho não substitui descrição. Um draft sem explicação do que falta e do que você quer que a pessoa olhe recebe o mesmo tratamento de um PR sem descrição: ninguém entra. Diga o que já está pronto, o que falta e qual pergunta você quer responder.

Seção 19PR pequeno vs. PR gigante

Poucas variáveis afetam tanto a qualidade de uma revisão quanto o tamanho do diff. A razão é simples e não tem a ver com preguiça.

Atenção não escala linearmente.

O guia de code review do Google trata isso como número: cem linhas é um tamanho razoável para uma mudança e mil linhas já é grande demais, com a ressalva de que a contagem de arquivos pesa tanto quanto a de linhas — duzentas linhas em um arquivo podem estar de bom tamanho, as mesmas duzentas espalhadas por cinquenta arquivos normalmente não (GOOGLE, 2026b). O motivo que o guia dá é prático: é mais fácil achar cinco minutos várias vezes para revisar mudanças pequenas do que reservar meia hora seguida para uma grande. Quando esse tempo não aparece, o que sai é uma leitura superficial terminada em "LGTM".

PR A — focado

  • 180 linhas alteradas
  • uma responsabilidade: corrigir o cálculo de desconto
  • 3 arquivos, sendo um de teste
  • contexto claro na descrição

Revisável em uma sentada. Se algo quebrar depois do deploy, é óbvio o que reverter.

PR B — tudo junto

  • 4.800 linhas alteradas
  • refatoração + feature nova
  • migração de banco
  • reformatação automática do projeto inteiro
  • atualização de dependências

A mudança de verdade está escondida em meio a milhares de linhas mecânicas. Reverter significa desfazer cinco coisas não relacionadas.

O problema do PR B não é o número em si — é a mistura. Um PR de 2.000 linhas que só renomeia um método em quarenta arquivos é fácil de revisar, porque o padrão se repete. O que mata a revisão é ter cinco tipos de mudança no mesmo diff, obrigando quem lê a trocar de modo mental a cada arquivo e a nunca saber se aquela linha diferente é parte da feature ou efeito colateral da formatação.

A regra prática é "uma responsabilidade por PR". Se a feature exige uma refatoração antes, faça a refatoração em um PR próprio, sem mudança de comportamento, e a feature em outro — é recomendação explícita do mesmo guia, que orienta separar refatoração de mudança de comportamento (GOOGLE, 2026b). Além de revisável, isso deixa o histórico honesto: um commit que só move código e um commit que só muda comportamento contam coisas diferentes para quem investigar um bug daqui a um ano.

Boa prática

Quando um PR grande for inevitável — uma migração, um gerador de código — separe os commits por tipo de mudança e diga isso na descrição: "commits 1 e 2 são reformatação automática, o commit 3 é a mudança de verdade". A aba Commits passa a ser um roteiro de leitura, e quem revisa consegue dedicar a atenção onde ela importa.

Seção 20Como PRs são usados no mercado

Não existe um processo universal. O que existe são configurações diferentes da mesma ideia, ajustadas ao tamanho do time, ao risco do produto e ao setor. Três recortes comuns:

Startup pequena

  1. feature
  2. PR
  3. 1 aprovação
  4. merge

Cinco ou seis pessoas, todas conhecendo o sistema inteiro. A revisão é rápida e informal, muitas vezes acompanhada por uma conversa no chat. A proteção da main costuma exigir só uma aprovação e os testes passando. O risco aceito conscientemente é que decisões grandes passem com pouca discussão; a contrapartida é velocidade.

Empresa maior

  1. ticket
  2. branch
  3. PR
  4. CI
  5. CODEOWNER
  6. 2 aprovações
  7. checks de segurança
  8. merge

O PR nasce de um ticket no Jira ou equivalente, e o número do ticket costuma estar no nome da branch e no título. O CODEOWNERS direciona a revisão para quem mantém cada área. Há mais checks: testes, lint, tipos, cobertura, análise de dependências, às vezes uma verificação de licenças. Também aparecem regras que só fazem sentido em escala, como exigir que a branch esteja atualizada com a main antes do merge — para que o CI teste a combinação que realmente vai para produção.

Projeto open source

  1. fork
  2. branch
  3. PR para o repositório original
  4. revisão do mantenedor
  5. alterações
  6. merge

Quem contribui normalmente não tem acesso de escrita, então o caminho é o fork: uma cópia do repositório na sua conta, onde você cria a branch e trabalha. O PR é aberto do seu fork para o repositório original — a tela de criação chama isso de compare across forks. A revisão tende a ser mais exigente com testes e documentação, porque o mantenedor vai conviver com aquele código sem ter o seu contexto, e o tempo de resposta varia de horas a meses. Ler o CONTRIBUTING.md antes de abrir o PR costuma ser a diferença entre ser revisado e ser ignorado.

No mercado

Em qualquer um dos três cenários, o que se espera de quem está começando é o mesmo: PRs pequenos, descrição honesta, resposta rápida aos comentários e nenhuma surpresa. Ninguém espera que você acerte a arquitetura de primeira; esperam que você facilite a vida de quem vai revisar.

Seção 21Fluxo completo de uma tarefa

Juntando tudo, é assim que uma tarefa atravessa o processo — com os nomes que ela teria em uma empresa e o que está acontecendo por trás de cada etapa.

  1. Ticket #431 — "Adicionar avatar do usuário no perfil"

    A tarefa chega com o problema descrito e algum critério de aceite. Se estiver vaga, o momento de perguntar é agora, não no meio da implementação.

  2. git switch -c feat/431-user-avatar

    Branch criada a partir de uma main atualizada. O número do ticket no nome liga o código à tarefa sem precisar de memória.

  3. Implementação

    O código e os testes crescem juntos. Testes escritos depois do PR aberto costumam ser justificativas do que já foi feito, em vez de verificações do que deveria acontecer.

  4. Commits

    Pequenos e com mensagem no imperativo, cada um deixando o projeto em um estado coerente. Isso é o que permite revisar por partes e reverter com precisão.

  5. git push -u origin feat/431-user-avatar

    A branch passa a existir no GitHub. Nada mudou para o resto do time ainda.

  6. Abertura do Pull Request

    Título explicando o efeito, descrição com contexto, o que mudou, como testar e riscos. Labels, reviewers e Closes #431 na descrição.

  7. CI executa

    Testes, lint, build e checagens de segurança rodam sobre a branch. Enquanto estiver vermelho, pedir revisão é gastar o tempo de outra pessoa com algo que a máquina já apontou.

  8. Revisão

    Comentários em linha, dúvidas, sugestões. Quem revisa distingue o que bloqueia do que é opcional; quem escreveu lê tudo antes de responder qualquer coisa.

  9. Ajustes e nova rodada

    Commits novos entram na mesma branch e atualizam o PR automaticamente. Cada thread recebe resposta; as encerradas são resolvidas; a revisão é solicitada de novo.

  10. Aprovação

    Com as exigências do repositório satisfeitas — número de aprovações, code owners, checks obrigatórios, conversas resolvidas — o botão de merge libera.

  11. Merge

    Na estratégia adotada pelo time. Com squash, o título do PR vira a mensagem do commit na main e a issue vinculada fecha sozinha.

  12. Branch removida

    O histórico já está na main. A branch pode ser restaurada pelo próprio PR se alguém precisar.

  13. Deploy

    Em times com entrega contínua, o merge na main dispara o pipeline de deploy. Em outros, a mudança entra na próxima release. Se algo der errado, o botão Revert do PR gera a correção em segundos.

Seção 22Boas práticas

A lista abaixo não é etiqueta: cada item resolve um problema concreto que aparece quando ele não é seguido.

PRs pequenos, com uma responsabilidade
Revisão superficial é consequência de diff grande, não de desleixo. Quanto menor o PR, mais específicos os comentários e mais fácil reverter se algo quebrar (GOOGLE, 2026b).
Título que descreve o efeito
Com squash, ele vira a mensagem do commit na main. É o que vai aparecer no git log, no changelog e na busca de quem investigar um bug daqui a um ano.
Descrição com contexto, mudanças, teste e riscos
Quem revisa não acompanhou sua semana. Cada pergunta que a descrição responde é uma ida e volta de horas que não acontece.
Commits compreensíveis
Commits separados por intenção permitem revisar por etapas e usar git bisect de verdade. "wip" e "ajustes" tornam o histórico inútil para quem investiga.
Revisar o próprio diff antes de pedir revisão
Boa parte dos comentários que você receberia — arquivo temporário, console.log, trecho comentado — você encontra sozinho na aba Files changed.
Testes junto com a mudança
Teste escrito depois tende a confirmar o que o código faz, e não o que deveria fazer. Além disso, é o teste que impede que a correção volte a quebrar seis meses depois.
Não misturar refatoração não relacionada
Renomear coisas no meio de uma feature esconde a mudança de verdade em meio a ruído e impede reverter uma sem desfazer a outra (GOOGLE, 2026b).
Responder todos os comentários
Silêncio é ambíguo: quem revisou não sabe se você concordou, discordou ou não viu — e thread sem resposta é PR parado sem motivo explícito.
Manter a branch atualizada quando necessário
Em PRs que vivem mais de um ou dois dias, trazer a base para dentro com frequência evita descobrir um conflito grande no pior momento — e faz o CI testar a combinação real.
Não ignorar um check vermelho
Reexecutar até passar transforma o CI em ruído. Se o teste é instável, isso é um problema do projeto e merece uma issue, não um clique em re-run.

Seção 23Erros comuns de quem está começando

Trabalhar direto na main
Funciona até o dia em que duas pessoas fazem isso ao mesmo tempo. Em repositórios protegidos, nem funciona: o push é recusado. Crie a branch antes do primeiro commit.
Abrir um PR gigante
Duas semanas de trabalho em um diff só garante revisão superficial e merge demorado. Quebre em etapas que façam sentido sozinhas.
Título "update" e descrição vazia
Empurra para quem revisa o trabalho de descobrir o que você fez. É a forma mais barata de garantir que seu PR fique por último na fila.
Pedir revisão de código que você não testou
Rodar os testes antes de abrir o PR é barato. Descobrir pelo reviewer que a suíte está vermelha custa o tempo de duas pessoas.
Levar comentários para o lado pessoal
Uma revisão com dez comentários geralmente significa que a pessoa leu com atenção. O objeto da conversa é o código, não você.
Aproveitar o PR para arrumar outras coisas
"Já que eu estava aqui" é como um PR de 200 linhas vira um de 900. Anote e abra outro PR.
Resolver a conversa sem corrigir nem responder
Fecha a thread e deixa o problema. Quem revisou percebe — e volta a abrir, com menos paciência.
Dar Approve sem revisar
Aprovar por cortesia esvazia o processo inteiro e transfere para você parte da responsabilidade pelo que entrar. Se não teve tempo, diga isso; se revisou só uma parte, use Comment e explique o que olhou.

Seção 24Checklist do autor

Uma passada rápida antes de clicar em Create pull request:

  • Estou na branch certa, criada a partir de uma main atualizada
  • O PR tem uma responsabilidade principal, não cinco
  • Li o meu próprio diff, arquivo por arquivo
  • O projeto compila e a suíte de testes passa localmente
  • Adicionei ou atualizei testes para o comportamento novo
  • O título explica o efeito da mudança, não o nome da branch
  • A descrição tem contexto, o que mudou e por quê
  • Escrevi como testar, em passos que outra pessoa consegue seguir
  • Incluí screenshots ou exemplos quando a mudança é visível
  • Não entrou nenhum arquivo acidental: log, configuração local, código comentado
  • Marquei os reviewers certos e vinculei a issue com Closes #

Seção 25Checklist do reviewer

E antes de clicar em Submit review:

  • Entendi qual problema este PR resolve
  • A solução resolve esse problema, e não um parecido
  • Verifiquei os casos de borda: nulo, vazio, limite, erro
  • Consigo entender o código sem o autor ao lado
  • Pensei em regressões: o que mais usa esse trecho?
  • Os testes cobrem o comportamento novo, não só o caminho feliz
  • Olhei implicações de segurança quando o contexto pede
  • Deixei claro o que bloqueia e o que é sugestão opcional
  • Cada comentário meu explica o motivo, não só o que mudar
  • Se aprovei, foi porque revisei de verdade

Seção 26Glossário

Repository (repositório)
O projeto com todo o seu histórico. Existe em duas cópias: a local, na sua máquina, e a remota, no GitHub.
Branch
Um ponteiro para um commit. Criar uma é barato e instantâneo, porque nada é copiado.
Commit
Uma mudança registrada no histórico, com autor, mensagem e identificador (SHA).
Diff
A diferença entre duas versões do código, mostrada linha a linha com + e -.
Pull Request
Proposta de integrar os commits de uma branch em outra, com discussão, revisão e checks. Existe no GitHub, não no Git.
Base / compare
A branch de destino e a branch de origem de um PR.
Reviewer
Pessoa convidada a revisar um PR. Pode ser indicada manualmente ou automaticamente, via CODEOWNERS.
Approval
Revisão enviada com o estado Approve, indicando que a mudança está pronta para entrar.
Merge
A integração efetiva da branch de origem na de destino.
Merge conflict
Situação em que o Git não consegue combinar duas mudanças automaticamente e precisa de decisão humana.
CI (integração contínua)
Execução automática de testes e verificações a cada mudança proposta.
Status check
O resultado de uma verificação automatizada exibido no PR. Pode ser obrigatório ou apenas informativo.
CODEOWNERS
Arquivo que associa padrões de caminho a pessoas ou times, para solicitar revisão automaticamente.
Branch protection
Regras clássicas que restringem o que pode ser feito em uma branch: exigir PR, aprovações, checks.
Ruleset
Modelo mais recente de regras do GitHub, empilhável, com status próprio e visível para todo o time.
Draft PR
Pull Request marcado como trabalho em andamento: não pode ser mergeado e não solicita revisão dos code owners.
Fork
Cópia de um repositório na sua conta, usada para contribuir com projetos onde você não tem acesso de escrita.
Squash
Estratégia de merge que combina todos os commits do PR em um só na branch de destino.

FontesReferências

Documentação consultada para escrever este guia, toda ela verificada em 17 de setembro de 2026. As citações no texto seguem a NBR 10520 e a lista abaixo, a NBR 6023; como várias obras são do mesmo autor e do mesmo ano, elas aparecem diferenciadas por letra (2026a, 2026b, e assim por diante). Cada citação no corpo do artigo é um link para a entrada correspondente.

Vale separar dois tipos de afirmação. Como o GitHub se comporta — o que cada botão faz, o que uma regra exige, o que cada estratégia de merge produz — vem da documentação oficial e está citado no ponto em que aparece. Já as recomendações de prática — tamanho de PR, tom de comentário, o que responder, quando bloquear — são convenções de equipe: onde existe fonte pública que as sustente, ela está citada; no restante, o texto as apresenta como recomendação e não como dado. Os números de tamanho de mudança da seção 19, por exemplo, são do guia de code review do Google, não estimativas deste artigo.