git pull
sta probabilmente creando il commit. Se esegui un commit locale e poi esegui git pull
dopo che qualcun altro ha inviato un commit al repository, Git scarica il commit dell'altro sviluppatore e lo unisce al tuo ramo locale.
Come evitare questi impegni di unione in futuro
Potresti usarlo git pull --rebase
per evitare che ciò accada in futuro, ma il rebasing ha i suoi pericoli e consiglio di evitarlo del pull
tutto .
Invece, ti incoraggio a seguire questo schema di utilizzo:
# download the latest commits
git remote update -p
# update the local branch
git merge --ff-only @{u}
# if the above fails with a complaint that the local branch has
# diverged:
git rebase -p @{u}
Spiegazione
git remote update -p
scarica tutti i commit nei repository remoti e aggiorna i rami di tracciamento remoti (ad es origin/master
.). NON tocca la directory di lavoro, l'indice o le filiali locali.
L' -p
argomento elimina le diramazioni a monte. Pertanto, se ilfoo
ramo viene eliminato nel origin
repository, git remote update -p
eliminerà automaticamente il riferimento origin/foo
.
git merge --ff-only @{u}
dice a Git di unire il ramo a monte (l' @{u}
argomento) nel ramo locale, ma solo se il ramo locale può essere "inoltrato rapidamente" al ramo a monte (in altre parole, se non è divergente).
git rebase -p @{u}
sposta efficacemente i commit che hai fatto ma non hai ancora spinto in cima al ramo a monte, il che elimina la necessità di creare i commit di unione sciocchi che stai cercando di evitare. Ciò migliora la linearità della storia di sviluppo, facilitando la revisione.
L' -p
opzione dice a Git di conservare le fusioni. Questo impedisce a Git di linearizzare i commit in fase di riequilibrio. Questo è importante se, ad esempio, hai unito un ramo di funzionalità in master
. Senza -p
, ogni commit sul ramo della funzione verrebbe duplicatomaster
come parte della linearizzazione effettuata da git rebase
. Ciò renderebbe più difficile rivedere la storia dello sviluppo, non più facile.
Attenzione : git rebase
potrebbe non fare quello che ti aspetti che faccia, quindi rivedi i risultati prima di spingere. Per esempio:
git log --graph --oneline --decorate --date-order --color --boundary @{u}..
Preferisco questo approccio rispetto git pull --rebase
ai seguenti motivi:
- Ti permette di vedere i commit a monte in entrata prima di modificare la cronologia per incorporarli.
- Ti consente di passare l' opzione
-p
( --preserve-merges
) a git rebase
nel caso in cui sia necessario rifare una fusione intenzionale (ad esempio, l'unione di un ramo di funzionalità già inserito in master
).
Stenografia: git up
invece digit pull
Per semplificare l'esecuzione di quanto sopra, ti consiglio di creare un alias chiamato up
:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
Ora tutto ciò che devi fare per aggiornare il tuo ramo è eseguire:
git up
invece di git pull
. Se ricevi un errore perché il tuo ramo locale si è discostato dal ramo a monte, questo è il tuo spunto per ribasare.
Perché no git pull --rebase
?
La corsa git pull --rebase
è equivalente alla corsa git fetch
seguita dagit rebase
. Questo tenta di avanzare rapidamente ai nuovi commit a monte, ma se ciò non è possibile, ridisegnerà i tuoi commit locali sui nuovi commit a monte. Questo di solito è OK, ma fai attenzione:
- Rebase è un argomento avanzato e dovresti capire le implicazioni prima di riformulare.
git pull --rebase
non ti dà l'opportunità di esaminare i commit prima di incorporarli. A seconda di cosa è cambiato a monte, è molto probabile che rebase è sbagliato operazione-a rebase --onto
, merge
, reset
o push -f
potrebbe essere più adatto di una pianurarebase
.
- Non è (attualmente) possibile passare
--preserve-merges
all'operazione rebase, quindi qualsiasi unione intenzionale di un ramo di feature verrà linearizzata, ripetendo (e quindi duplicando) tutti i commit di branch di feature.
"Correzione" di un commit unione esistente creato da git pull
Se non hai ancora inviato un commit di unione creato da git pull
, puoi modificare il commit di unione. Supponendo di non aver effettuato alcuna fusione intenzionale (ad esempio, unendo un ramo di funzionalità già inserito nel ramo corrente), è necessario:
git rebase @{u}
Il comando sopra dice a Git di selezionare tutti i commit non-merge raggiungibili da HEAD
(il commit corrente), meno tutti i commit raggiungibili da @{u}
(che è la scorciatoia per "il ramo upstream", cioè, origin/master
se lo HEAD
è master
), replay (cherry-pick ) in cima al ramo a monte, quindi sposta il riferimento al ramo corrente in modo che punti al risultato della riproduzione dei commit. In questo modo, i commit non-merge vengono trasferiti sul commit upstream più recente, eliminando l'unione creata da git pull
.
Se si dispone di un commit di unione intenzionale, non si desidera eseguire git rebase @{u}
perché verrà riprodotto tutto dall'altro ramo. Affrontare questo caso è sostanzialmente più complicato, motivo per cui è buono da usare git up
ed evitare del git pull
tutto. Probabilmente dovrai usare reset
per annullare l'unione creata da pull
e quindi fare git rebase -p @{u}
. L' -p
argomento per cui git rebase
non ha funzionato in modo affidabile per me, quindi potresti finire per dover reset
annullare l'unione intenzionale, aggiornare il tuo ramo locale @{u}
e quindi ripetere l'unione intenzionale (il che è un dolore se ci fosse molta unione pelosa conflitti).