Come copiare i commit da un ramo all'altro?


728

Ho due rami dal mio padrone:

  • v2.1 : (versione 2) ci sto lavorando da diversi mesi
  • wss : che ho creato ieri per aggiungere una funzionalità specifica al mio master (in produzione)

C'è un modo per copiare i commit di ieri da wss a v2.1?


Per copiare semplicemente commit (o un intervallo di commit) da un ramo all'altro questa risposta mi ha aiutato meglio: stackoverflow.com/questions/1994463/...
Caramba

Risposte:


566

Dovresti davvero avere un flusso di lavoro che ti consenta di fare tutto unendo:

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (wss)

Quindi tutto quello che devi fare è git checkout v2.1e git merge wss. Se per qualche motivo non puoi davvero farlo, e non puoi usare git rebase per spostare il tuo ramo wss nel posto giusto, il comando per prendere un singolo commit da qualche parte e applicarlo altrove è git cherry-pick . Basta controllare il ramo su cui si desidera applicare ed eseguire git cherry-pick <SHA of commit to cherry-pick>.

Alcuni dei modi in cui rebase potrebbe salvarti:

Se la tua storia è simile a questa:

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (v2-only) - x - x - x (wss)

Puoi usare git rebase --onto v2 v2-only wssper spostare wss direttamente su v2:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - x - x (v2-only)
           \
             x - x - x (wss)

Quindi puoi unire! Se davvero, davvero, davvero non riesci ad arrivare al punto in cui puoi unirti, puoi comunque usare rebase per fare efficacemente diverse scelte di ciliegie contemporaneamente:

# wss-starting-point is the SHA1/branch immediately before the first commit to rebase
git branch wss-to-rebase wss
git rebase --onto v2.1 wss-starting-point wss-to-rebase
git checkout v2.1
git merge wss-to-rebase

Nota: il motivo per cui è necessario un lavoro extra per farlo è che sta creando commit duplicati nel tuo repository. Questa non è davvero una buona cosa: il punto centrale di una semplice ramificazione e fusione è quello di essere in grado di fare tutto, rendendo gli impegni in un posto e fondendoli ovunque siano necessari. I commit duplicati significano l'intenzione di non unire mai quei due rami (se decidi di volerlo in seguito, otterrai dei conflitti).


1
Non potrei essere più d'accordo con questa risposta. +1. Vedi anche il mio vecchio risposta illustra le conseguenze di ciliegia-picking: stackoverflow.com/questions/881092/...
VonC

18
Superba risposta su come farlo nel modo giusto ! Vorrei poter votare due volte anche per lo sforzo di creare diagrammi ASCII.
gotgenes,

@VonC: Grazie per il supporto e le informazioni extra sul perché non scegliere la ciliegia - So di essermi risparmiato un po 'lì. @gotgenes: grazie! Penso che ne valga la pena, basta guardare la manpage git-rebase. Non c'è modo migliore per spiegarlo.
Cascabel,

Per quanto riguarda il motivo per cui potresti non essere in grado di unire - L'unione di Git non funziona bene con git-svn. Per copiare una serie di commit da un ramo SVN a un altro, ho finito per selezionarli e quindi eseguire un rebase / reword interattivo per rimuovere i git-svn-idriferimenti errati prima di dcommitreimpostarli. Anche se probabilmente avrei potuto tralasciare il passo della scelta della ciliegia e usare un rebase da solo.
Bob,

1
Ecco il mio caso d'uso: le correzioni di bug critiche sono state impegnate nel ramo funzionalità. Ne ho bisogno in master per andare in produzione ora. Questo mi salverà il culo.
Capitano Hypertext,

910

Uso

git cherry-pick <commit>

da applicare <commit>alla tua attuale filiale .

Io stesso probabilmente verificherei i commit che seleziono gitke li selezionerei con un clic destro sulla voce commit lì.


Se vuoi andare più automatico (con tutti i suoi pericoli) e supponendo che tutti i commit da ieri siano avvenuti su wss, potresti generare l'elenco dei commit usando git log(con --prettysuggerito da Jefromi)

git log --reverse --since=yesterday --pretty=%H

quindi tutto insieme supponendo che tu usi bash

for commit in $(git log --reverse --since=yesterday --pretty=%H);
do
    git cherry-pick $commit
done

Se qualcosa va storto qui (c'è un sacco di potenziale) sei nei guai poiché funziona sul checkout dal vivo, quindi fai delle scelte manuali o usa rebase come suggerito da Jefromi.


Tutti i segnaposto per l'opzione --pretty si trovano nella manpage git-log. È possibile ottenere qualsiasi formato desiderato, particolarmente utile per ottenere i campi desiderati per uno script in una forma facilmente analizzabile.
Cascabel,

Vorrei anche sottolineare che, supponendo che tu voglia davvero creare commit duplicati, il metodo utilizzato git rebasenella mia risposta è più solido. In particolare, usando un ciclo for come questo, se una delle scelte Cherry fallisce, proverà comunque a fare tutto il resto. Questo è ... molto, non molto buono, diciamo.
Cascabel,

2
Concordato. Ecco perché non lo uso mai, ma lo faccio manualmente. Ma cherry-pick è ancora la risposta, almeno al titolo della domanda. Ho modificato la risposta.
Benjamin Bannier,

1
Qualcuno si è impegnato in un ramo vecchio / errato e cherry-pick mi ha permesso di inserire quel commit nel ramo giusto (mantenendoli comunque come committer). Perfetto.
Patrick,

8
Uno spettacolo raro, una gitrisposta semplice e diretta alla soluzione, invece di vagare nelle complessità di git per dimostrare quanto bene il rispondente lo sappia.
Przemek D

74

git cherry-pick : Applica le modifiche introdotte da alcuni commit esistenti

Supponiamo di avere il ramo A con commit (X, Y, Z). Abbiamo bisogno di aggiungere questi si impegna in ramo B . Useremo le cherry-pickoperazioni.

Quando usiamo cherry-pick, dovremmo aggiungere commit sul ramo B nello stesso ordine cronologico che i commit appaiono in Branch A .

cherry-pick supporta una serie di commit, ma se hai commit di fusione in quell'intervallo, diventa davvero complicato

git checkout B
git cherry-pick SHA-COMMIT-X
git cherry-pick SHA-COMMIT-Y
git cherry-pick SHA-COMMIT-Z

Esempio di flusso di lavoro:

inserisci qui la descrizione dell'immagine

Possiamo usare cherry-pickcon le opzioni

-e o --edit : con questa opzione, git cherry-pick ti permetterà di modificare il messaggio di commit prima del commit.

-n o --no-commit : di solito il comando crea automaticamente una sequenza di commit. Questo flag applica le modifiche necessarie per selezionare ogni commit denominato nel tuo albero di lavoro e nell'indice, senza effettuare alcun commit. Inoltre, quando viene utilizzata questa opzione, l'indice non deve corrispondere al commit HEAD. La scelta della ciliegia viene eseguita in base allo stato iniziale dell'indice.

Ecco un interessante articolo riguardante cherry-pick.


19

È possibile creare una patch dagli commit che si desidera copiare e applicare la patch al ramo di destinazione.


16
Anche se per qualche motivo vuoi davvero usare patch (es) invece di cherry-pick (s) / rebase, il modo più semplice per farlo è con git format-patch <revision range>e git am *.patch.
Cascabel,

Richiede checkouta un altro ramo.
CoolMind il

12

O se sei un po 'meno dalla parte dell'evangelista, puoi fare un po' brutto modo che sto usando. In deploy_template ci sono commit che voglio copiare sul mio master come branch deploy

git branch deploy deploy_template
git checkout deploy
git rebase master

Questo creerà il nuovo branch deploy (io uso -f per sovrascrivere il branch deploy esistente) su deploy_template, quindi ridisegnare questo nuovo branch sul master, lasciando deploy_template intatto.


1

Per il semplice caso di copiare l'ultimo commit dal ramo wss alla v2.1, puoi semplicemente prendere l'id commit ( git log --oneline | head -n 1) e fare:

git checkout v2.1
git merge <commit>

Ciò richiede il check-out in un altro ramo.
CoolMind

1

Il comando cherry-pick può leggere l'elenco dei commit dall'input standard.

Il seguente comando cherry-picks esegue il commit creato dall'utente John che esiste nel ramo "sviluppo" ma non nel ramo "rilascio", e lo fa in ordine cronologico.

git log develop --not release --format=%H --reverse --author John | git cherry-pick --stdin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.