Dato che il tempo ha git cherry-pick
imparato ad essere in grado di applicare più commit, la distinzione in effetti è diventata alquanto discutibile, ma questa è qualcosa che può essere chiamata evoluzione convergente ;-)
La vera distinzione sta nell'intento originale di creare entrambi gli strumenti:
git rebase
Il compito è di inoltrare una serie di modifiche che uno sviluppatore ha nel proprio repository privato, create contro la versione X di qualche branch upstream, alla versione Y di quello stesso branch (Y> X). Questo cambia effettivamente la base di quella serie di commit, quindi "rebasing".
(Consente inoltre allo sviluppatore di trapiantare una serie di commit su qualsiasi commit arbitrario, ma questo è di uso meno ovvio.)
git cherry-pick
serve per portare un impegno interessante da una linea di sviluppo a un'altra. Un esempio classico è il backport di una correzione di sicurezza effettuata su un ramo di sviluppo instabile su un ramo stabile (di manutenzione), dove a merge
non ha senso, poiché porterebbe un sacco di modifiche indesiderate.
Fin dalla sua prima apparizione, git cherry-pick
è stato in grado di selezionare più commit contemporaneamente, uno per uno.
Quindi, forse la differenza più evidente tra questi due comandi è il modo in cui trattano il ramo su cui lavorano: di git cherry-pick
solito porta un commit da qualche altra parte e lo applica sopra il tuo ramo corrente, registrando un nuovo commit, mentre git rebase
prende il tuo ramo corrente e riscrive una serie del proprio suggerimento si impegna in un modo o nell'altro. Sì, questa è una descrizione molto stupida di ciò che git rebase
può fare, ma è intenzionale, per cercare di far penetrare l'idea generale.
Aggiorna per spiegare ulteriormente un esempio di utilizzo git rebase
in discussione.
Data questa situazione,
The Book afferma:
Tuttavia, c'è un altro modo: puoi prendere la patch della modifica introdotta in C3 e riapplicarla sopra C4. In Git, questo si chiama ribasamento. Con il comando rebase, puoi prendere tutte le modifiche che sono state salvate su un ramo e applicarle su un altro.
In questo esempio, dovresti eseguire quanto segue:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
"Il problema" qui è che in questo esempio, il ramo "esperimento" (l'argomento per ribasare) è stato originariamente biforcato dal ramo "principale", e quindi condivide i commit da C0 a C2 con esso - effettivamente, "esperimento" è " master "fino a, e incluso, C2 più commit C3 su di esso. (Questo è il caso più semplice possibile; ovviamente, "esperimento" potrebbe contenere diverse dozzine di commit in cima alla sua base originale.)
Ora git rebase
viene detto di riassumere "esperimento" sull'attuale punta di "maestro", e funziona git rebase
così:
- Corre
git merge-base
per vedere qual è l'ultimo commit condiviso sia da "experiment" che da "master" (qual è il punto di diversione, in altre parole). Questo è C2.
- Salva via tutti i commit effettuati dal punto di deviazione; nel nostro esempio di giocattoli, è solo C3.
- Riavvolge la TESTA (che punta al commit di punta di "esperimento" prima che l'operazione inizi) per puntare alla punta di "maestro" - ci stiamo ribasando su di essa.
- Tenta di applicare ciascuno dei commit salvati (come se fosse con
git apply
) in ordine. Nel nostro esempio di giocattolo è solo un commit, C3. Diciamo che la sua applicazione produrrà un commit C3 '.
- Se tutto è andato bene, il riferimento "esperimento" viene aggiornato per puntare al commit derivante dall'applicazione dell'ultimo commit salvato (C3 'nel nostro caso).
Ora torna alla tua domanda. Come puoi vedere, qui tecnicamente git rebase
infatti trapianta una serie di commit da "esperimento" alla punta di "maestro", quindi puoi giustamente dire che c'è davvero "un altro ramo" nel processo. Ma il succo è che il tip commit da "experiment" è finito per essere il nuovo tip commit in "experiment", ha semplicemente cambiato la sua base:
Di nuovo, tecnicamente puoi dire che git rebase
qui sono incorporati alcuni commit da "master", e questo è assolutamente corretto.