Shopping cart

Subtotal $0.00

View cartCheckout

Building better devs

TnewsTnews
  • Home
  • Programação
  • Stacked PRs no GitHub: Como Fazer Code Review de Mudanças Gigantes Sem Enlouquecer
Programação

Stacked PRs no GitHub: Como Fazer Code Review de Mudanças Gigantes Sem Enlouquecer

Email : 2

Quem nunca abriu aquele pull request de 47 arquivos modificados, 3.200 linhas adicionadas, e viu o reviewer responder com um “LGTM” em 4 minutos? A gente sabe que ninguém leu aquilo. E quem leu, pediu demissão depois.

O GitHub finalmente entregou o que devs pediam há anos: Stacked Pull Requests, agora em public preview para todos os repositórios. A feature permite quebrar mudanças gigantes em camadas menores e independentes, cada uma com seu próprio PR, review e CI. E o melhor: o rebase é automático.

Eu já usei ferramentas de terceiros pra fazer isso (Graphite, ghstack do Facebook, até shell scripts caseiros). Nenhuma delas resolvia o problema de verdade, porque o GitHub não entendia nativamente o conceito de “stack”. Agora entende.

O Problema que Todo Dev Conhece

Você está refatorando um módulo. A mudança envolve alterar o schema do banco, criar novos tipos, atualizar a API, reescrever os testes e mexer no frontend. Se você joga tudo num PR só, acontece uma de duas coisas:

  1. O reviewer olha, vê 2.000 linhas, e aprova sem ler (perigoso)
  2. O reviewer olha, vê 2.000 linhas, e não aprova nunca (bloqueante)

Os dois cenários são ruins. O primeiro enfia bug em produção. O segundo trava o sprint inteiro.

A solução clássica era “quebre em PRs menores”, mas na prática isso significava um pesadelo de rebases manuais, conflitos entre branches, e reviewers que não sabiam em que ordem olhar as coisas.

Como Stacked PRs Funcionam

A ideia é simples: em vez de um PR enorme, você cria uma pilha de PRs onde cada camada depende da anterior.


main
  └── feat/schema-changes      ← PR #1 (schema + tipos)
        └── feat/api-layer      ← PR #2 (API endpoints)
              └── feat/frontend  ← PR #3 (componentes React)

Cada PR aponta para o branch abaixo dele, não para main diretamente. O PR #1 aponta para main. O PR #2 aponta para feat/schema-changes. O PR #3 aponta para feat/api-layer.

Na interface do GitHub, cada PR exibe um ícone de stack com o número da camada. Um mapa visual mostra a pilha completa e permite navegar entre as camadas com um clique.

O ponto central: o reviewer do PR #2 só vê o diff daquela camada específica. Não precisa filtrar mentalmente as mudanças do schema que já foram feitas no PR #1. Cada review é focado, curto, e faz sentido isoladamente.

Instalação e Primeiros Passos

O GitHub criou uma extensão oficial do CLI para gerenciar stacks localmente:


# Instalar a extensão
gh extension install github/gh-stack

# (Opcional) Criar alias para digitar menos
gh stack alias

Depois de instalado, o workflow fica assim:


# Iniciar a stack criando o primeiro branch
gs init feat/schema-changes

# Fazer suas mudanças, commitar normalmente
git add .
git commit -m "Add new user schema fields"

# Adicionar uma nova camada na stack
gs add feat/api-layer

# Mais mudanças, mais commits
git add .
git commit -m "Add user profile API endpoints"

# Adicionar mais uma camada
gs add feat/frontend

# Quando estiver pronto, push de tudo
gs push

# Abrir todos os PRs da stack de uma vez
gs submit

O gs submit cria todos os PRs na ordem certa, com cada um apontando para o branch correto. Sem copiar e colar URLs, sem configurar base branches manualmente.

O Rebase Automático (a Parte que Importa)

Rebasing sempre foi o terror de quem tentava fazer stacked PRs manualmente. Alguém faz um fix no PR #1, e agora os PRs #2 e #3 estão desatualizados. Você precisa fazer rebase em cascata, resolver conflitos em cada branch, e rezar para não ter quebrado nada.

O GitHub agora faz isso automaticamente. Existem duas formas:

Rebase server-side (pela interface web):

Dentro de qualquer PR da stack, existe um botão para rebase em cascata. Um clique e o GitHub rebasa todos os PRs acima daquele ponto.

Rebase local (pelo CLI):


# Rebasa toda a stack localmente
gs rebase

E quando você faz merge do PR inferior, os PRs acima são automaticamente re-apontados para main e rebasados. Sem intervenção manual.

Isso sozinho já vale a feature inteira. Quem já perdeu uma tarde fazendo rebases em cascata sabe do que eu estou falando.

Merge: Flexível Como Deveria Ser

Você tem três opções para fazer merge de uma stack:

Estratégia O que acontece
Merge do topo Faz merge de todos os PRs da stack de uma vez, de baixo para cima
Merge do meio Faz merge até aquele ponto; PRs acima são re-apontados para main
Merge individual Faz merge só daquele PR; os de cima são rebased automaticamente

Os três métodos de merge do GitHub funcionam: merge commit, squash e rebase. O histórico final é o mesmo de ter feito merge de cada PR individualmente, começando de baixo.

E sim, merge queues também são suportadas (rollout progressivo nas próximas semanas).

Branch Protection Funciona Igual

Uma preocupação legítima: “se eu uso branch protection com CODEOWNERS e checks obrigatórios, isso ainda funciona?”

Funciona. Cada PR na stack precisa passar pelas mesmas regras que qualquer PR normal:

  • Aprovações de CODEOWNERS são exigidas em cada camada
  • Checks de CI rodam em cada PR individualmente
  • Status checks obrigatórios precisam passar em todos os PRs antes do merge
  • Os requisitos de merge são determinados pelo branch base do PR mais baixo da stack

Não tem atalho. Cada camada é um cidadão de primeira classe no fluxo de review.

Na Prática: Quando Usar (e Quando Não Usar)

Stacked PRs brilham em cenários específicos:

Use quando:

  • A mudança toca múltiplas camadas da aplicação (banco, API, frontend)
  • A feature é grande demais para um review produtivo
  • Você quer continuar trabalhando enquanto o PR anterior está em review
  • Múltiplos reviewers precisam olhar partes diferentes da mudança
  • Agentes de IA estão gerando código que precisa de review humano em partes

Não use quando:

  • A mudança é pequena e atômica (um bugfix de 20 linhas não precisa de stack)
  • As mudanças são independentes entre si (use PRs separados normais)
  • Você está trabalhando num fork (stacked PRs exigem que todos os branches estejam no mesmo repositório)

O Ecossistema Antes do GitHub

Essa feature não nasceu do nada. O conceito de stacked diffs existe há mais de uma década:

Ferramenta Contexto
Phabricator (Meta) Pioneiro do modelo “uma mudança = um diff”. Usado internamente no Facebook por anos. Descontinuado em 2021
Gerrit (Google) Sistema de code review do Google que usa change sets empilhados
Graphite Startup que trouxe stacked PRs para o GitHub como extensão de terceiros
ghstack (Meta) CLI open source que simula stacked diffs no GitHub
Aviator Plataforma de merge que suporta stacked PRs com merge queues

O Graphite, especificamente, construiu um negócio inteiro em cima dessa lacuna do GitHub. Agora que o GitHub entrega a feature nativamente, a pergunta é: o Graphite ainda tem razão de existir?

A resposta curta: provavelmente sim, pelo menos por enquanto. O Graphite tem analytics de PR, dashboards de produtividade, e integrações que vão além do que o GitHub oferece nativamente. Mas o core da proposta de valor (stacked PRs) agora é commodity.

Integração com Agentes de IA

Um detalhe que passou despercebido no anúncio: o GitHub mencionou que agentes de IA podem aprender o workflow de stacks usando gh skill install github/gh-stack.

Isso abre uma possibilidade interessante. Imagine um agente como o Copilot Workspace recebendo uma task complexa e, em vez de gerar um PR monstruoso, quebrando a implementação em uma stack de PRs focados. Schema num PR. API em outro. Testes em outro.

O reviewer humano consegue analisar cada camada com contexto suficiente para dar feedback real, em vez de olhar 3.000 linhas e torcer para estar tudo certo.

Com a tendência de agentes de código gerando PRs cada vez maiores (Cursor com 1.000 commits por segundo, Claude Code fazendo refactors de 960.000 linhas), stacked PRs podem ser a diferença entre review real e “LGTM” automático.

Tutorial Completo: Stack do Zero ao Merge

Vamos fazer na prática. Suponha que você está adicionando um sistema de notificações push no seu app:


# 1. Instalar a extensão (uma vez só)
gh extension install github/gh-stack

# 2. Criar o primeiro branch da stack
gs init feat/notification-schema

# 3. Criar a migration e os tipos
cat > migrations/add_notifications.sql << 'SQL'
CREATE TABLE notifications (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id),
    title VARCHAR(255) NOT NULL,
    body TEXT,
    read_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_notifications_user ON notifications(user_id);
SQL

git add . && git commit -m "Add notifications table schema"

# 4. Subir uma camada: API
gs add feat/notification-api

cat > src/routes/notifications.ts << 'TS'
import { Router } from 'express';
import { db } from '../db';

const router = Router();

router.get('/:userId', async (req, res) => {
  const notifications = await db.query(
    'SELECT * FROM notifications WHERE user_id = $1 ORDER BY created_at DESC',
    [req.params.userId]
  );
  res.json(notifications.rows);
});

router.patch('/:id/read', async (req, res) => {
  await db.query(
    'UPDATE notifications SET read_at = NOW() WHERE id = $1',
    [req.params.id]
  );
  res.sendStatus(204);
});

export default router;
TS

git add . && git commit -m "Add notification API endpoints"

# 5. Mais uma camada: frontend
gs add feat/notification-ui

# ... código React/Vue/Svelte aqui ...
git add . && git commit -m "Add notification bell component"

# 6. Push e submit de toda a stack
gs push
gs submit

Resultado: três PRs criados, cada um com seu diff isolado, prontos para review em paralelo.

API e Webhooks

Para quem automatiza workflows, o GitHub expôs stacks via API:


# REST API: listar PRs de uma stack
curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
  "https://api.github.com/repos/owner/repo/pulls/123/stack"

Webhooks de pull request agora incluem um objeto stack no payload, com informações sobre a posição do PR na pilha, quantas camadas existem, e o status de cada uma.

Na GraphQL API, campos stack estão disponíveis para consultas read-only.

Limitações (Sim, Tem Algumas)

Nem tudo são flores:

  • Cross-fork não funciona. Todos os branches precisam estar no mesmo repositório. Se você trabalha com forks (comum em open source), vai ter que usar outro workflow.
  • GitHub Desktop não suporta. Se você depende do Desktop em vez do CLI, não dá para criar stacks por lá.
  • Merge queues estão em rollout progressivo. Se seu repo usa merge queue, pode demorar um pouco para funcionar com stacks.
  • Curva de aprendizado. Devs que nunca trabalharam com stacked diffs podem demorar para entender quando e como quebrar uma mudança em camadas. Não é intuitivo na primeira vez.

O Que Muda no Dia a Dia

Se sua equipe faz reviews de PRs grandes regularmente, stacked PRs vão mudar o jogo. Reviews ficam mais rápidos, mais focados, e mais úteis. O reviewer não precisa mais fazer ginástica mental para separar “o que é schema” de “o que é lógica de negócio” de “o que é UI”.

Para quem trabalha solo, a utilidade é menor. Mas mesmo assim, a capacidade de continuar codando enquanto o PR anterior está em review, sem criar um emaranhado de branches manuais, já vale a pena.

A feature está disponível agora para todos os repositórios do GitHub. Basta instalar a extensão gh-stack e começar a empilhar.

Comparando com o Workflow Tradicional

Para deixar mais concreto, veja a diferença entre o fluxo antigo e o novo:

Antes (PR monolítico):


1. Dev coda tudo numa branch (3 dias)
2. Abre PR com 2.500 linhas
3. Reviewer demora 2 dias pra revisar
4. 47 comentários, 3 rounds de revisão
5. Merge depois de 5 dias

Agora (stacked PRs):


1. Dev coda a primeira camada (schema) em 4 horas
2. Abre PR #1 com 200 linhas — review em 1 hora
3. Enquanto isso, já está codando a API no PR #2
4. Reviewer aprova PR #1, começa PR #2
5. Tudo mergeado em 2 dias, com reviews reais

A diferença não é só de velocidade. É de qualidade. Um review de 200 linhas é fundamentalmente diferente de um review de 2.500 linhas. No primeiro, o reviewer encontra bugs. No segundo, o reviewer encontra desculpas para aprovar logo.

Estudos mostram que a taxa de detecção de defeitos cai drasticamente acima de 400 linhas por review. Stacked PRs mantêm cada camada dentro dessa zona produtiva.

O que o Phabricator fazia internamente no Meta há uma década, o GitHub finalmente trouxe para todo mundo. Demorou, mas chegou.


Fonte de inspiração: Stacked pull requests are now in public preview (GitHub Blog)

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts