Stacked pull request: come creare ed esaminare uno stack su GitHub
Le stacked pull request (pull request impilate) dividono una grande modifica in piccoli livelli. Vediamo il supporto nativo di GitHub e la code review in uno stack.
In sintesi. Le stacked pull request (pull request impilate) dividono una grande modifica in piccole pull request che si appoggiano l’una sull’altra. GitHub ha portato la funzione in anteprima pubblica il 30 luglio 2026 e in disponibilità generale il 6 ottobre 2026. Il 14 ottobre 2026 abbiamo letto gli annunci di GitHub, la sua documentazione e la guida dell’estensione gh stack. A questo aggiungiamo ciò che abbiamo imparato costruendo uno stack a mano nel nostro repository, prima che arrivasse il supporto nativo.
- Ogni livello è una pull request a sé. Quella più in basso punta al branch principale, le altre al branch di quella sotto; ognuna mostra solo il diff del proprio livello.
- A ogni livello valgono le regole del branch principale. Approvazioni obbligatorie, controlli obbligatori e CODEOWNERS si applicano anche se la pull request non punta direttamente a
main. - Il merge va dal basso verso l’alto. La pull request che scegli entra insieme a quelle sotto in un’unica operazione; quelle che restano sopra ricevono un rebase automatico e puntano al branch principale.
- Verifica tu su quale commit sono girati i controlli. Nello stack che abbiamo costruito a mano, i controlli verdi erano quelli di un commit vecchio; dopo un rebase confronta quel commit con la punta del branch.
Che cos’è uno stack e a cosa serve
Se apri una grande funzionalità in un’unica pull request, chi fa la review vede centinaia di righe tutte insieme. Le stacked pull request (pull request impilate) dividono lo stesso lavoro in piccole pull request messe in fila. Questa fila si chiama stack; ogni pull request al suo interno si chiama livello (layer).
Secondo la definizione di GitHub, uno stack è formato da due o più pull request nello stesso repository. Quella più in basso punta al branch principale dello stack (trunk): di solito è main, ma può essere anche un branch di rilascio. Ogni pull request successiva punta al branch di quella sotto. Il branch a cui punta una pull request si chiama la sua base.

Ogni pull request mostra solo il diff del proprio livello: la differenza tra il suo branch e quello sotto. L’ordine segue una regola: il codice su cui un livello si basa sta nello stesso branch o in uno più in basso. I tipi condivisi e lo schema del database vanno in basso, gli endpoint dell’API e l’interfaccia che li usano vanno in alto.
I vantaggi sono due. Secondo la documentazione di GitHub una pull request piccola viene esaminata più in fretta, ed è meno probabile che venga letta di corsa, che invecchi o che finisca in conflitto. Inoltre, se la tua prossima modifica si basa su un lavoro non ancora unito, non devi aspettarlo: apri una nuova pull request sopra. Se il codice lo scrive un agente IA, l’ordine nasce da solo: un livello per ogni compito.
Concatenare i branch a mano non è una novità; la novità è che GitHub riconosce la catena. La funzione è entrata in anteprima pubblica il 30 luglio 2026 ed è passata in disponibilità generale il 6 ottobre 2026; secondo l’annuncio è disponibile su tutti i piani di github.com.
Ciò che fa la funzione lo riportiamo dalla documentazione di GitHub, così come l’abbiamo letta il 14 ottobre 2026. Noi sviluppiamo diffox, uno strumento che esamina le pull request; prima che arrivasse il supporto nativo abbiamo costruito uno stack a mano nel nostro repository. Ciò che abbiamo imparato lì è più sotto, in una sezione a parte.
Come creare uno stack su GitHub
Per la riga di comando GitHub CLI ha l’estensione gh stack. Crea i branch nell’ordine giusto, fa il rebase e il push, apre le pull request e le collega tra loro come stack. Uno stack a tre livelli si crea così:
gh extension install github/gh-stack
gh stack init auth-layer # primo branch, sopra il branch principale
git add .
git commit -m "Livello di autenticazione"
gh stack add api-endpoints # secondo branch, sopra il primo
git add .
git commit -m "Endpoint API"
gh stack add frontend # terzo branch
git add .
git commit -m "Interfaccia"
gh stack submit # fa il push, apre le pull request, le collega allo stack
gh stack view # mostra i branch, le pull request e il loro statogh stack submit apre ogni pull request con la base giusta: il primo branch punta a main, ogni branch successivo a quello sotto. Se il branch principale non è main, scrivi gh stack init --base release auth-layer. L’estensione non è obbligatoria; lo stesso stack si crea anche in altri modi:
- Interfaccia web. Apri la prima pull request come sempre. Alla seconda dai come base il branch della prima e scegli l’opzione «Create stack». Se hai già pull request aperte le cui basi formano una catena, GitHub la riconosce e mostra un banner che propone di trasformarle in uno stack.
- Agente di programmazione.
gh skill install github/gh-stackinstalla la skill che insegna all’agente a lavorare congh stack; come esempio GitHub cita Copilot. - Altri strumenti. Chi gestisce i propri branch con Jujutsu, Sapling o git-town apre gli stessi branch come stack su GitHub con il comando
gh stack link.
Nella pagina di una pull request che fa parte di uno stack compare la mappa dello stack (stack map). La mappa mostra ogni pull request dello stack e il suo stato, e con un clic ti porta al livello che vuoi; il branch principale è in fondo alla mappa.
Come funzionano protezione dei branch e CI in uno stack
Il punto debole della catena fatta a mano erano le regole. I livelli superiori non puntano a main ma a un branch di funzionalità; e la documentazione di GitHub scrive che, senza il supporto nativo, le regole di protezione dei branch e i controlli di CI spesso scattano solo sulla pull request più in basso.
In uno stack nativo ogni pull request, a qualunque branch punti direttamente, viene valutata secondo le regole del branch principale dello stack. La pagina di riferimento elenca quattro regole: approvazioni di review obbligatorie, controlli di stato obbligatori, CODEOWNERS e code scanning.
GitHub Actions segue la stessa logica. Un workflow attivato dall’evento pull_request verso main gira per ogni pull request dello stack; non devi modificare il file del workflow.
Attenzione però al consumo di CI: il workflow gira una volta per pull request, quindi uno stack grande lo moltiplica. Secondo la documentazione, le espressioni dei workflow danno accesso alle informazioni dello stack, così puoi limitare i job costosi a certi livelli: sotto github.event.pull_request.stack ci sono la dimensione dello stack (size) e la posizione della pull request (position). Se sono uguali, sei al livello più alto.
Come si fa il merge di uno stack
Il merge di uno stack si fa dal basso verso l’alto. Puoi unirne più d’una insieme, purché siano consecutive e partano dalla pull request più in basso non ancora unita. Una pull request a metà dello stack non si può unire da sola: quelle sotto entrano con lei.

Secondo la documentazione, per il merge di una pull request servono tre condizioni: rispetta tutti i requisiti di protezione del branch principale, li rispetta anche ogni pull request sotto di lei, e la cronologia tra i branch è lineare. Se su uno dei branch inferiori arriva un nuovo commit, o se il branch principale va avanti, la cronologia non è più lineare. Allora nel riquadro di merge compare il pulsante «Rebase stack»; da riga di comando l’equivalente è gh stack rebase, seguito da gh stack push.
Sono supportati tutti e tre i metodi di merge: merge commit, squash e rebase. Con lo squash ogni pull request diventa un solo commit sul branch principale: tre pull request, tre commit. Dopo il merge, la pull request successiva riceve un rebase automatico e punta direttamente al branch principale. I branch locali li aggiorna gh stack sync --prune: fa avanzare il branch principale, ci rimette sopra i branch rimasti e cancella i branch locali già uniti.
Nei repository che usano la merge queue (coda di merge), le pull request dello stack entrano in coda nell’ordine giusto. Se una viene tolta dalla coda, escono anche quelle sopra.
Costruendo uno stack a mano ci siamo bloccati in tre punti
Prima che arrivasse il supporto nativo, ad agosto 2026, abbiamo costruito a mano uno stack a due livelli nel nostro repository. Il nostro repository fa il merge con lo squash. Dopo il merge della pull request inferiore, per quella superiore abbiamo dovuto fare tre cose a mano.

La prima è stata il rebase. Lo squash trasforma i commit del branch inferiore in un unico commit nuovo; i vecchi commit non compaiono nella cronologia del branch principale. Il branch superiore portava ancora quei commit, quindi un merge semplice con il branch principale è andato in conflitto. A risolvere è stato git rebase --onto, che sposta solo i commit propri della pull request superiore. La seconda è stata la base: la pull request superiore continuava a puntare al branch inferiore, e l’abbiamo spostata a mano sul branch principale.
La terza era silenziosa. Né il force-push né il cambio di base hanno avviato la CI sulla nuova punta del branch, quella dopo il rebase. I segni verdi nella pagina erano dei controlli girati sulla punta precedente. A far partire la CI è stato chiudere e riaprire la pull request.
# la pull request inferiore è stata unita con lo squash; sei sul branch superiore
git fetch origin
git rebase --onto origin/main <vecchia-punta-del-branch-inferiore>
git push --force-with-lease
# sposta la base della pull request superiore sul branch principale
gh pr edit 123 --base main
# il commit su cui sono girati i controlli è la punta del branch?
gh pr view 123 --json headRefOid
gh run list --branch api-endpoints --json headSha,workflowName,conclusionUna trappola simile l’abbiamo trovata in un’altra pull request. Quando la pull request è andata in conflitto con la sua base, GitHub non ha creato il merge commit su cui girano i workflow, e dieci degli undici controlli non sono mai partiti. La pagina scriveva comunque «All checks have passed · 1 successful check», perché l’unico controllo che girava non aveva bisogno di quel commit. La regola è scritta nella documentazione di GitHub: in una pull request con un conflitto i workflow pull_request non girano.
Che cosa fa ora GitHub al posto tuo
Mettendo la documentazione di GitHub accanto a questi passi, il quadro è questo.
| Tema | Catena di branch a mano | Stack nativo di GitHub |
|---|---|---|
| Il branch superiore, dopo il merge del livello inferiore | Rebase a mano; dopo lo squash serve git rebase --onto | Rebase automatico |
| La base della pull request superiore | Spostata a mano sul branch principale | Torna da sola sul branch principale |
| Regole di protezione dei branch e CI | Spesso scattano solo sulla pull request più in basso | Valutate a ogni livello secondo il branch principale |
| I controlli dopo il rebase | Da noi non sono ripartiti; si vedeva il risultato del commit vecchio | Ripartono dopo «Rebase stack» e gh stack push |
Nella colonna «Catena di branch a mano» rebase, base e controlli vengono dalla nostra esperienza; la riga delle regole dalla documentazione di GitHub. Colonna «Stack nativo di GitHub»: documentazione di GitHub, 14 ottobre 2026.
Secondo la documentazione, rebase e base ora sono compito di GitHub. Per lo squash, la documentazione di gh stack descrive ciò che abbiamo visto noi: dopo lo squash i vecchi commit non sono nella cronologia del branch principale; gh stack sync riconosce il caso e fa il rebase con --onto.
Per i controlli la documentazione scrive chiaramente due casi: dopo il pulsante «Rebase stack» e dopo gh stack push la CI riparte. Per il rebase automatico che segue un merge parziale, il 14 ottobre 2026 non abbiamo trovato nulla di simile nella documentazione. Per questo, prima del merge di un livello superiore, conviene guardare queste quattro cose.

Come esaminare uno stack
Con uno stack non esamini più un unico grande diff, ma tanti diff piccoli, ognuno rispetto al livello sotto. Per chi fa la review cambiano tre cose.
- Parti dal basso. Il consiglio di GitHub è chiedere la review a partire dal basso quando i livelli sono strettamente legati: un errore in basso si propaga a ogni branch sopra. Se i livelli li esaminano persone diverse, si può anche procedere in parallelo.
- Non cercare il codice del livello inferiore nel diff di quello superiore. Se una funzione chiamata dal terzo livello è definita nel primo, nel diff non si vede, e in
mainnon c’è ancora. La definizione è nel branch stesso che stai esaminando; la mappa dello stack ti porta alla pull request di quel livello. - Scrivi il rilievo sul livello a cui appartiene. Secondo la documentazione la correzione si fa sul branch a cui appartiene la modifica, poi si fa il rebase dei branch sopra. Se il diff non cambia, il rebase non fa perdere le approvazioni esistenti.
gh stack checkout auth-layer # il livello a cui appartiene la correzione
git add .
git commit -m "Gestisci il caso del token scaduto"
gh stack rebase --upstack # rimette i branch superiori sopra questo commit
gh stack push # invia i branch con --force-with-leaseQueste regole valgono sia per una persona sia per uno strumento di review con IA: entrambi leggono il diff del livello. Approvare un livello non significa approvare quelli sotto; ogni pull request porta le sue approvazioni obbligatorie e i suoi controlli.
Non tutte le modifiche hanno bisogno di uno stack
Lo stack serve per lavori che si appoggiano l’uno sull’altro e sono troppo grandi per una review in una sola seduta. In questi casi è meglio un’unica pull request, o pull request indipendenti tra loro:
- Se la modifica è piccola. Dividere un diff che si legge in una seduta fa aprire pagine in più a chi fa la review.
- Se i lavori non dipendono l’uno dall’altro. Uno stack è un’unica catena lineare: ogni branch ha un solo branch sotto e al massimo uno sopra. Una correzione senza legami è una pull request a parte.
- Se il contributo arriva da un fork. Tutti i branch devono stare nello stesso repository; gli stack tra fork diversi non sono supportati.
- Se la CI è costosa. Ogni livello fa girare i propri controlli; prima limita i job costosi a certi livelli.
Nella documentazione che abbiamo letto il 14 ottobre 2026 ci sono altri tre limiti. GitHub Desktop non supporta gli stack. Gli strumenti che fanno il merge tramite API devono passare all’API di merge asincrona. Sull’auto-merge due pagine dicono cose diverse: la documentazione sul merge scrive che negli stack non è supportato, l’annuncio del 6 ottobre che arriverà nelle prossime settimane.
diffox esamina il diff della pull request che riceve. In uno stack ogni livello è una pull request a sé, quindi ognuno viene esaminato separatamente e i rilievi vengono scritti sulla pull request di quel livello.
Domande frequenti
Che cos’è una stacked pull request?
Le stacked pull request (pull request impilate) sono un modo di dividere una grande modifica in piccole pull request che si appoggiano l’una sull’altra. La pull request più in basso punta al branch principale, di solito main; ogni pull request successiva punta al branch di quella sotto. Ognuna mostra solo il diff del proprio livello e viene esaminata separatamente.
Come si crea una stacked pull request su GitHub?
Da riga di comando installa l’estensione con gh extension install github/gh-stack. gh stack init crea il primo branch, gh stack add i branch che vanno sopra; gh stack submit apre le pull request e le collega allo stack. Nell’interfaccia web basta dare alla seconda pull request come base il branch della prima e scegliere l’opzione «Create stack». Tutti i branch devono stare nello stesso repository.
Che cos’è gh stack?
gh stack è l’estensione di GitHub CLI pubblicata da GitHub che gestisce gli stack. Crea i branch nell’ordine giusto, fa il rebase a catena, fa il push, apre le pull request e ti fa spostare tra i livelli. Non è obbligatoria; uno stack si crea anche dall’interfaccia web.
Le stacked pull request sono ancora in public preview?
No. GitHub ha annunciato la funzione in public preview (anteprima pubblica) il 30 luglio 2026 e l’ha portata in disponibilità generale il 6 ottobre 2026. Secondo l’annuncio è disponibile su tutti i piani di github.com e arriverà in una prossima versione di GitHub Enterprise Server.
Che cosa succede alle pull request sopra dopo il merge di quella in basso?
Secondo la documentazione di GitHub restano aperte; la pull request successiva riceve un rebase automatico e punta direttamente al branch principale. Sono supportati tutti e tre i metodi di merge, squash compreso. I tuoi branch locali li aggiorna gh stack sync: riconosce la situazione dopo uno squash e fa il rebase con --onto.
Come funzionano CI e regole di protezione dei branch nelle stacked pull request?
Ogni pull request dello stack, a qualunque branch punti direttamente, viene valutata secondo le regole del branch principale dello stack: approvazioni obbligatorie, controlli obbligatori e CODEOWNERS si applicano a ogni livello. I workflow pull_request diretti a main girano per ogni livello. Per il merge di un livello, anche tutti i livelli sotto devono rispettare le condizioni.
diffox esamina le stacked pull request?
diffox esamina il diff della pull request che riceve. Ogni livello dello stack è una pull request a sé, quindi ogni livello viene esaminato con il proprio diff. Non fa un trattamento speciale per gli stack, e non serve nessuna impostazione in più.