Come selezionare più commit

Ho due rami. Commit a è la testa di uno, mentre l’altro ha b , c , d , f sulla cima di a . Voglio spostare c , d , e ed f al primo ramo senza commit b . Usando cherry pick è facile: checkout primo ramo cherry-pick uno per uno c f e rebase secondo ramo sul primo. Ma esiste un modo per selezionare tutti cf in un unico comando?

Ecco una descrizione visiva dello scenario (grazie JJD ):

inserisci la descrizione dell'immagine qui

Git 1.7.2 ha introdotto la capacità di cherrypick una serie di commit. Dalle note di rilascio :

git cherry-pick “ha imparato a scegliere una serie di commit (ad esempio” cherry-pick A..B “e” cherry-pick –stdin “), così ha fatto” git revert “, questi non supportano il controllo di sequencing più bello” rebase [-i] “ha, però.


Compresi commenti importanti (crediti ai rispettivi autori)

Nota 1: Nel modulo “cherry-pick A..B”, A dovrebbe essere più vecchio di B. Se l’ordine è sbagliato, il comando fallirà silenziosamente. – Damiano

Nota 2: Inoltre, questo non selezionerà A, ma piuttosto tutto dopo A fino a e incluso B. – JB Rainsberger

Nota 3: per includere A basta digitare git cherry-pick A ^ .. B – sschaef

Il modo più semplice per farlo è con l’opzione on rebase . Supponiamo che il ramo a cui finisce la corrente a sia chiamato mybranch e questo è il ramo su cui vuoi spostare cf .

 # checkout mybranch git checkout mybranch # reset it to f (currently includes a) git reset --hard f # rebase every commit after b and transplant it onto a git rebase --onto ab 

Oppure la one-liner richiesta:

 git rebase --onto abf 

È ansible utilizzare una combinazione seriale di git rebase e git branch per applicare un gruppo di commit su un altro ramo. Come già pubblicato da wolfc, il primo comando copia effettivamente i commit. Tuttavia, la modifica non è visibile fino a quando non si aggiunge il nome di un ramo alla maggior parte dei commit del gruppo.

Si prega di aprire l’immagine in una nuova scheda …

Flusso di lavoro

Per riepilogare i comandi in forma di testo:

  1. Apri gitk come processo indipendente usando il comando: gitk --all & .
  2. Esegui git rebase --onto abf .
  3. Premere F5 in gitk . Niente cambia. Ma nessun HEAD è segnato.
  4. Esegui la git branch selection
  5. Premere F5 in gitk . Appare il nuovo ramo con i suoi commit.

Questo dovrebbe chiarire le cose:

  • Commit a è la nuova destinazione principale del gruppo.
  • Commit b è il commit prima del primo commit del gruppo (esclusivo).
  • Commit f è l’ultimo commit del gruppo (incluso).

Successivamente, è ansible utilizzare la funzionalità di git checkout feature && git reset --hard b per eliminare i commit c f dal ramo della feature .

Oltre a questa risposta, ho scritto un post sul blog che descrive i comandi in un altro scenario che dovrebbe aiutare a usarlo in generale.

Per applicare i commenti di JB Rainsberger e sschaef per rispondere in modo specifico alla domanda … Per utilizzare un intervallo di selezione delle ciliegie in questo esempio:

 git checkout a git cherry-pick b..f 

o

 git checkout a git cherry-pick c^..f 
 git rev-list --reverse b..f | xargs -n 1 git cherry-pick 
 git format-patch --full-index --binary --stdout range... | git am -3 

Se hai delle revisioni selettive da unire, ad esempio A, C, F, J da A, B, C, D, E, F, G, H, I, J commetti, usa semplicemente il comando seguente:

git cherry-pick ACFJ

In realtà, il modo più semplice per farlo potrebbe essere

  1. salva la fusione tra i due rami MERGE_BASE=$(git merge-base branch-a branch-b)
  2. avanti veloce o rebase il ramo più vecchio sul ramo più nuovo
  3. rebase il ramo risultante su se stesso, iniziando dalla base di unione del passaggio 1 e rimuovendo manualmente i commit che non sono desiderati:

     git rebase ${SAVED_MERGE_BASE} -i 

    In alternativa, se ci sono solo pochi nuovi commit, salta il passaggio 1 e usa semplicemente

     git rebase HEAD^^^^^^^ -i 

    nel primo passaggio, usando abbastanza ^ per oltrepassare la base unione.

Vedrai qualcosa di simile nel rebase interattivo:

 pick 3139276 commit a pick c1b421d commit b pick 7204ee5 commit c pick 6ae9419 commit d pick 0152077 commit e pick 2656623 commit f 

Quindi rimuovi le linee b (e tutte le altre che vuoi)