Diciamo che abbiamo la seguente situazione in Git:
Un repository creato:
mkdir GitTest2
cd GitTest2
git init
Alcune modifiche nel master hanno luogo e vengono committate.
echo "Su Master" > file
git commit -a -m "commit iniziale"
Feature1 si è ramificata da master e alcuni lavori sono stati fatti:
git branch feature1
git checkout feature1
echo "Feature1" > featureFile
git commit -a -m "Commit per feature1"
Nel frattempo, viene scoperto un bug nel master-code e viene stabilito un hotfix-branch
git checkout master
git branch hotfix1
git checkout hotfix1
Il bug viene corretto nel ramo hotfix e reinserito nel master (forse dopo una pull request/code review):
echo "Bugfix" > bugfixFile
git commit -a -m "Bugfix Commit"
git checkout master
git merge --no-ff hotfix1
Lo sviluppo della feature1 continua:
git checkout feature1
Diciamo che ho bisogno dell'hotfix nel mio ramo feature, forse perché il bug si verifica anche lì. Come posso ottenere questo senza duplicare i commit nel mio ramo feature?
Voglio evitare di ottenere due nuovi commit sul mio ramo feature che non hanno alcuna relazione con l'implementazione della feature. Questo sembra particolarmente importante per me se uso le richieste di pull: Tutti questi commit saranno anche inclusi nella richiesta di pull e dovranno essere rivisti anche se questo è già stato fatto (poiché l'hotfix è già nel master).
Non posso fare un git merge master --ff-only
: "fatal: Not possible to fast-forward, aborting.", ma non sono sicuro che questo mi abbia aiutato.
Come facciamo a fondere il ramo master nel ramo delle funzionalità? Facile:
git checkout feature1
git merge master
Non ha senso forzare un fast forward merge qui, poiché non può essere fatto. Hai fatto il commit sia nel ramo feature che nel ramo master. L'avanzamento veloce è impossibile ora.
Dai un'occhiata a GitFlow. È un modello di branching per Git che può essere seguito, e tu inconsciamente l'hai già fatto. È anche un'estensione di Git che aggiunge alcuni comandi per i nuovi passi del flusso di lavoro che fanno cose automaticamente che altrimenti dovreste fare manualmente.
Quindi cosa avete fatto bene nel vostro flusso di lavoro? Hai due rami con cui lavorare, il tuo ramo feature1 è fondamentalmente il ramo "develop" nel modello GitFlow.
Hai creato un ramo hotfix da master e l'hai unito di nuovo. E ora sei bloccato.
Il modello GitFlow ti chiede di unire l'hotfix anche al ramo di sviluppo, che è "feature1" nel tuo caso.
Quindi la vera risposta sarebbe:
git checkout feature1
git merge --no-ff hotfix1
Questo aggiunge tutte le modifiche che sono state fatte all'interno dell'hotfix al ramo feature, ma solo quelle modifiche. Potrebbero andare in conflitto con altre modifiche di sviluppo nel ramo, ma non andranno in conflitto con il ramo master se alla fine si dovesse fondere il ramo delle funzionalità con il master.
Sii molto attento con il rebase. Fai il rebase solo se i cambiamenti che hai fatto sono rimasti locali al tuo repository, per esempio non hai spinto nessun ramo in qualche altro repository. Il rebase è un grande strumento per organizzare i tuoi commit locali in un ordine utile prima di spingerli fuori nel mondo, ma il rebase dopo incasinerà le cose per i principianti di git come te.
Dovresti essere in grado di fare il rebase del tuo ramo su master:
git checkout feature1
git rebase master
Gestisci tutti i conflitti che sorgono. Quando arrivi ai commit con i bugfix (già in master), Git dirà che non ci sono stati cambiamenti e che forse sono già stati applicati. Si continua quindi il rebase (saltando i commit già in master) con
git rebase --skip
Se si esegue un git log
sul proprio ramo feature, si vedrà il commit di bugfix apparire solo una volta, e nella parte master.
Per una discussione più dettagliata, dai un'occhiata alla documentazione del libro Git su git rebase
(https://git-scm.com/docs/git-rebase) che copre questo esatto caso d'uso.
================ Modifica per un contesto aggiuntivo ====================
Questa risposta è stata fornita specificamente per la domanda posta da @theomega, tenendo conto della sua particolare situazione. Nota questa parte:
Voglio prevenire [...] commit sul mio ramo di funzionalità che non hanno alcuna relazione con l'implementazione della funzionalità.
Il rebasing del suo ramo privato su master è esattamente ciò che produrrà quel risultato. Al contrario, fondere master nel suo ramo farebbe precisamente ciò che lui specificamente non vuole che accada: aggiungere un commit che non è correlato all'implementazione della caratteristica su cui sta lavorando attraverso il suo ramo.
Per rivolgersi agli utenti che leggono il titolo della domanda, saltano il contenuto effettivo e il contesto della domanda, e poi leggono solo la risposta superiore alla cieca assumendo che si applicherà sempre al loro (diverso) caso d'uso, permettetemi di elaborare:
git merge master
come nella risposta di @Sven).Infine, se non sei soddisfatto del fatto che questa risposta non è la più adatta alla tua situazione, anche se lo era per @theomega, aggiungere un commento qui sotto non sarà particolarmente utile: Io non controllo quale risposta viene selezionata, solo @theomega lo fa.
Potresti essere in grado di fare un "cherry-pick" per tirare i commit esatti di cui hai bisogno nel tuo ramo feature.
Fai un git checkout hotfix1
per entrare nel ramo hotfix1. Poi fai un git log
per ottenere l'hash SHA-1 (grande sequenza di lettere e numeri casuali che identifica univocamente un commit) del commit in questione. Copialo (o i primi 10 caratteri circa).
Poi, git checkout feature1
per tornare al tuo ramo feature.
Poi, git cherry-pick <l'hash SHA-1 che hai appena copiato>
Questo tirerà quel commit, e solo quel commit, nel tuo ramo feature. Quel cambiamento sarà nel ramo - lo hai appena "cherry-picked" dentro. Poi, riprendi il lavoro, modifica, commit, push, ecc. a tuo piacimento.
Quando, alla fine, esegui un altro merge da un ramo al tuo ramo delle caratteristiche (o viceversa), Git riconoscerà che hai già fatto il merge in quel particolare commit, saprà che non deve farlo di nuovo, e semplicemente "salterà sopra".