git cherry-pick
Scopri il comando git cherry-pick per copiare commit singoli da un branch a un altro. Opzioni, gestione dei conflitti ed esempi.
Cosa fa git cherry-pick
Il comando git cherry-pick prende la modifica introdotta da uno o più commit esistenti e la riapplica sul branch corrente come un nuovo commit. Mentre git merge e git rebase spostano intere linee di storia in una sola volta, cherry-pick ti permette di prendere un singolo commit e inserirlo esattamente dove ne hai bisogno.
Questa pagina spiega come funziona cherry-pick internamente, come selezionare un singolo commit o un intervallo, le opzioni più utili, come risolvere i conflitti e quando preferire cherry-pick rispetto a un merge o a git revert.
Come funziona
Un commit è uno snapshot, ma cherry-pick lo tratta come una patch: calcola il diff tra il commit e il suo parent, poi applica quel diff alla cima del branch corrente e registra un nuovo commit. Il nuovo commit mantiene il messaggio originale, l'autore e la data, ma ottiene un nuovo hash e un nuovo parent perché ora si trova in un punto diverso della storia.
Questa differenza è il concetto fondamentale: cherry-pick copia una modifica, non la sposta. Il commit sorgente rimane esattamente dove si trovava sul suo branch originale.
git switch main
git cherry-pick a1b2c3dLa modifica del commit a1b2c3d è ora su main come un commit nuovo di zecca.
Un esempio pratico
Supponiamo che un hotfix sia stato committato su feature ma appartenga in realtà a main. Prima trova l'hash del commit con git log:
git switch feature
git log --oneline
# d9ae654 fix login redirect
# 7c1a902 work in progress
# fa42ab5 baseOra passa a main e copia solo quel commit:
git switch main
git cherry-pick d9ae654[main 02bbf3e] fix login redirect
1 file changed, 1 insertion(+)Nota il nuovo hash 02bbf3e — la correzione è ora su main come un commit nuovo, mentre d9ae654 esiste ancora intatto su feature.
Selezionare un intervallo di commit
Puoi applicare più commit in un'unica operazione. Un intervallo copia tutti i commit dopo il primo fino all'ultimo incluso:
git cherry-pick a1b2c3d..f4e5d6cQuesto esclude a1b2c3d stesso. Per rendere l'intervallo inclusivo del commit iniziale, aggiungi il suffisso ^ in modo che l'intervallo inizi dal suo parent:
git cherry-pick a1b2c3d^..f4e5d6cI commit vengono applicati uno alla volta, in ordine; se uno di essi genera un conflitto, cherry-pick si interrompe su quel commit così puoi risolverlo prima di continuare.
Opzioni comuni
| Comando | Descrizione |
|---|---|
git cherry-pick <commit> | Applica la modifica di <commit> come un nuovo commit sul branch corrente. |
git cherry-pick -n <commit> | Applica la modifica ma non effettua il commit, lasciandola in staging così puoi revisionarla o modificarla prima di committare. |
git cherry-pick -x <commit> | Aggiunge una riga (cherry picked from commit …) al messaggio — utile sui branch pubblici affinché altri possano tracciare l'origine. |
git cherry-pick -e <commit> | Apre il tuo editor per modificare il messaggio del commit prima che venga registrato. |
git cherry-pick --continue | Riprende l'operazione dopo aver risolto i conflitti. |
git cherry-pick --skip | Salta il commit corrente (ad esempio, quando la sua modifica è già presente) e prosegue. |
git cherry-pick --abort | Annulla l'operazione e ripristina il branch allo stato originale. |
Con -x il messaggio registrato appare così:
fix login redirect
(cherry picked from commit d9ae65426adbde425c3e386a32297e9e833d8816)Gestione dei conflitti
Se la modifica non si applica correttamente, cherry-pick si interrompe come farebbe un merge e lascia i marcatori di conflitto nei file interessati. Vedrai:
CONFLICT (content): Merge conflict in app.js
error: could not apply d9ae654... fix login redirect
hint: ... fix conflicts and then run "git cherry-pick --continue".Risolvi manualmente i file in conflitto, aggiungili allo stage con git add, quindi continua:
git add app.js
git cherry-pick --continueIn questo momento sono disponibili tre vie d'uscita:
git cherry-pick --continue— termina dopo aver risolto i conflitti.git cherry-pick --skip— scarta il commit corrente e passa al successivo nell'intervallo.git cherry-pick --abort— annulla tutto e riporta il branch al punto di partenza.
Usa git status in qualsiasi momento per vedere quali file sono ancora in conflitto.
Quando usarlo
Cherry-pick è particolarmente utile quando:
- Una correzione è finita sul branch sbagliato e ne hai bisogno altrove.
- Stai eseguendo il backporting di una singola patch su un branch di release o di manutenzione.
- Vuoi un solo commit da un branch feature senza fare il merge di tutto il branch.
Cherry-pick vs. merge, rebase e revert
| Obiettivo | Usa |
|---|---|
| Copiare uno (o pochi) commit specifici su un altro branch | git cherry-pick |
| Integrare l'intera storia di un branch | git merge |
| Spostare i commit di un branch su una nuova base | git rebase |
| Annullare un commit registrando un commit opposto | git revert |
Possibili problemi
- Duplicati nella storia condivisa. Eseguire cherry-pick su un branch che verrà poi unito alla sorgente crea due commit con la stessa modifica. Git di solito è abbastanza intelligente da saltare il duplicato al momento del merge, ma può complicare la storia — preferisci merge o rebase quando vuoi l'intero branch.
- Risultati vuoti. Se la modifica è già presente nel branch di destinazione, cherry-pick si ferma con
The previous cherry-pick is now empty. Usagit cherry-pick --skipper continuare, oppure--abortper annullare. - Nuovo hash, non quello originale. Poiché il commit viene ricreato, il suo hash cambia. Aggiungi
-xaffinché il messaggio registri la provenienza.