2009-04-07 13 views
158

Utilizzo Git da circa un anno e penso sia fantastico, ma ho appena iniziato una seconda versione del progetto e ne ho avviato una nuova. Sto lottando un po 'con il modo migliore per gestire le cose andando avanti.git: salta specifici commit durante l'unione

Ho due rami chiamati say master10 (per v1) e master20 (per v2). Ho fatto correzioni di bug in v1 su branch master10 e ho sviluppato nuove cose su master20. Ogni volta che faccio una correzione di bug, unisco in v2 controllando master20 e facendo git merge master10. Fin qui tutto bene.

Ora, tuttavia, ho apportato una modifica in v1 che non desidero nella v2, ma voglio continuare a unire altre correzioni di bug. Come faccio a dire a Git di saltare quel particolare commit (o un intervallo di commit), ma che andando avanti vorrei ancora unire altre correzioni di bug.

Ho pensato che git rebase potrebbe essere quello che mi serve, ma ho letto il documento e la mia testa è quasi esplosa.

Penso che quello che voglio sia qualcosa come un comando "git sync" che dice a git che due rami sono ora in-sync e in futuro si fondono solo i commit da questo punto di sincronizzazione.

Qualsiasi aiuto apprezzato.

risposta

234

Se si desidera unire la maggior parte ma non tutti i commit sul ramo "maint" a "master", ad esempio, è possibile farlo. Richiede un po 'di lavoro ---- come accennato in precedenza, il solito caso d'uso è quello di unire tutto da un ramo --- ma a volte capita di aver apportato una modifica a una versione di rilascio che non dovrebbe essere integrata di nuovo (forse quella del codice stato sostituito in master già), quindi come lo si rappresenta? Ecco ...

Quindi supponiamo che a maint siano state applicate 5 modifiche e che uno di questi (maint ~ 3) non debba essere riunito in master, sebbene tutti gli altri debbano essere. Lo fai in tre fasi: in realtà unisci tutto prima di quello, dì a git di contrassegnare maint ~ 3 come fuso anche quando non lo è, e quindi unisci il resto. La magia è:

bash <master>$ git merge maint~4 
bash <master>$ git merge -s ours maint~3 
bash <master>$ git merge maint 

Il primo comando fonde tutto prima tua maint fastidioso commettere sul master. Il messaggio di log di merge predefinito spiegherà che stai unendo "branch 'maint' (parte iniziale)".

Il secondo comando unisce il fastidioso maint ~ 3 commit, ma l'opzione "-s ours" dice a git di usare una speciale "strategia di unione" che, di fatto, funziona semplicemente mantenendo l'albero in cui ci si sta fondendo e ignorando il commit (s) si sta fondendo completamente. Ma fa ancora un nuovo commit di unione con HEAD e maint ~ 3 come genitori, quindi il grafico di revisione ora dice che maint ~ 3 viene unito. Quindi, in effetti, probabilmente vorrai usare anche l'opzione -m per 'git merge', per spiegare che quel commit di maint ~ 3 viene effettivamente ignorato!

Il comando finale unisce semplicemente il resto di maint (maint ~ 2..maint) in master in modo da sincronizzarlo di nuovo.

+0

Mi chiedo tuttavia se questo non sia un po 'pericoloso: che cosa è l'albero ~ 3 non deve essere ignorato ma semplicemente rimandato? Con la tua soluzione, ogni successivo git si fonde maint non si unirà di nuovo albero ~ 3. – VonC

+1

Per il commit posticipato, vorrei creare un "ramo secondario", fare esattamente ciò che descrivi (incluso git merge -s ours maint ~ 3), quindi unire tutto dal ramo secondario al master. Credo che un futuro "git merge maint" stavolta si unirà "mast ~ 3" – VonC

+2

Penso che se hai bisogno di posticipare l'unione di quel commit, hai poca scelta ma saltarlo (unire -s nostro) e poi applicarlo usando il comando cherry-pick. Una volta che il commit è raggiungibile dal master, non può essere nuovamente unito, evitando di unire la stessa modifica due volte è uno dei principali obiettivi git. – araqnid

0

Creare un terzo ramo per le modifiche desiderate in master10 ma non in master20. Considera sempre master10 come il tuo "maestro", il ramo più stabile di tutti. Il ramo che tutti gli altri rami vogliono mantenere sempre sincronizzati.

+0

Immagino che possa funzionare, ma mi sono già messo in questo stato, e un terzo ramo probabilmente mi confonderebbe ancora di più. :) –

15

I commit includono ascendenza. Non è possibile unire un commit senza unire precedenti commit.

È possibile selezionarli, naturalmente. È un flusso sottile quando si ha un ramo in modalità manutenzione.

+1

Grazie, Cherry Pick farà il lavoro. Non bello come quello che speravo, ma lo farà. –

26

IMHO, la cosa più logica da fare è unire tutto e quindi utilizzare git revert (commit_you_dont_want) per rimuoverlo.

Esempio:

git merge master 
git revert 12345678 

Se si dispone di più "al-ignore" impegna, o vorrebbe modificare ripristinare un messaggio:

git merge master 
git revert -n 123456 
git revert -n abcdef 
git commit -m "... Except commits 123456 and abcdef" 

Allora la vostra storia può apparire come:

| ... Except 123456 and abcdef 
|\ Merge branch 'master' into 'your_branch' 

Se si verificano conflitti che implicano SOLO questi commit "da ignorare", è possibile utilizzare:

git merge master -X ours 

Così la tua versione persisterà sull'altra. Anche senza i messaggi di errore, puoi ancora "annullare" quei commit indesiderati, perché potrebbero avere altre modifiche che non sono in conflitto e non le vuoi ancora.

Se si verificano conflitti che NON riguardano SOLTANTO i commit "da ignorare", è necessario risolverli manualmente e probabilmente sarà necessario risolverli nuovamente durante il ripristino.

+1

Se successivamente si desidera unire in seguito i commit ripristinati nel ramo, Git continuerà a ignorarli? –

+0

@ AnriëtteMyburgh È possibile ripristinare i commit di reversione per poi unirli in qualcosa che in realtà non si può fare facilmente con la strategia "merge-s ours". – ikdc

2

Una sorta di pubblicità per il mio project che sostanzialmente avvolge il processo descritto da @araqnid.

È una specie di supporto che introduce seguente flusso GIT:

  • c'è una notifica giornaliera/settimanale in attesa di unioni dai rami di manutenzione in dev/branch master
  • controlli ramo manutentore per lo stato e lo decide/se è necessario che tutti i commit siano obbligatori e bloccarli o chiedere agli sviluppatori di bloccarsi. Alla fine, il ramo di manutenzione viene unito a upsteam.

Una citazione dalla pagina del progetto:

A seconda del flusso di lavoro è possibile avere la manutenzione o rami specifici del cliente con il ramo master. Questi rami sono anche chiamati rami LTS.

Spesso le correzioni rapide passano nei rami in cui è stato segnalato il bug e quindi il commit viene unito nuovamente al ramo principale.

pratica generale è di avere tutti i rami perfettamente sincronizzate con il maestro, vale a dire che si desidera vedere un delta chiaro tra un particolare ramo e master per capire se il master contiene tutte caratteristiche e correzioni di bug.

Tuttavia a volte non si desidera un commit particolare perché sono specifici per il cliente e non devono essere visibili da altri utenti. Oppure il tuo ramo principale è diverso da quello che richiede un approccio diverso per risolvere il problema, o ancora meglio, il problema non è più presente.

Anche in caso di prelievo di ciliegie dal master nel ramo di manutenzione il commit risultante deve essere bloccato nel master.