← Torna al blog

Git cherry-pick spiegato: quando usarlo (e quando no)

tutorial git

Che cos'è Git Cherry-Pick?

Una correzione critica è appena arrivata sulla tua branch di sviluppo -- ma lo stesso bug è in produzione. Non puoi fare il merge dell'intera branch di sviluppo nella branch di release, perché è piena di funzionalità a metà. Quello che ti serve davvero è prendere quel singolo commit e applicarlo altrove. È esattamente ciò che fa git cherry-pick.

Il cherry-pick prende le modifiche introdotte da un commit esistente e le riproduce sulla tua branch corrente come un commit completamente nuovo. Il nuovo commit contiene lo stesso diff e, per impostazione predefinita, lo stesso messaggio, ma ha un genitore diverso e quindi uno SHA diverso. Questo dettaglio conta più di quanto sembri: Git identifica i commit tramite il loro SHA, quindi dopo un cherry-pick il tuo repository contiene due commit distinti che introducono la stessa modifica. Tienilo a mente -- spiega sia perché il cherry-pick è così utile, sia perché abusarne causa problemi in seguito.

Quando il cherry-pick è lo strumento giusto

Retroportare un hotfix su una branch di release

È il caso classico. Hai corretto un bug su main, ma i tuoi utenti usano la versione 2.3 e hanno bisogno della correzione subito. Fai il cherry-pick della correzione sulla branch di release:

git switch release/2.3
git cherry-pick a1b2c3d

La branch di release riceve esattamente quella correzione, e nient'altro da main si aggiunge di nascosto.

Un commit è finito sulla branch sbagliata

Volevi fare il commit sulla tua branch di feature, ma eri su main. Il cherry-pick offre un recupero pulito: passa alla branch dove il commit deve stare, fai lì il cherry-pick, poi torna indietro e rimuovilo dalla branch dove non c'entra nulla. Se il passaggio di rimozione ti lascia dubbi, la nostra guida su come annullare un commit Git copre ogni opzione nel dettaglio.

Salvare una correzione da una branch abbandonata

A volte un esperimento non porta da nessuna parte, ma un commit nel mezzo della branch correggeva un bug reale. Invece di fare il merge di una branch senza futuro, fai il cherry-pick dell'unico commit di valore sulla tua branch attiva e lascia che il resto dell'esperimento venga eliminato in pace.

Uso di base

La forma più semplice prende un singolo commit:

git cherry-pick a1b2c3d

Git applica le modifiche di quel commit e crea immediatamente un nuovo commit sulla tua branch corrente, riutilizzando il messaggio originale. Puoi anche passare più commit in una volta, e Git li applica uno a uno, nell'ordine in cui li elenchi:

git cherry-pick a1b2c3d f4e5d6c

Opzioni pratiche da conoscere

-x: registrare la provenienza del commit

Quando retroporti, in seguito vorrai sapere da dove proviene un commit. L'opzione -x aggiunge una riga come (cherry picked from commit a1b2c3d...) al messaggio del nuovo commit:

git cherry-pick -x a1b2c3d

Fanne un'abitudine per qualsiasi cherry-pick tra branch pubbliche di lunga durata. Tra sei mesi, quella singola riga ti dirà all'istante se una correzione è arrivata in una release e da dove proveniva.

Prendere un intervallo di commit

Puoi fare il cherry-pick di un intero intervallo con la sintassi a due punti:

git cherry-pick A..B

Attenzione: questo applica i commit successivi ad A, fino a B incluso. A stesso è escluso. Se vuoi includere A, scrivi:

git cherry-pick A^..B

Il ^ significa "il genitore di A", il che rimette A dentro l'intervallo. Confondere queste due sintassi è uno degli errori più comuni con il cherry-pick.

--no-commit: applicare senza fare commit

A volte vuoi le modifiche ma non un commit automatico -- per esempio per combinare più commit prelevati in uno solo, o per sistemare il risultato prima del commit:

git cherry-pick --no-commit a1b2c3d

Le modifiche arrivano nella tua directory di lavoro e nell'area di staging, e crei il commit tu stesso quando sei pronto.

Gestire i conflitti durante un cherry-pick

Un cherry-pick può andare in conflitto per la stessa ragione di un merge: il commit che stai prelevando è stato scritto su un codice diverso da quello della tua branch corrente. Quando succede, Git si ferma a metà operazione e contrassegna i file in conflitto:

error: could not apply a1b2c3d... fix login timeout
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue"

Ora hai tre vie d'uscita:

  • git cherry-pick --continue -- dopo aver modificato i file in conflitto e averli aggiunti allo staging con git add, questo completa il cherry-pick e crea il commit.
  • git cherry-pick --abort -- annulla l'intera operazione e riporta la tua branch esattamente allo stato in cui era prima di iniziare. Niente è perso, niente è applicato.
  • git cherry-pick --skip -- quando preleva più commit, salta quello corrente e passa al successivo. Utile quando un commit dell'intervallo risulta già applicato o irrilevante.

La risoluzione dei conflitti in sé funziona esattamente come per un conflitto di merge: apri ogni file in conflitto, scegli tra gli hunk concorrenti (o combinali), rimuovi i marcatori di conflitto e aggiungi il file allo staging. Se i marcatori di conflitto ti intimidiscono ancora, la nostra guida su come risolvere visivamente i conflitti di merge Git vale anche per i cherry-pick.

Cosa NON fare con il cherry-pick

Non fare il cherry-pick di branch intere

Se ti ritrovi a fare il cherry-pick di cinque, dieci, venti commit da una branch all'altra, fermati. È per questo che esistono merge e rebase. Entrambi spostano il lavoro tra branch lasciando che Git capisca la relazione che le lega, il che mantiene le operazioni future semplici e senza conflitti. Se non sai quale dei due si adatta al tuo flusso di lavoro, il nostro confronto rebase vs merge passa in rassegna i compromessi.

La cronologia duplicata si fa sentire più tardi

Ricorda: un cherry-pick crea un nuovo commit con un nuovo SHA, e Git non conserva alcuna traccia formale del fatto che i due commit rappresentano "la stessa modifica". Se fai il cherry-pick di commit da una branch di feature verso main e più tardi fai comunque il merge di quella branch, Git deve riconciliare due copie delle stesse modifiche. Spesso ci riesce in silenzio. Ma non appena una delle copie è stata modificata in seguito, ottieni conflitti sconcertanti in cui i due lati sembrano quasi identici -- e la tua cronologia mostra la stessa modifica due volte, con due date e due SHA, il che rende più difficile ragionare con strumenti come git log e git bisect.

Una buona regola pratica: il cherry-pick serve a spostare eccezioni -- un hotfix, un commit fuori posto, una correzione salvata. Nel momento in cui diventa il tuo modo abituale di spostare lavoro tra branch, la tua cronologia ti sta dicendo che la strategia di branching va ripensata.

Il cherry-pick in GitSquid

In GitSquid, il cherry-pick si trova dove te lo aspetteresti: clic destro su qualsiasi commit nel grafo dei commit e scegli l'opzione cherry-pick dal menu contestuale. Niente più SHA da copiare avanti e indietro tra un log e un terminale.

Il vantaggio più grande è sapere a cosa vai incontro. Il Conflict Predictor di GitSquid -- gratuito per tutti -- mostra esattamente quali file andranno in conflitto prima di eseguire un merge, un rebase o un cherry-pick, con anteprime degli hunk ed evidenziazione della sintassi. Invece di scoprire i conflitti a metà di un'operazione, li vedi in anticipo e puoi decidere se procedere, scegliere un altro commit o preparare la risoluzione con calma.

E quando un cherry-pick va davvero in conflitto, "Resolve in scratch worktree" apre un worktree temporaneo come nuova scheda, così puoi risolvere tutto lì mentre il tuo checkout attivo resta intatto.

Riferimento rapido

Comando Cosa fa
git cherry-pick <sha> Applica un commit sulla branch corrente
git cherry-pick <sha1> <sha2> Applica più commit, in ordine
git cherry-pick -x <sha> Aggiunge lo SHA di origine al messaggio del commit
git cherry-pick A..B Prende i commit dopo A fino a B (A escluso)
git cherry-pick A^..B Prende l'intervallo includendo A
git cherry-pick --no-commit <sha> Applica le modifiche senza fare commit
git cherry-pick --continue Completa il pick dopo aver risolto i conflitti
git cherry-pick --abort Annulla e ripristina la branch com'era
git cherry-pick --skip Salta il commit corrente, continua con il resto

Il cherry-pick è un bisturi, non una pala. Usato per l'estrazione precisa e occasionale -- il retroporting di un hotfix, un commit fuori posto, una correzione salvata -- è uno dei comandi più soddisfacenti di Git. Usato come sostituto del merge, riempie silenziosamente la tua cronologia di duplicati che torneranno a perseguitarti. Conosci la differenza, aggiungi -x quando retroporti, e tieni a mente --abort come via di fuga.

Vuoi vedere quali file andranno in conflitto prima ancora di iniziare? Scarica GitSquid gratis e lascia che il Conflict Predictor elimini le incognite dal tuo prossimo cherry-pick.