Quando dovrei usare git pull --rebase?


806

Conosco alcune persone che usano git pull --rebasedi default e altre che insistono per non usarlo mai. Credo di aver capito la differenza tra fusione e rebasing, ma sto cercando di metterlo nel contesto di git pull. Si tratta solo di non voler vedere molti messaggi di commit unione o ci sono altri problemi?


1
Fonte per le persone che sconsigliano git pull --rebase? Rebase o git rebase è un'attività separata da git pull --rebase!
przemo_li,

Risposte:


584

Dovresti usare git pull --rebasequando

  • le modifiche non meritano un ramo separato

Anzi - perché non allora? È più chiaro e non impone un raggruppamento logico sui tuoi commit.


Ok, suppongo che abbia bisogno di qualche chiarimento. In Git, come probabilmente sai, sei incoraggiato a ramificarsi e fondersi. La tua filiale locale, in cui raccogli le modifiche, e la filiale remota sono, in realtà, diverse filiali e git pullsta per fonderle. È ragionevole, dal momento che spingi non molto spesso e di solito accumuli un numero di modifiche prima che costituiscano una funzionalità completa.

Tuttavia, a volte - per qualsiasi motivo - pensi che sarebbe effettivamente meglio se questi due - remoti e locali - fossero un ramo. Come in SVN. È qui che git pull --rebaseentra in gioco. Non ti unisci più - ti impegni effettivamente in cima al ramo remoto . Ecco di cosa si tratta.

Che sia pericoloso o meno è la questione se stai trattando il ramo locale e remoto come una cosa inseparabile. A volte è ragionevole (quando i cambiamenti sono piccoli, o se sei all'inizio di uno sviluppo robusto, quando cambiamenti importanti sono portati da piccoli impegni). A volte non lo è (quando normalmente crei un altro ramo, ma eri troppo pigro per farlo). Ma questa è una domanda diversa.


17
Penso che sia utile quando lavori sullo stesso ramo, ma puoi cambiare la tua workstation. Tendo a eseguire il commit e il push delle mie modifiche da una workstation, quindi tirare rebase nell'altra e continuare a lavorare sullo stesso ramo.
Pablo Pazos,

11
È una buona pratica utile impostare Git in modo che si ribassi automaticamente al pull con git config --global pull.rebase preserve (conserva dice oltre ad abilitare il rebasing, per cercare di preservare le fusioni se ne hai fatto uno localmente).
Colin D Bennett,

2
Non sono d'accordo sul fatto che dovresti usare pull --rebase solo quando lavori su un ramo. Dovresti usarlo tutto il tempo, se non impossibile a causa di qualche altra circostanza.
Tomáš Fejfar,

@P Shved ... "Tuttavia, a volte - per qualsiasi motivo - pensi che sarebbe effettivamente meglio se questi due - remoto e locale - fossero un ramo" ... questo può essere fatto? che in ambiente locale, posso avere il mio ramo e un mirror ramo remoto come origine / master. Potete per favore fornire input qui?
Mandroid,

736

Vorrei fornire una prospettiva diversa su cosa significhi effettivamente "git pull --rebase", perché a volte sembra perdersi.

Se hai mai usato Subversion (o CVS), potresti essere abituato al comportamento di "svn update". Se hai delle modifiche da impegnare e il commit fallisce perché sono state apportate modifiche a monte, "svn update". Subversion procede unendo le modifiche a monte con le tue, causando potenzialmente conflitti.

Quello che Subversion ha appena fatto è stato essenzialmente "pull --rebase". L'atto di riformulare le modifiche locali per renderle relative alla versione più recente è la parte "riequilibrante" di essa. Se prima del tentativo di commit fallito avevi eseguito "svn diff" e successivamente hai confrontato il diff risultante con l'output di "svn diff", la differenza tra i due diff è ciò che ha fatto l'operazione di rebasing.

La differenza principale tra Git e Subversion in questo caso è che in Subversion, le "tue" modifiche esistono solo come modifiche non impegnate nella tua copia di lavoro, mentre in Git hai delle commit effettive localmente. In altre parole, in Git hai biforcuto la storia; la tua storia e la storia a monte sono divergenti, ma hai un antenato comune.

Secondo me, nel caso normale di avere il tuo ramo locale semplicemente riflettendo il ramo a monte e facendo uno sviluppo continuo su di esso, la cosa giusta da fare è sempre "--rebase", perché è quello che stai facendo semanticamente . Tu e gli altri state tagliando via la storia lineare prevista di un ramo. Il fatto che qualcun altro abbia spinto leggermente prima del tuo tentativo di spinta è irrilevante, e sembra controproducente per ognuno di questi incidenti di tempismo comportare fusioni nella storia.

Se senti davvero il bisogno di qualcosa per essere un ramo per qualsiasi motivo, questa è una preoccupazione diversa secondo me. Ma a meno che tu non abbia un desiderio specifico e attivo di rappresentare i tuoi cambiamenti sotto forma di unione, il comportamento predefinito dovrebbe, secondo me, essere "git pull --rebase".

Ti preghiamo di considerare altre persone che hanno bisogno di osservare e comprendere la storia del tuo progetto. Vuoi che la storia sia disseminata di centinaia di fusioni in tutto il luogo o vuoi solo le poche fusioni selezionate che rappresentano reali fusioni di sforzi intenzionali di sviluppo divergente?


18
@MarceloCantos Per essere chiari, non sto dicendo che git (lo strumento) dovrebbe default rifare. Ciò sarebbe pericoloso poiché un rebase essenzialmente distrugge la storia. Sto dicendo che in termini di flusso di lavoro, quando non hai intenzione di diramare e stai solo tagliando via in qualche ramo su cui stanno lavorando anche altre persone, "git pull --rebase" dovrebbe essere il comportamento predefinito dell'utente.
Scodifica l'

1
Stai dicendo che non si dovrebbe git config --global branch.autosetupmerge always?
Marcelo Cantos,

9
@MarceloCantos No, non lo sono;) Personalmente lascerei l'autosetupmerge per impostazione predefinita true (se sto unendo indietro e quarta tra i rami diversi dal <-> remoto locale, mi piace che sia esplicito). Sto solo dicendo che come umano uso sempre "git pull --rebase" come parte del mio normale flusso di lavoro "prendi l'ultimo nel ramo principale", perché non voglio mai creare un commit di unione a meno che non mi stia ramificando esplicitamente.
scrivere il

9
+1 @scode. Dopo molte dolorose ore di lotta con la domanda rebase / merge, finalmente ecco una risposta che la inchioda.
AgileYogi,

10
Questa risposta è solo un tentativo di adattare gli utenti dei sistemi di controllo di versione non distribuiti a Git invece di dare loro la possibilità di comprendere correttamente i vantaggi di disporre di filiali adeguate.
Alexey Zimarev,

211

Forse il modo migliore per spiegarlo è con un esempio:

  1. Alice crea il ramo tematico A e ci lavora
  2. Bob crea un ramo di argomento B non correlato e ci lavora
  3. Lo fa Alice git checkout master && git pull. Il Master è già aggiornato.
  4. Bob lo fa git checkout master && git pull. Il Master è già aggiornato.
  5. Lo fa Alice git merge topic-branch-A
  6. Bob lo fa git merge topic-branch-B
  7. Bob fa git push origin masterprima di Alice
  8. Alice lo fa git push origin master, il che viene rifiutato perché non è un'unione di avanzamento rapido.
  9. Alice guarda il registro di origine / master e vede che il commit non è correlato al suo.
  10. Lo fa Alice git pull --rebase origin master
  11. Il commit di merge di Alice viene svolto, il commit di Bob viene eseguito e il commit di Alice viene applicato dopo il commit di Bob.
  12. Alice lo fa git push origin master, e tutti sono felici di non dover leggere un inutile commit di unione quando guardano i log in futuro.

Si noti che il ramo specifico che viene unito è irrilevante per l'esempio. Il master in questo esempio potrebbe essere altrettanto facilmente un ramo di rilascio o un ramo di sviluppo. Il punto chiave è che Alice e Bob stanno contemporaneamente unendo i loro rami locali a un ramo remoto condiviso.


2
Bello. Tendo ad essere esplicito e git co master && git pull; git checkout topic-branch-A; git rebase master; git checkout master; git merge topic-branch-A; git push origin masterripetere se la spinta di un altro verso il maestro è avvenuta prima della mia. Anche se riesco a vedere i succinti vantaggi nella tua ricetta.
HankCa,

Bella spiegazione @Cody Poll
Rajanikanta Pradhan

148

Penso che dovresti usare git pull --rebasequando collabori con altri nello stesso ramo. Sei nel tuo lavoro → commit → lavoro → ciclo di commit, e quando decidi di spingere il tuo lavoro la tua spinta viene rifiutata, perché c'è stato un lavoro parallelo sullo stesso ramo. A questo punto faccio sempre a pull --rebase. Non uso lo squash (per appiattire i commit), ma rifaccio per evitare i commit di unione extra.

Man mano che la tua conoscenza di Git aumenta, ti ritrovi a guardare molto di più nella storia rispetto a qualsiasi altro sistema di controllo della versione che ho usato. Se hai un sacco di piccoli impegni di unione, è facile perdere la concentrazione del quadro più ampio che sta accadendo nella tua storia.

Questa è in realtà l'unica volta che eseguo il rebasing (*) e il resto del mio flusso di lavoro è basato su merge. Ma finché i committer più frequenti lo fanno, la storia sembra molto meglio alla fine.

(*) Durante l'insegnamento di un corso Git, uno studente mi ha arrestato su questo, dal momento che in alcune circostanze ho anche sostenuto il rinnovamento dei rami delle funzioni. E aveva letto questa risposta;) È anche possibile tale rifasamento, ma deve sempre essere secondo un sistema prestabilito / concordato, e come tale non dovrebbe essere "sempre" applicato. E a quel tempo di solito non lo faccio pull --rebaseneanche, ed è di questo che si tratta;)


2
sicuramente si può scrivere una sceneggiatura per nascondere i commit di unione dal registro
hasen

3
Le fusioni possono contenere anche differenze, il che significa che non è del tutto banale
krosenvold

9
@hasen j Sì, ma il CONTENUTO di tali fusioni può avere importanza
krosenvold

Questa risposta è vaga e supponente rispetto alla risposta scelta: cosa intendi esattamente per "stesso ramo"? Ci sono alcuni punti positivi, che non sono comunque nella risposta scelta.
iwein,

1
La vaghezza attorno a "branch" è abbastanza intenzionale, poiché ci sono molti modi per usare refs; "linea di lavoro" è solo un'opzione.
krosenvold,

49

Non credo che ci sia mai un motivo per non usarlo pull --rebase- ho aggiunto il codice a Git specificamente per consentire al mio git pullcomando di ribadire sempre contro i commit a monte.

Quando si guarda alla storia, non è mai interessante sapere quando il ragazzo / ragazza che lavora alla funzione si è fermato per sincronizzarsi. Potrebbe essere utile per il ragazzo / ragazza mentre lo sta facendo, ma è quello che reflogserve. Sta solo aggiungendo rumore per tutti gli altri.


2
"Quando si guarda alla storia, non è mai interessante sapere quando il ragazzo che ha lavorato alla funzione ha smesso di sincronizzarsi." / ma ciò non significa che quei commit intermedi siano probabilmente build rotte?
Eglasio,

10
Sì, e non sono nemmeno uno "stato intero". Ecco perché non li vogliamo. Voglio sapere cosa voleva, non come ci fosse arrivato.
Dustin,

4
Se pull --rebasedeve essere sempre usato, perché non pullfarlo di default?
straya,

2
Temo che dovrai formare la tua opinione. Ho diverse cose nel mio .gitconfigper fare in modo che alcune delle opzioni facciano la cosa giusta. Penso che git rebase faccia la cosa sbagliata di default, così come git tag, ecc ... Se non sei d'accordo, non hai bisogno di giustificare la tua opinione.
Dustin,

8
Questo sembra un buon consiglio se tiri da "upstream", diciamo da master, e se il ramo in cui ti muovi non è diventato pubblico (ancora). Se masterpassi dall'altro ramo di un ramo di una caratteristica è più simile al contrario: non c'è mai un motivo da usare --rebase, giusto? Questo potrebbe essere il motivo per cui non è predefinito. Ho scoperto che i rebase sono come i cambiamenti dovrebbero passare dall'alto verso il basso della gerarchia verso il basso e le fusioni sono il modo in cui fluiscono verso l'alto. derekgourlay.com/blog/git-when-to-merge-vs-when-to-rebase
jolvi

38

Ricorda:

  • pull = fetch + merge
  • pull --rebase = fetch + rebase

Quindi, scegli il modo in cui vuoi gestire il tuo ramo.

Faresti meglio a conoscere la differenza tra unire e rebase :)


9

Penso che si riduce a una preferenza personale.

Vuoi nascondere i tuoi sciocchi errori prima di spingere le tue modifiche? Se è così, git pull --rebaseè perfetto. Ti consente di ridurre in seguito i tuoi commit a pochi (o uno) commit. Se ti sei unito alla tua storia (non pubblicata), non è così facile fare una storia git rebasesuccessiva.

Personalmente non mi dispiace pubblicare tutti i miei sciocchi errori, quindi tendo a fondermi invece di ribadire.


8
Nota per chiunque visualizzi questa domanda: questa risposta è completamente irrilevante per la domanda "quando dovrei usare git pull --rebase?"
therealklanni,

3
@therealklanni Ho modificato la risposta in modo che diventi più chiaro quanto sia rilevante per la domanda (si spera senza distruggere l'intento).
Paŭlo Ebermann,

Condividere un registro di lavoro sporco e non strutturato non è uno sforzo onesto, è solo pigrizia. Stai sprecando il tempo delle persone facendoti inseguire attraverso la tua tana di coniglio di sviluppo e debugging; dare loro il risultato, non le divagazioni.
Krystah,

8

git pull --rebasepotrebbe nascondere una riscrittura della cronologia da un collaboratore git push --force. Consiglio di usarlo git pull --rebase solo se sai di aver dimenticato di spingere i tuoi commit prima che qualcun altro faccia lo stesso.

Se non hai commesso nulla, ma il tuo spazio di lavoro non è pulito, poco git stashprima di git pull. In questo modo non riscrivi silenziosamente la tua storia (che potrebbe far cadere silenziosamente parte del tuo lavoro).

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.