Git pull restituisce messaggi estranei "Merge branch" nel log di commit


110

Sto lavorando con un altro sviluppatore su un progetto e stiamo usando Github come nostro repository remoto. Sono su un Mac che utilizza git 1.7.7.3, lui su Windows utilizza git 1.7.6.

Questo è quello che sta succedendo

  1. Uno di noi (chiamiamolo sviluppatore A, ma non importa quale) invia una serie di commit a GitHub.
  2. L'altro (sviluppatore B) effettua alcuni commit locali.
  3. B fa a git pull.
  4. B fa a git push.
  5. Guardando il registro della cronologia dei commit, vedo il ramo Merge "master" di github.com:foo/bar

Il log di commit viene disseminato di messaggi "Merge branch" nel tempo e mostra anche che lo sviluppatore B sta effettuando il commit delle modifiche apportate dallo sviluppatore A. L'unico modo che abbiamo trovato per prevenire questo problema è stato quello di fare un git pull --rebasepassaggio 3, ma non so quali effetti collaterali introdurrà il ribasamento. Questa è la prima volta che lavoro su un repository Git multi-sviluppatore, quindi è solo un comportamento normale? Qualche idea su come risolvere questo problema?


2
Puoi visualizzare il registro senza fusioni congit log --no-merges
wjandrea

Risposte:


88

Il commit che stai vedendo va benissimo. Viene pulleseguito effettivamente git fetche quindi git mergeun'unione di solito avviene quando si esegue git pull.

L'alternativa all'uso del rebasing invece della fusione è possibile, ma di solito dovresti evitarlo. Il rebasing ti consente di mantenere una cronologia lineare, ma rimuove anche qualsiasi informazione sulla ramificazione originariamente avvenuta. Provocherà anche la riscrittura della cronologia del ramo corrente, ricreando tutti i commit che non sono contenuti nel ramo di destinazione (nel tuo caso, il remoto). Poiché i commit ricreati sono commit diversi , ciò può causare molta confusione durante lo sviluppo insieme ad altri, specialmente quando le persone hanno già estratto parti di quei commit prima che vengano riscritti (ad esempio con i branch di funzionalità). Quindi, come regola generale, non dovresti mai riscrivere alcun commit che è già stato eseguito.

I commit che vedi sono lì per combinare due (o più) rami. Va benissimo avere un commit che non fa nient'altro che unire più rami. In effetti è molto chiaro quando si dispone di un commit di unione che combina rami quando si guarda alla cronologia. Rispetto al rebase, l'unione consente anche di vedere in modo efficace la cronologia originale così come è stata sviluppata, inclusi i rami effettivi che coesistevano.

Quindi, per farla breve: Sì, avere commit di unione va benissimo e non dovresti preoccuparti di loro.


2
Risposta molto buona. Io stesso ho provato lo stile rebase poiché era consigliato in alcune linee guida per i contributi di progetti open source e mi ha causato problemi. Anche un nuovo membro del team ha avuto lo stesso. Penso che l'opzione rebase non sia per i team che lavorano insieme tutto il giorno, ma è corretta per i progetti che hanno contributori principali e altri contributori che si limitano a inviare patch. Quelli dovrebbero andare bene per recuperare il repository principale e ribasare le modifiche appena prima che emettano una richiesta pull.
Meligy

2
@sTodorov Se non ci sono nuove modifiche, la parte fetch del pull non farà nulla, ma l'unione è ancora in esecuzione. Quindi, se il tuo ramo locale attuale non è aggiornato, unirà le nuove modifiche nel tuo ramo. E se non può eseguire un'unione in avanti veloce (se si hanno commit divergenti), creerà un commit di unione.
colpisci il

28
Questa risposta fa sembrare che l'uso di rebase come descritto dall'OP sia pericoloso, ma non lo è. Il rebase al passaggio 3 non riscrive l'intera cronologia. Solo i commit locali che non sono stati inviati vengono riscritti essendo riapplicati sopra il nuovo HEAD (l'ultimo commit inviato a quel ramo). Ciò impedisce il commit di unione estranea e non ha altri effetti collaterali.
bob esponja

1
@bobesponja Tutti i commit che non si trovano sul ramo remoto estratto vengono riscritti. Ciò può includere commit pubblicati da altri branch, ad esempio con feature branch, a cui altri potrebbero aver già avuto accesso in precedenza. In quanto tale, sì, ribasare senza pensare a ciò che ribassi è alquanto pericoloso.
colpisci l'

1
@bobesponja Sì, se pubblichi il tuo feature branch in anticipo (perché altri ci lavorano o semplicemente come backup), non dovresti ribasarlo perché altri potrebbero già averlo recuperato. Ribasare quindi - come dici tu stesso - va contro il ribasamento delle linee guida che ho affermato nella mia risposta. Tuttavia, se non pubblichi i tuoi commit, il rebasing va bene se vuoi e non ti dispiace la cronologia lineare. Ma dipende da come lavori, quindi la risposta generale è evitarlo a meno che non sia davvero sicuro. Btw. Ho rivisto la mia risposta, quindi se il problema viene risolto, ti sarei grato se avessi rimosso il tuo voto negativo.
colpisci l'

48

Questa risposta è stata rivista, poiché la mia comprensione, i diagrammi e le conclusioni non erano corrette.


git pullcausa i commit di merge perché git si sta unendo. Questo può essere cambiato impostando i tuoi rami per usare rebase invece di merge. L'utilizzo di rebase invece di merge su un pull fornisce una cronologia più lineare al repository condiviso. D'altra parte, i commit di unione mostrano gli sforzi di sviluppo paralleli nel ramo.

Ad esempio, due persone stanno lavorando sullo stesso ramo. Il ramo inizia come:

...->C1

La prima persona termina il proprio lavoro e si avvia alla filiale:

...->C1->C2

La seconda persona termina il proprio lavoro e vuole spingere, ma non può perché ha bisogno di aggiornare. Il repository locale per la seconda persona ha il seguente aspetto:

...->C1->C3

Se il pull è impostato per unire, il secondo repository di persone sarà simile.

...->C1->C3->M1
      \      /
       ->C2->

Dove M1 è un merge commit. Questa nuova cronologia del ramo verrà inviata al repository. Se invece, il pull è impostato per rebase il repository locale sarebbe simile a:

...->C1->C2->C3

Non vi è alcun commit di unione. La storia è stata resa più lineare.

Entrambe le scelte riflettono la storia della filiale. git ti permette di scegliere quale cronologia preferisci.

Ci sono effettivamente posti in cui il rebase può causare un problema con i rami remoti. Questo non è uno di quei casi. Preferiamo usare rebase in quanto semplifica una cronologia di branch già complicata e mostra una versione della cronologia relativa al repository condiviso.

Puoi impostare branch.autosetuprebase = sempre per fare in modo che git stabilisca automaticamente i tuoi rami remoti come rebase invece che come master.

git config --global branch.autosetuprebase always

Questa impostazione fa in modo che git crei automaticamente un'impostazione di configurazione per ogni ramo remoto:

branch.<branchname>.rebase=true

Puoi impostarlo tu stesso per i tuoi rami remoti già configurati.

git config branch.<branchname>.rebase true

Vorrei ringraziare @LaurensHolst per aver messo in discussione e seguito le mie precedenti dichiarazioni. Ho sicuramente imparato di più su come git funziona con i commit pull e merge.

Per ulteriori informazioni sui commit di unione, puoi leggere Contribuire a un progetto in ProGit-Book . La sezione Private Small Team mostra i commit di unione.


7
“L'utilizzo di rebase invece di merge su un pull fornisce la cronologia corretta al repository condiviso. L'utilizzo della fusione fornisce una falsa cronologia. " - Qual è la logica alla base di questa affermazione piuttosto audace? Non è possibile che una storia con unioni sia "falsa storia". È una rappresentazione accurata dell'ordine in cui sono successe le cose. Quello che stai facendo ribasando è in realtà alterare la storia, per crearne una versione leggermente più lineare. Sacrifichi la precisione per l'estetica. Forse qualcosa che preferisci fare, ma in nessun modo più veritiero.
Laurens Holst

2
L'utilizzo di rebase invece di merge non sacrifica la precisione per l'estetica. Usiamo --no-ff per le fusioni, quindi l'estetica non è un requisito. La precisione è un desiderio. Rebase fornisce quella precisione.
Bill Door,

2
In che modo la cronologia ribasata è più accurata? Non chiarisci questo e non vedo come sarebbe.
Laurens Holst

1
La cronologia è un riflesso del momento in cui si sono verificati i commit nel repo condiviso . Un giorno 1, il repo condiviso ha visto il commit C2. Il giorno 2, il repository condiviso vede il commit C3. Se C3 venisse prima di C2, il riflesso del tempo non sarebbe corretto. C3 non è venuto prima di C2. Tutto ciò che fa rebase è riorganizzare i commit sul repository locale per riflettere adeguatamente la cronologia mostrata dal repository condiviso.
Bill Door

6
Le tue domande mi hanno portato a rivedere la mia comprensione dei commit di unione. Il mio diagramma non è corretto. Sto rivedendo la discussione. Anche le mie conclusioni sono errate. La cronologia per rebase e merge è ugualmente corretta. Puoi fare la tua scelta.
Bill Door

11

Tu puoi fare:

git pull --rebase

Tuttavia, questo metterà sempre le tue modifiche in cima a quelle dei tuoi collaboratori. Ma non riceverai alcun messaggio di fusione inquinante.


9

In realtà c'è una risposta molto più semplice a questo. Chiedi allo sviluppatore B di eseguire un pull PRIMA di eseguire il commit. Ciò impedirà quei commit di unione, poiché sono causati dalla cronologia che hai creato sul tuo repository locale dal tuo commit locale che tenta di fondersi con la cronologia dei commit sul repository remoto. Se ricevi un messaggio che dice qualcosa sulla falsariga di "le modifiche verranno sovrascritte" quando esegui un pull, significa semplicemente che entrambi avete toccato lo stesso file, quindi fate:

git stash
git pull
git stash pop

quindi puoi risolvere qualsiasi conflitto di unione se ce ne sono.


I più fastidiosi e ansiosi sono esattamente i conflitti di fusione. Preferisco evitarlo
Verde

1
@Green Se sei preoccupato per i conflitti di unione, anche git pull non è diverso.
Zoso

Tranne quella volta in cui ti dimentichi di stashprima di te pull. Ugh git mi richiede di essere sempre al top del mio gioco.
linuxNoob

Necessità di git pull --rebaseintegrare le modifiche remote prima di quelle locali, a prescindere.
vonbrand

7

Fare un git pull inserirà i messaggi "Merge branch", che è proprio quello che fa. Eseguendo un git pull, hai unito il ramo remoto al tuo ramo locale.

Quando esegui un pull git e ci sono conflitti, il log di git mostrerà gli aggiornamenti ai file in conflitto come provenienti dall'utente che ha risolto i conflitti. Presumo che ciò sia dovuto al fatto che la persona che risolve il conflitto esegue nuovamente il commit del file.

Per quanto ne so è così che funziona git, e non c'è un modo per aggirarlo.

Il rebasing spazzerà via la cronologia di git, quindi non sarai in grado di vedere quando si sono verificate le unioni.

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.