Estrai tutti i commit da un ramo, sposta i commit specificati in un altro


102

Ho i seguenti rami:

  • master
  • production

e le seguenti filiali remote:

  • origin/master
  • origin/production

Ho uno script che recupera il origin/masterramo e ottiene il diff di ciò che è cambiato dal mio ultimo fetch ( log -p master..origin/master). Poi mi unisco origin/master.

I commit trovati vengono inviati a uno strumento di revisione del codice.

Voglio spingere gli impegni di successo - e solo loro - al ramo di produzione, e poi ovviamente a origin/production.

Come posso farlo?

Inoltre, ho 2 script in esecuzione: quello che recupera da origin/master, invia i dettagli dei commit a un database e unisci, e l'altro che sto attualmente scrivendo che dovrà inviare i commit riusciti.

Mi piacerebbe avere quei 2 script in esecuzione evitando le condizioni di gara / conflitti di unione. Dato che voglio lavorare solo con commit specifici, forse c'è un modo per sbarazzarmi dei commit che non voglio?


Cosa intendi per "commit di successo"?
bdonlan

quello che è stato rivisto e contrassegnato come riuscito. non importa davvero qui, l'importante è che ci siano commit che voglio mantenere e spingere su un altro ramo, e altri di cui voglio sbarazzarmi / ignorare.
Sylvain

Risposte:


313

Il termine che penso tu stia cercando è un "cherry pick". Cioè, prendi un singolo commit dal centro di un ramo e aggiungilo a un altro:

A-----B------C
 \
  \
   D

diventa

A-----B------C
 \
  \
   D-----C'

Questo, ovviamente, può essere fatto con il comando git cherry-pick.

Il problema con questo commit è che git considera i commit per includere tutta la cronologia prima di loro, quindi, se hai tre commit in questo modo:

A-----B-----C

E cerca di sbarazzarti di B, devi creare un commit completamente nuovo in questo modo:

A-----------C'

Dove C 'ha un ID SHA-1 diverso. Allo stesso modo, selezionare un commit da un ramo all'altro implica fondamentalmente la generazione di una patch, quindi applicarla, perdendo così anche la cronologia in quel modo.

Questa modifica degli ID di commit interrompe la funzionalità di fusione di git tra le altre cose (sebbene se usata con parsimonia ci sono euristiche che lo copriranno). Ancora più importante, però, ignora le dipendenze funzionali: se C effettivamente utilizza una funzione definita in B, non lo saprai mai.

Forse un modo migliore per gestirlo sarebbe avere rami a grana più fine. Cioè, invece di avere solo un 'master', avere 'featureA', 'bugfixB', ecc. Esegui la revisione del codice su un intero ramo alla volta - dove ogni ramo è molto concentrato sul fare una sola cosa - e poi uniscilo un ramo quando hai finito. Questo è il flusso di lavoro per cui è progettato git e in cosa è bravo :)

Se insisti a trattare le cose a livello di patch, potresti voler dare un'occhiata a darcs: considera un repository un insieme di patch, e quindi la selezione di ciliegie diventa l'operazione fondamentale. Tuttavia questo ha una serie di problemi, come essere molto lento :)

Modifica: Inoltre, non sono sicuro di aver capito la tua seconda domanda, sui due script. Forse potresti descriverlo in modo più dettagliato, forse come una domanda separata per evitare che le cose si confondano?


Riguardo alla mia seconda domanda, voglio solo assicurarmi che i processi di recupero delle modifiche (1 ° script) e di invio dei commit dati in un'altra posizione (2 ° script) possano funzionare senza condizioni di competizione / conflitti di fusione, mentre si lavora con rami diversi. Ma alla fine immagino che non abbia importanza dato che potrei unire i 2 script in uno in modo che i 2 script non funzionino simultaneamente :)
Sylvain

9
"Questa modifica degli ID di commit interrompe la funzionalità di unione di git tra le altre cose" @bdonlan per favore spiega come viene frenata la funzionalità di unione. Cosa significa?
Narek

5
@Narek Probabilmente significa che i cambiamenti nel commit C 'si scontreranno con gli stessi cambiamenti nel commit C quando unirai il secondo ramo. Questa è la conseguenza della perdita della storia dietro il commit C.
bytefu

1
"E cerca di sbarazzarti di B" - perché stai cercando di sbarazzarti di B?
d512

3
@ user1334007, significa che prima era ABC. Ora, a causa della tua scelta di C, il tuo ramo è AD-C ", che non contiene più" B ".
AnneTheAgile

1

Mi rendo conto che questa è una vecchia domanda, ma qui viene fatto riferimento: come unire un commit specifico in Git

Quindi, una risposta più recente: usa i rami delle funzionalità e le richieste pull.

Che aspetto ha, dove fA è un commit con la funzione A e fB è un commit con la funzione B:

            fA   fC (bad commit, don't merge)
           /  \ /
master ----A----B----C
                \  /
                 fB

Le richieste pull sono associate alla funzionalità di GitHub, ma in realtà tutto ciò che intendo è che qualcuno ha la responsabilità di unire i rami delle funzionalità in master.

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.