2016-04-29 12 views

risposta

5

Questa è, in effetti, una domanda molto buona, perché commette le istantanee.

La ragione rebase funziona è perché rebase è effettivamente ripetuto git cherry-pick (con un po 'di avvolgere sul davanti per capire cosa scegliere, e più alla fine di spostare le etichette ramo) e git cherry-pick opere girando una impegnarsi in un set di modifiche.

Supponiamo per esempio di avere questa sequenza di commit:

  A--B--C <-- topic 
     /
...--o--*--o--o  <-- mainline 

Per rebase topic sul mainline abbiamo bisogno di (1) trovare i commit che sono sul topic ma non su mainline (che sono C, B e A lungo la riga superiore, che termina con il commit contrassegnato con *), quindi (2) copiarli in nuovi commit che verranno aggiunti sotto la punta di mainline.

Rebase trova primo dei tre post-* commit e li mette in un (reverse ordinato: A, B, C) Lista (si omette anche unire i commit per impostazione predefinita ma non ci sono unioni qui). Quindi esegue un cherry pick per ogni commit.

A cherry-pick A, Git diffs A contro *. Questo trasforma le due istantanee in changeset. Git quindi applica le modifiche alla punta più a commit mainline e fa un nuovo commit, chiamiamolo A', su un ramo di anonimo:

  A--B--C <-- topic 
     /
...--o--*--o--o  <-- mainline 
       \ 
       A' <-- HEAD 

Per cherry-pick B, Git diff B contro A. L'applicazione di queste modifiche a A' produce un altro commit B'. Ripetere l'operazione per C di ottenere C':

  A--B--C   <-- topic 
     /
...--o--*--o--o   <-- mainline 
       \ 
       A'-B'-C' <-- HEAD 

scorso, Git bucce l'etichetta topic lontano da C e la punta a C' invece. La vecchia catena è abbandonato (anche se è ancora possibile trovare attraverso reflogs, e rebase copia l'ID del C al nome speciale ORIG_HEAD così):

  A--B--C   [abandoned] 
     /
...--o--*--o--o   <-- mainline 
       \ 
       A'-B'-C' <-- topic 

e ora il rebase è completo.

Nota che ogni copia viene eseguita utilizzando i meccanismi di fusione di git, se necessario (se i diff non si applicano in modo pulito subito). Ognuno può provocare un conflitto di merge, richiedendo il rebase di fermarsi e ottenere aiuto da voi. (O, peggio, puoi ottenere un mis-merge, anche se questi sono rari nella pratica.)

Ovviamente, se si riordina il commit (spostando le linee pick in un rebase interattivo), si modifica solo l'ordine che selezioniamo e si applica ogni commit. Le operazioni cherry-pick funzionano ancora allo stesso modo: confronta il commit selezionato con il suo genitore (C vs B, A vs *, B vs A).

+0

Ma i dati diffs dipendono dal contenuto del file nel commit precedente, che cambierebbe dopo averli riordinati. Oppure questo riordino è solo cosmetico? –

+0

Le nuove copie sono * nuove copie *, con tutto ciò che questo implica. Supponiamo, ad esempio, che mentre si preme il selettore 'B' si verifichi un conflitto di unione perché la punta di' mainline' ha una modifica in conflitto. Quando correggi il conflitto e continua il rebase, il nuovo commit 'B'' ora ha una diversa modifica rispetto al commit originale' B'. Sia 'B' che' B'' sono ancora nel repository, e il prossimo cherry-pick (supponendo che sia per 'C') confronta' C' a 'B' prima di provare ad applicare quella modifica a' B'' (che può ottenere un altro conflitto di fusione poiché 'B'' è ora diverso!). – torek

+0

Penso di vederlo ora dopo aver letto il tuo commento e riletto la tua risposta. Sembra che sia stato appena respinto dalla terminologia. Come ora lo vedo, certo, i commit possono essere riordinati, ma i commit successivi dopo un rebase sono completamente nuovi se lo hai riordinato o meno. Questo risultato commesso ha anche un "file di snapshot" diverso che è il risultato dell'applicazione del diff solo dal cherry-picking alla punta della mainline. In questo modo, il riordino è cosmetico poiché i commit originali che sono stati riordinati rimangono invariati. Per favore fatemi sapere se ho ragione. –

Problemi correlati