12k
All articles

Como funcionam os pull requests empilhados no GitHub

Veja como funcionam os pull requests empilhados no GitHub: crie uma pilha com gh-stack, revise camadas, rebaseie alterações e mescle PRs dependentes.

OpenReplay Team
OpenReplay Team
Como funcionam os pull requests empilhados no GitHub

Os pull requests empilhados (stacked pull requests) do GitHub dividem uma mudança grande em uma cadeia ordenada de pull requests pequenos. Cada um aponta para a branch do pull request logo abaixo dele, e o GitHub revisa, faz rebase e faz merge da cadeia como uma única unidade.

A maioria das equipes conhece a alternativa. Você desenvolve uma feature em três partes dependentes, abre três PRs, e o segundo mostra tanto as mudanças do primeiro quanto as suas próprias. Os revisores desistem, ou você junta tudo em um único PR gigante que ninguém lê direito.

Este artigo explica do início ao fim como funcionam as pilhas nativas do GitHub: como criar uma pilha, como funciona a revisão, o que acontece quando um PR no meio da pilha muda e o que cada opção de merge faz. Se precisar relembrar o básico sobre PRs comuns, veja como criar pull requests pelo terminal.

Principais pontos

  • Em uma pilha do GitHub, a base de cada pull request é a branch do PR logo abaixo dele, então cada diff contém apenas as mudanças daquela camada.
  • O GitHub anunciou os pull requests empilhados em public preview em 30 de julho de 2026. O recurso está sujeito a mudanças.
  • Segundo o quickstart do GitHub, a extensão de CLI gh-stack exige o GitHub CLI 2.90.0 ou superior e o Git 2.20 ou superior.
  • Se uma camada intermediária muda, todas as branches acima dela ficam apontando para um commit desatualizado. Essas branches precisam passar por rebase de baixo para cima e receber force-push.
  • Fazer merge do PR pronto mais alto da pilha integra esse PR e todos os PRs abaixo dele ainda sem merge em uma única operação. Se o merge falhar no meio do caminho, os PRs que já foram integrados continuam integrados e os demais continuam abertos. Cada PR é verificado de acordo com as regras da branch base da pilha.

O problema dos pull requests dependentes

Pull requests dependentes travam na revisão porque o GitHub compara cada PR com sua branch base. Suponha que você abra três PRs, todos apontando para main: auth-middleware, depois api-routes e depois ui-login. O diff do segundo PR também contém todo o código do middleware, e o terceiro contém tudo. Ninguém consegue dizer quais linhas cada PR realmente introduz.

Sem pilhas nativas, os desenvolvedores costumam contornar isso de duas formas. Ou juntam tudo em um PR grande, o que torna a revisão mais lenta e esconde erros. Ou apontam manualmente cada PR para a branch abaixo dele e, a cada mudança, fazem eles mesmos o rebase e o redirecionamento de toda a cadeia.

O que são PRs empilhados no GitHub?

Um pull request empilhado no GitHub é um elo de uma cadeia ordenada. Cada PR usa como base a branch do PR abaixo dele, de modo que seu diff mostra apenas as mudanças feitas naquela camada. A visão geral do GitHub sobre pull requests empilhados explica que o PR da base da pilha aponta para o trunk da pilha, que normalmente é main, mas pode ser qualquer branch, como uma branch de release. Todas as branches de uma pilha precisam estar no mesmo repositório, então as pilhas não podem abranger forks.

Veja como fica o exemplo de três camadas depois de empilhado:

main
 └─ auth-middleware   PR → main             (diff: middleware only)
     └─ api-routes     PR → auth-middleware  (diff: routes only)
         └─ ui-login    PR → api-routes       (diff: login UI only)

O modelo continua sendo baseado em branches e bases, algo que o Git já entende. O GitHub acrescenta o controle por cima: ele conhece a ordem dos PRs, os vincula entre si e opera sobre eles como um grupo.

Criando uma pilha com o gh CLI

A extensão gh-stack cria e gerencia pilhas pelo terminal. O quickstart do GitHub lista como pré-requisitos o GitHub CLI 2.90.0 ou superior e o Git 2.20 ou superior. A referência de comandos da CLI e o README da extensão indicam um mínimo mais baixo, o gh 2.0, então o valor do quickstart é o mais seguro a seguir. Você também precisa estar autenticado e ter permissão de push no repositório. Se o gh for novidade para você, comece por criar pull requests pelo terminal.

gh --version        # 2.90.0 or later
git --version       # 2.20 or later
gh auth login
gh extension install github/gh-stack

Em seguida, monte a pilha uma camada por vez:

gh stack init                      # prompts for the first branch name, e.g. auth-middleware
git add -A
git commit -m "Auth middleware"

gh stack add api-routes
git add -A
git commit -m "API routes"

gh stack add ui-login
git add -A
git commit -m "Login UI"

gh stack push                      # pushes branches only
gh stack submit                    # opens PRs with correct bases and links them
gh stack view                      # branches, PR links, statuses, latest commits

O gh stack init configura o controle local da pilha e cria a primeira branch. A menos que você passe --base, o trunk é a branch padrão do repositório. A referência de comandos da CLI destaca que o push apenas envia as branches e nunca mexe nos pull requests. O submit é o comando que abre os PRs, define a branch base correta para cada um e os reúne em uma pilha.

Você também pode usar a interface web. No github.com, é possível criar uma pilha abrindo um PR cuja base seja a branch de um PR anterior e selecionando Create stack. Para ampliar uma pilha existente, abra qualquer PR dela e escolha Add to stack no cabeçalho. Se seus PRs abertos já estiverem encadeados, o GitHub exibe um banner oferecendo transformá-los em uma pilha. As pilhas podem ser usadas pelo app mobile do GitHub e por agentes de código como o Copilot, por meio da skill gh-stack. O GitHub Desktop não oferece suporte a elas.

Revisando uma pilha camada por camada

Os revisores podem aprovar cada camada de uma pilha separadamente. Revisores diferentes podem trabalhar em camadas diferentes ao mesmo tempo, enquanto o autor continua construindo por cima. O principal benefício dos pull requests empilhados é que a revisão acontece sobre diffs pequenos, e a feature inteira não precisa estar pronta para a revisão começar.

Ao abrir qualquer PR da pilha, você vê apenas o diff daquela camada. A caixa de merge contém um mapa da pilha que lista todos os PRs da cadeia com seus status, e o número no ícone da pilha, no topo da página, indica qual camada está aberta.

Camadas pequenas também deixam um histórico mais útil na main. Cada commit integrado é focado, então uma sessão de git bisect consegue apontar uma mudança específica, em vez de um merge de mil linhas.

Atualizando um PR no meio da pilha

Quando um novo commit entra em uma branch no meio de uma pilha, todas as branches acima dela continuam apontando para o commit antigo. Essas branches superiores precisam passar por rebase sobre a camada atualizada e receber force-push. No exemplo, uma correção de revisão em api-routes deixa ui-login desatualizada. A auth-middleware não é afetada.

Em uma cadeia gerenciada manualmente, você faz isso por conta própria com Git puro (veja 10 comandos Git para o básico sobre rebase):

# plain Git, no gh-stack
git checkout ui-login
git rebase api-routes              # resolve any conflicts
git push --force-with-lease
# repeat for every branch above, bottom to top

Com o gh-stack, o tutorial de empilhamento de mudanças de código reduz isso a dois comandos:

gh stack checkout api-routes
git add -A
git commit -m "Fix API routes"
gh stack rebase --upstack          # rebases only the branches above api-routes
gh stack push                      # per-branch --force-with-lease

Se o rebase parar em um conflito, corrija os arquivos conflitantes, adicione-os com git add e execute gh stack rebase --continue. Para desistir, gh stack rebase --abort devolve todas as branches ao estado em que estavam antes do rebase.

No github.com, um botão Rebase stack aparece na caixa de merge assim que a pilha deixa de ser linear. Segundo o guia de gerenciamento de pull requests empilhados, clicar nele reaplica as branches sobre o trunk mais recente, começando pela base, e faz force-push de cada uma. Commits feitos dessa forma nos servidores do GitHub não têm assinatura, então repositórios que exigem commits assinados devem fazer o rebase localmente com gh stack rebase.

O rebase reescreve as branches superiores. Se alguém da equipe estiver com uma dessas branches em checkout, deve parar e sincronizar com o remoto antes de fazer qualquer outro commit. Caso contrário, o próximo push dessa pessoa vai entrar em conflito com o histórico reescrito.

Fazendo merge de uma pilha

Fazer merge do pull request pronto mais alto da pilha integra esse PR junto com todos os PRs abaixo dele ainda sem merge, em uma única operação. Se algo falhar no meio do caminho, como um conflito inesperado, o merge para naquele PR: os PRs abaixo dele que já foram integrados continuam na branch base, e o PR que falhou e todos acima dele continuam abertos. Se você fizer merge apenas das camadas inferiores, os PRs acima delas continuam abertos, enquanto o GitHub faz o rebase deles e muda sua base para a branch base da pilha. O guia de merge exige que a pilha tenha histórico linear antes que qualquer parte dela possa ser integrada.

Você faz merge deO que entra na mainO que acontece com o restante
PR pronto do topo (ui-login)Os três PRsNada fica aberto
PR da base (auth-middleware)Apenas esse PROs PRs superiores passam por rebase e são redirecionados para a main
PR do meio (api-routes)Esse PR e todos os PRs abaixo deleui-login continua aberto e é redirecionado para a main

Um PR no meio de uma pilha do GitHub não pode ser integrado sozinho. Ele sempre entra junto com os PRs abaixo dele. Segundo a referência do GitHub sobre pull requests empilhados, as pilhas funcionam com merge commits, squash e rebase. Com squash, cada PR vira seu próprio commit consolidado, então fazer merge de três PRs coloca três commits na main.

As regras de merge vêm da branch base da pilha, e não da branch para a qual cada PR aponta diretamente. Assim, as proteções de branch e as verificações obrigatórias continuam decidindo o que chega à main. As pilhas também funcionam com filas de merge (merge queues), que recebem os PRs na ordem correta. O changelog de 30 de julho de 2026 informava que o suporte a filas de merge seria liberado gradualmente, e o guia de merge do GitHub agora descreve as filas de merge como totalmente suportadas.

Empilhamento antes do suporte nativo

Antes de o GitHub oferecer suporte nativo a pilhas, era preciso usar uma ferramenta separada para gerenciar a cadeia de branches. Graphite, spr e git-branchless cuidavam desse controle por fora do modelo de pull requests do próprio GitHub.

Os pull requests empilhados nativos do GitHub funcionam com as revisões, verificações obrigatórias e proteções de branch que você já tem, então a equipe não precisa adotar mais uma ferramenta. Para as equipes que migraram para ferramentas de empilhamento apenas para contornar PRs dependentes ilegíveis, isso elimina o principal motivo para usá-las.

Conclusão

Uma pilha do GitHub é uma cadeia de pull requests em que cada um usa a branch abaixo dele como base, com o GitHub cuidando do rebase, do redirecionamento e do merge. Como cada camada é pequena, os revisores conseguem lê-la com atenção, e uma mudança no meio da pilha exige apenas o rebase das branches acima dela. Para experimentar, instale o github/gh-stack e divida sua próxima feature de várias partes em três camadas.

Perguntas frequentes

O auto-merge funciona com pull requests empilhados no GitHub?

Não. A documentação de merge do GitHub informa que o auto-merge não é suportado para pull requests empilhados. Ferramentas que fazem merge pela API precisam usar a API de merge assíncrona para pilhas, porque os endpoints de merge de pull request mais antigos não conseguem integrar uma pilha. Para integrar uma pilha automaticamente quando as verificações passarem, use uma fila de merge: as pilhas são compatíveis com filas de merge, e a fila recebe os PRs na ordem da pilha.

O que acontece quando um pull request empilhado é removido de uma fila de merge?

Todos os pull requests acima dele na pilha também saem da fila. Para manter a pilha inteira, a fila de merge permite que um grupo de merge cresça até 50% além do tamanho máximo configurado. Uma pilha grande demais para essa margem extra é dividida pelo GitHub em vários grupos de merge consecutivos.

Como atualizo minha pilha local depois que o pull request da base é integrado?

Execute gh stack sync. Em uma única etapa, ele baixa as alterações mais recentes, avança o trunk, faz o rebase das branches restantes sobre ele, envia essas branches e atualiza o status de cada pull request. Adicione --prune para excluir as branches locais dos pull requests já integrados. Se o sync encontrar um conflito, ele devolve todas as branches ao estado anterior; nesse caso, execute gh stack rebase para resolver o conflito e depois gh stack push.

Como reordeno, removo ou renomeio camadas de uma pilha existente?

Use o gh stack modify, uma interface interativa de terminal que permite remover, mesclar (fold), inserir, reordenar e renomear branches. Ele exige uma working tree limpa, histórico linear, nenhum rebase em andamento e nenhum pull request na fila de merge. Não é possível reordenar branches e, na mesma sessão, também removê-las, mesclá-las, inseri-las ou renomeá-las. Suas alterações só são aplicadas quando você salva, e gh stack modify --abort restaura a pilha ao estado anterior. Depois, execute gh stack submit para atualizar o GitHub.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.