git - salta specifici commit durante l'unione


200

Sto usando Git da circa un anno e penso che sia fantastico, ma ho appena iniziato una seconda versione del progetto e ho iniziato una nuova filiale per questo. Sto lottando un po 'con il modo migliore per gestire le cose in futuro.

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

Ora, tuttavia, ho apportato una modifica in v1 che non voglio in v2, ma voglio continuare a unire altre correzioni di bug. Come posso dire a Git di saltare quel particolare commit (o una serie di commit), ma che in futuro voglio ancora unire altre correzioni di bug.

Ho pensato che git rebasepotesse essere quello di cui ho bisogno, ma ho letto il documento e la mia testa è quasi esplosa.

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

Qualsiasi aiuto apprezzato.

Risposte:


289

Se vuoi unire la maggior parte, ma non tutti gli commit sul ramo "maint" in "master", ad esempio, puoi farlo. Richiede un po 'di lavoro ---- come menzionato sopra, il solito caso d'uso è di unire tutto da un ramo --- ma a volte capita che tu abbia apportato una modifica a una versione di rilascio che non dovrebbe essere integrata indietro (forse quel codice è stato già sostituito in master), quindi come lo rappresenti? Ecco qui...

Supponiamo quindi che al maint siano state applicate 5 modifiche e che uno di questi (maint ~ 3) non debba essere ricollegato al master, sebbene tutti gli altri dovrebbero esserlo. Lo fai in tre fasi: in realtà unisci tutto prima di quello, dì a git di contrassegnare maint ~ 3 come unito anche quando non lo è, e poi 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 unisce tutto prima che il tuo fastidioso maint si impegni sul master. Il messaggio di registro di unione predefinito spiegherà che stai unendo "branch 'maint' (parte iniziale)".

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

Il comando finale unisce semplicemente il resto di maint (maint ~ 2..maint) in master in modo da sincronizzare nuovamente tutti.


5
Penso che se hai bisogno di posticipare l'unione di quel commit, hai poca scelta se non quella di saltare (unisci il nostro) e successivamente applicarlo usando il comando cherry-pick. Una volta che il commit è raggiungibile dal master, non può più essere unito. Evitare di unire lo stesso cambiamento due volte è uno dei principali obiettivi git.
araqnid,

3
Per quanto riguarda l'esempio del tuo ramo secondario: sospetto che una volta che hai unito il ramo secondario ti trovi esattamente nella stessa situazione in cui ti trovi dopo il secondo passaggio del mio post. La creazione di rami aggiuntivi non fa alcuna differenza per le relazioni di commit.
araqnid,

5
Solo per interesse, se vuoi solo omettere una modifica, perché non dovresti fare una sola unione e poi ripristinare quella sola invece di eseguire tre fusioni? Ciò comporterebbe un minor numero di changeet impegnati nel repository e una cronologia più esplicita.
Mark Booth,

3
Spesso è più facile dare un nome esplicito ai commit. Quindi devi solo visualizzare il registro git del ramo da unire e annotare gli hash del commit che non dovrebbero essere uniti e quello precedente - invece di contare i commit ...
zwirbeltier

14
@MarkBooth: il commit che vuoi saltare potrebbe essere in un enorme conflitto con il ramo in cui vuoi unirti. È più semplice saltarlo invece di risolvere i conflitti, quindi ripristinare quella modifica e risolvere nuovamente i conflitti
SztupY

39

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

Esempio:

git merge master
git revert 12345678

Se hai più commit da "ignorare" o desideri modificare il messaggio di ripristino:

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

Quindi la tua storia potrebbe apparire come:

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

In caso di conflitti che coinvolgono SOLO questi commit "da ignorare", è possibile utilizzare:

git merge master -X ours

Quindi la tua versione persisterà sull'altra. Anche senza messaggi di errore, potresti comunque "ripristinare" quei commit indesiderati, perché potrebbero avere altre modifiche che non sono in conflitto e non li desideri ancora.

Se hai conflitti che coinvolgono NON SOLO i commit "da ignorare", dovresti risolverli manualmente e probabilmente dovrai risolverli di nuovo durante il ripristino.


2
Se poi vuoi unire in seguito quei commit ripristinati nel ramo, Git li ignorerà ancora?
Anriëtte Myburgh,

@ AnriëtteMyburgh È possibile ripristinare gli impegni di reversione per unirli successivamente in qualcosa che in realtà non si può fare altrettanto facilmente con la strategia "Unisci-i nostri".
Lily Chung,

Grazie, questo è esattamente ciò di cui avevo bisogno se qualche commit più vecchio in un ramo di funzioni che non volevo in master e un gruppo che volevo in master. Bello e pulito.
Vale Trujillo,

17

Impegni includono origini. Non è possibile unire un commit senza unire i commit precedenti.

Puoi sceglierli ciliegia, ovviamente. Questo è un buon flusso quando hai un ramo che è in modalità manutenzione.


1
Grazie, Cherry Pick farà il lavoro. Non è bello come quello che speravo, ma lo farà.
Brad Robinson,


3

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

È una specie di aiuto che introduce il seguente flusso GIT:

  • c'è una notifica giornaliera / settimanale sulle fusioni in sospeso dai rami di manutenzione nel ramo dev / master
  • il manutentore della filiale verifica lo stato e decide se sono necessari tutti i commit e ne blocca alcuni o chiede agli sviluppatori di bloccarsi. Alla fine il ramo di manutenzione viene unito nel upsteam.

Una citazione dalla pagina del progetto:

A seconda del flusso di lavoro è possibile avere filiali di manutenzione o specifiche del cliente insieme alla filiale principale. Questi rami sono anche chiamati rami LTS.

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

La pratica generale è avere tutti i rami perfettamente sincronizzati con il master, cioè si desidera vedere un delta chiaro tra un ramo e un master particolare per capire se il master contiene tutte le funzionalità e correzioni di bug.

Tuttavia, a volte non si desidera eseguire commit particolari perché sono specifici del cliente e non devono essere visibili da altri utenti. Oppure il tuo ramo principale è divergente al punto che richiede un approccio completamente diverso per risolvere il problema, o ancora meglio, il problema non è più presente lì.

Anche in caso di selezione della ciliegia dal master nel ramo di manutenzione, il commit risultante deve essere bloccato nel master.


0

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


Immagino che potrebbe funzionare, ma mi sono già trovato in questo stato e un terzo ramo probabilmente mi confonderebbe ancora di più. :)
Brad Robinson

0

Piuttosto che reverto cherry-pickper questo caso, devi prendere Git per considerare le modifiche che stai saltando per essere più vecchie di quelle che hai fatto.

Così:

  1. unisci l'ultimo commit prima dei commit che vuoi saltare. Questo, ovviamente, unirà tutti i commit precedenti. git merge ccc
  2. unisci i commit che vuoi saltare. git merge fff --no-commit
  3. mettere in scena eventuali fusioni, annullare tutte le modifiche, annullare tutte le modifiche. (Forse ci sono comandi a prova di errore per questo, ma farei solo questa parte in un'interfaccia utente - comunque tu sappia come)
  4. completa l'unione vuota git merge --continue
  5. unisci i commit DOPO quello che volevi saltare. git merge source-branch-head

Dopo il passaggio 4, git considererà il tuo ramo più recente di quel commit, dal momento che lo hai già gestito (scegliendo di mantenere le tue versioni delle cose).

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.