Come risolvere i conflitti di unione in Git


4769

Come posso risolvere i conflitti di unione in Git?


31
Il seguente post sul blog sembra dare un ottimo esempio su come gestire il conflitto di unione con Git che dovrebbe farti andare nella giusta direzione. Gestire ed evitare i conflitti in Git
mwilliams,

4
È possibile configurare uno strumento di unione (kdiff3 jebaird.com/2013/07/08/… ) e quindi utilizzare git mergetool. Quando lavori in grandi gruppi di sviluppatori incontrerai sempre conflitti di unione.
Grado G Cooper

Non dimenticare che puoi mitigare la maggior parte dei conflitti di unione fondendoti regolarmente a valle!
Ant P,


8
Domanda affascinante: chiesta nel 2008, aperta al 100% si è conclusa senza alcun suggerimento su ciò che realmente riguarda (si tratta della GUI? Sui comandi git? Sulla semantica? Sulla spinta / estrazione o solo sui conflitti generali?) - completamente senza risposta. 30 risposte, tutte (per quanto mostra una rapida occhiata) più o meno in corso su diversi strumenti diff3 e di fusione, nessuna accettata. La risposta più votata menziona un comando che non funziona nemmeno con l' gitinstallazione predefinita . Sono riuscito a raggiungere la pagina iniziale di SE oggi per me, 2017, con 1,3 milioni di visualizzazioni e migliaia di voti in entrambi i modi. Affascinante.
AnoE

Risposte:


2913

Provare: git mergetool

Apre una GUI che ti guida attraverso ogni conflitto e puoi scegliere come unirti. A volte richiede un po 'di modifica manuale in seguito, ma di solito è sufficiente da solo. È molto meglio che fare tutto a mano certamente.

Secondo il commento di @JoshGlover:

Il comando

non apre necessariamente una GUI a meno che non ne installi una. Correre git mergetoolper me ha portato vimdiffall'utilizzo. È possibile installare uno dei seguenti strumenti per usarlo al posto: meld, opendiff, kdiff3, tkdiff, xxdiff, tortoisemerge, gvimdiff, diffuse, ecmerge, p4merge, araxis, vimdiff, emerge.

Di seguito è riportata la procedura di esempio da utilizzare vimdiffper risolvere i conflitti di unione. Sulla base di questo link

Passaggio 1 : eseguire i seguenti comandi nel proprio terminale

git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false

Questo imposterà vimdiff come strumento di unione predefinito.

Passaggio 2 : eseguire il comando seguente nel terminale

git mergetool

Passaggio 3 : vedrai un display vimdiff nel seguente formato

  ╔═══════╦══════╦════════╗
  ║       ║      ║        ║
  ║ LOCAL ║ BASE ║ REMOTE ║
  ║       ║      ║        ║
  ╠═══════╩══════╩════════╣
  ║                       ║
  ║        MERGED         ║
  ║                       ║
  ╚═══════════════════════╝

Queste 4 visualizzazioni sono

LOCALE: si tratta del file dal ramo corrente

BASE: antenato comune, aspetto del file prima di entrambe le modifiche

REMOTO: file che si sta unendo nel proprio ramo

UNITO - unisci il risultato, questo è ciò che viene salvato nel repository

Puoi navigare tra queste viste usando ctrl+ w. Puoi raggiungere direttamente la vista MERGED usando ctrl+ wseguito da j.

Maggiori informazioni sulla navigazione di Vimdiff qui e qui

Passaggio 4 . È possibile modificare la vista MERGED nel modo seguente

Se si desidera ottenere modifiche da REMOTE

:diffg RE  

Se si desidera ottenere modifiche da BASE

:diffg BA  

Se si desidera ottenere modifiche da LOCAL

:diffg LO 

Passaggio 5 . Salva, esci, esegui il commit e pulisci

:wqa salva ed esci da vi

git commit -m "message"

git clean Rimuovi file extra (es. * .Orig) creati dallo strumento diff.


54
Cordiali saluti, è possibile utilizzare git mergetool -yper salvare alcune sequenze di tasti se si uniscono molti file contemporaneamente.
davr

373
Bene, non necessariamente apre una GUI a meno che non ne installi una. Correre git mergetoolper me ha portato vimdiffall'utilizzo. È possibile installare uno dei seguenti strumenti per usarlo al posto: meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse ecmerge p4merge araxis vimdiff emerge.
Josh Glover,

31
Buon punto Josh. Su Ubuntu ho avuto la migliore fortuna con Meld, il suo display di unione a tre vie non è male. Su OSX git ha scelto un buon default.
Peter Burns,

18
Questo ha aperto KDiff3. Che non ho assolutamente idea di come usare.
David Murdoch,

7
Puoi anche usare Beyond Compare 3 ora ( git mergetool -t bc3).
AzP

1703

Ecco un probabile caso d'uso, dall'alto:

Stai per apportare alcune modifiche, ma oops, non sei aggiornato:

git fetch origin
git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Updating a030c3a..ee25213
error: Entry 'filename.c' not uptodate. Cannot merge.

Quindi ti aggiorni e riprova, ma hai un conflitto:

git add filename.c
git commit -m "made some wild and crazy changes"
git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Auto-merging filename.c
CONFLICT (content): Merge conflict in filename.c
Automatic merge failed; fix conflicts and then commit the result.

Quindi decidi di dare un'occhiata alle modifiche:

git mergetool

Oh mio, oh mio, a monte ha cambiato alcune cose, ma solo per usare i miei cambiamenti ... no ... i loro cambiamenti ...

git checkout --ours filename.c
git checkout --theirs filename.c
git add filename.c
git commit -m "using theirs"

E poi proviamo un'ultima volta

git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Already up-to-date.

Ta-da!


19
Questo è stato molto utile perché ho avuto molti errori di unione con i file binari (risorse artistiche) e la fusione di questi sembra non riuscire sempre, quindi ho bisogno di sovrascriverlo sempre con il nuovo file e non "unire"
petrocket

188
! attento Il significato di --ours e --theirs è invertito. --ours == il telecomando. --theirs == local. Vedigit merge --help
mmell

57
Nel mio caso, confermo che --theirs = repository remoto, --ours = il mio repository locale. È l'opposto dei commenti di @mmell.
Aryo,

24
@mmell Solo su un rebase, a quanto pare. Vedithis question
Navin,

184
Ragazzi, "nostri" e "loro" sono relativi al fatto che vi state unendo o meno. Se ti stai unendo , allora "nostro" significa il ramo in cui ti stai unendo, e "loro" è il ramo in cui ti stai unendo. Quando ti stai riassegnando , allora "nostro" significa che ti stai impegnando , mentre "loro" si riferisce ai commit che si desidera modificare.

736

Trovo che gli strumenti di unione raramente mi aiutino a comprendere il conflitto o la risoluzione. Di solito ho più successo guardando gli indicatori di conflitto in un editor di testo e usando git log come supplemento.

Ecco alcuni consigli:

Suggerimento Uno

La cosa migliore che ho trovato è usare lo stile di conflitto di unione "diff3":

git config merge.conflictstyle diff3

Questo produce marcatori di conflitto come questo:

<<<<<<<
Changes made on the branch that is being merged into. In most cases,
this is the branch that I have currently checked out (i.e. HEAD).
|||||||
The common ancestor version.
=======
Changes made on the branch that is being merged in. This is often a 
feature/topic branch.
>>>>>>>

La sezione centrale è l'aspetto dell'antenato comune. Questo è utile perché puoi confrontarlo con le versioni top e bottom per avere un'idea migliore di ciò che è stato modificato su ciascun ramo, il che ti dà un'idea migliore di quale fosse lo scopo di ogni cambiamento.

Se il conflitto è solo di poche righe, ciò rende il conflitto molto evidente. (Sapere come risolvere un conflitto è molto diverso; devi essere consapevole di ciò su cui altre persone stanno lavorando. Se sei confuso, probabilmente è meglio chiamare quella persona nella tua stanza in modo che possano vedere quello che stai guardando a.)

Se il conflitto è più lungo, taglierò e incollerò ciascuna delle tre sezioni in tre file separati, come "mio", "comune" e "loro".

Quindi posso eseguire i seguenti comandi per vedere i due hunk diff che hanno causato il conflitto:

diff common mine
diff common theirs

Ciò non equivale a utilizzare uno strumento di unione, poiché uno strumento di fusione includerà anche tutti gli hunk differenziali non in conflitto. Trovo che sia fonte di distrazione.

Suggerimento due

Qualcuno lo ha già menzionato, ma comprendere l'intenzione dietro ogni pezzo diff è generalmente molto utile per capire da dove proviene un conflitto e come gestirlo.

git log --merge -p <name of file>

Questo mostra tutti i commit che hanno toccato quel file tra l'antenato comune e le due teste che stai unendo. (Quindi non include i commit che esistono già in entrambi i rami prima della fusione.) Questo ti aiuta a ignorare diff hunk che chiaramente non sono un fattore nel tuo conflitto attuale.

Suggerimento tre

Verifica le modifiche con strumenti automatizzati.

Se si dispone di test automatici, eseguirli. Se hai un pelucchi , eseguilo . Se è un progetto costruibile, crealo prima di impegnarti, ecc. In tutti i casi, devi fare un po 'di test per assicurarti che le tue modifiche non abbiano interrotto nulla. (Diamine, anche un'unione senza conflitti può rompere il codice di lavoro.)

Suggerimento quattro

Pianificare in anticipo; comunicare con i colleghi.

Pianificare in anticipo ed essere consapevoli di ciò su cui gli altri stanno lavorando può aiutare a prevenire l'unione dei conflitti e / o aiutare a risolverli prima, mentre i dettagli sono ancora in mente.

Ad esempio, se sai che tu e un'altra persona state entrambi lavorando su refactoring diversi che influiranno entrambi sullo stesso set di file, dovreste parlarvi in ​​anticipo e avere un senso migliore per quali tipi di modifiche ognuno di voi è fabbricazione. Potresti risparmiare considerevolmente tempo e sforzi se conduci le modifiche pianificate in serie piuttosto che in parallelo.

Per i principali refactoring che attraversano una vasta porzione di codice, dovresti considerare fortemente di lavorare in serie: tutti smettono di lavorare su quell'area del codice mentre una persona esegue il refactoring completo.

Se non riesci a lavorare in serie (a causa della pressione del tempo, forse), allora comunicare sui conflitti di fusione previsti ti aiuta almeno a risolvere i problemi prima, mentre i dettagli sono ancora in mente. Ad esempio, se un collega sta effettuando una serie dirompente di commit nel corso di un periodo di una settimana, è possibile scegliere di unire / rifilare su quel ramo di collaboratori una o due volte al giorno durante quella settimana. In questo modo, se trovi conflitti di unione / rebase, puoi risolverli più rapidamente che se aspetti qualche settimana per unire tutto insieme in un unico grande nodulo.

Suggerimento cinque

Se non sei sicuro di unire, non forzarlo.

La fusione può sembrare schiacciante, specialmente quando ci sono molti file in conflitto e gli indicatori di conflitto coprono centinaia di righe. Spesso durante la stima dei progetti software non includiamo abbastanza tempo per gli elementi generali come la gestione di un'unione nodosa, quindi è come un vero e proprio trascinamento passare diverse ore a dissezionare ogni conflitto.

A lungo termine, pianificare in anticipo ed essere consapevoli di ciò su cui gli altri stanno lavorando sono gli strumenti migliori per anticipare i conflitti di unione e prepararsi a risolverli correttamente in meno tempo.


6
L'opzione diff3 è un'ottima funzionalità da avere con le fusioni. L'unica GUI che ho incontrato mostra che è Perforce p4merge, che può essere installato e utilizzato separatamente dagli altri strumenti di Perforce (che non ho usato, ma di cui ho sentito lamentele).
alxndr,

3
Dopo un tentativo di rebase che ha provocato un conflitto di unione: $ git log --merge -p output build.xml: fatale: --merge senza MERGE_HEAD?
Ed Randall,

cosa succede se ho modifiche su un file da branch1 e la cancellazione di quel file in branch2. Come posso risolvere quel conflitto di unione? Esiste un modo per usare git in cui posso unirli mantenendo i cambiamenti di un ramo?
Miele,

git config merge.conflictstyle diff3- grazie Signore. Questo è fantastico e mi ha liberato dal tentativo di trovare (e pagare $$) per una buona interfaccia grafica a 3 vie. IMO questo è meglio perché mostra l'antenato comune nonché locale / remoto e mostra le ultime righe del registro di commit che (AFAIK) nessuna GUI fa. I commit sicuramente ti aiuteranno a identificare quale codice appartiene a quale ramo.
ffxsam,

Ho scoperto che a volte il conflitto diff3 si traduce in enormi diff hunk che sono in gran parte identici, mentre il default produrrà hunk più piccoli, più gestibili. Sfortunatamente, non ho un riproduttore che posso usare per una segnalazione di bug. Ma se riscontri questo problema potresti considerare di disattivare temporaneamente l'opzione.
Dave Abrahams,

348
  1. Identifica quali file sono in conflitto (Git dovrebbe dirti questo).

  2. Apri ogni file ed esamina le differenze; Git li delimita. Speriamo che sia ovvio quale versione di ciascun blocco conservare. Potrebbe essere necessario discuterne con altri sviluppatori che hanno commesso il codice.

  3. Dopo aver risolto il conflitto in un file git add the_file.

  4. Dopo aver risolto tutti i conflitti, esegui git rebase --continueo qualsiasi altro comando Git abbia detto di eseguire al termine.


38
@Justin Pensa a Git come al monitoraggio dei contenuti piuttosto che al tracciamento dei file. Quindi è facile vedere che il contenuto che hai aggiornato non è nel repository e deve essere aggiunto. Questo modo di pensare spiega anche perché Git non tiene traccia delle cartelle vuote: sebbene siano tecnicamente file, non c'è alcun contenuto da tracciare.
Gareth,

7
il contenuto è lì, il conflitto si verifica perché c'è 2 versione del contenuto. Pertanto "git add" non sembra corretto. E non funziona (git add, git commit) se si desidera eseguire il commit di un solo file dopo la risoluzione del conflitto ("fatale: impossibile eseguire un commit parziale durante un'unione")
Dainius,

1
Sì, tecnicamente, questo risponde alla domanda che è stata posta, ma non è una risposta utilizzabile, a mio avviso, scusate. Che senso ha fare un ramo uguale a un altro? Naturalmente una fusione avrà conflitti.
Giovedì

5
Thulfir: chi ha detto qualcosa su come rendere un ramo uguale a un altro? Esistono diversi scenari in cui è necessario unire, senza "rendere un ramo uguale a un altro". Uno è quando hai finito con un ramo di sviluppo e vuoi incorporare le sue modifiche nel ramo principale; successivamente, il ramo di sviluppo può essere eliminato. Un altro è quando si desidera reimpostare il ramo di sviluppo, al fine di facilitare l'eventuale fusione finale nel master.
Teemu Leisti,

4
@JustinGrant mette in git addscena i file nell'indice; essa non aggiunge nulla al repository. git commitaggiunge cose al repository. Questo utilizzo ha senso per le fusioni: l'unione mette automaticamente in scena tutte le modifiche che possono essere unite automaticamente; è tua responsabilità unire il resto delle modifiche e aggiungerle all'indice quando hai finito.
Mark E. Haase,

105

Controlla le risposte nella domanda Stack Overflow Interruzione di un'unione in Git , in particolare la risposta di Charles Bailey che mostra come visualizzare le diverse versioni del file con problemi, ad esempio,

# Common base version of the file.
git show :1:some_file.cpp

# 'Ours' version of the file.
git show :2:some_file.cpp

# 'Theirs' version of the file.
git show :3:some_file.cpp

Controlla anche l'opzione "-m" per "git checkout -m" - ti consente di estrarre le diverse mosche nel tuo spazio di lavoro
qneill

Questo mi ha salvato. Guardare ogni file separatamente mi ha permesso di ricordare cosa stavo cercando in ogni ramo. Quindi potrei prendere la decisione di scegliere.
Rohmer,

99

I conflitti di unione si verificano quando vengono apportate modifiche a un file contemporaneamente. Ecco come risolverlo.

git CLI

Ecco alcuni semplici passaggi da eseguire quando si entra in uno stato di conflitto:

  1. Nota l'elenco dei file in conflitto con: git status(nella Unmerged pathssezione).
  2. Risolvi i conflitti separatamente per ogni file con uno dei seguenti approcci:

    • Utilizzare la GUI per risolvere i conflitti: git mergetool(il modo più semplice).

    • Per accettare remote / altra versione, uso: git checkout --theirs path/file. Ciò rifiuterà qualsiasi modifica locale effettuata per quel file.

    • Per accettare local / la nostra versione, utilizzare: git checkout --ours path/file

      Tuttavia devi stare attento, poiché i cambiamenti remoti che i conflitti sono stati fatti per qualche motivo.

      Correlati: Qual è il significato preciso di "nostro" e "loro" in git?

    • Modifica manualmente i file in conflitto e cerca il blocco di codice tra <<<<</ >>>>>quindi scegli la versione dall'alto o dal basso =====. Vedi: Come vengono presentati i conflitti .

    • I conflitti di percorso e nome file possono essere risolti con git add/ git rm.

  3. Infine, rivedere i file pronti per commettere utilizzando: git status.

    Se avete ancora tutti i file sotto Unmerged paths, ed hanno consentito di risolvere il conflitto manualmente, poi lasciare Git sapere che risolto da: git add path/file.

  4. Se tutti i conflitti sono stati risolti correttamente, eseguire il commit delle modifiche tramite: git commit -ae premere su remoto come al solito.

Vedi anche: Risoluzione di un conflitto di unione dalla riga di comando su GitHub

Per esercitazioni pratiche, consultare: Scenario 5 - Correzione dei conflitti di unione di Katacoda .

DiffMerge

Ho usato con successo DiffMerge che può confrontare visivamente e unire i file su Windows, macOS e Linux / Unix.

Può mostrare graficamente le modifiche tra 3 file e consente l'unione automatica (quando è sicuro farlo) e il pieno controllo sulla modifica del file risultante.

DiffMerge

Fonte immagine: DiffMerge (screenshot di Linux)

Basta scaricarlo ed eseguirlo in repository come:

git mergetool -t diffmerge .

Mac OS

Su macOS è possibile installare tramite:

brew install caskroom/cask/brew-cask
brew cask install diffmerge

E probabilmente (se non fornito) è necessario il seguente wrapper extra semplice inserito nel PERCORSO (ad es. /usr/bin):

#!/bin/sh
DIFFMERGE_PATH=/Applications/DiffMerge.app
DIFFMERGE_EXE=${DIFFMERGE_PATH}/Contents/MacOS/DiffMerge
exec ${DIFFMERGE_EXE} --nosplash "$@"

Quindi è possibile utilizzare le seguenti scorciatoie da tastiera:

  • - Alt- Up/ Downper passare alle modifiche precedenti / successive.
  • - Alt- Left/ Rightper accettare il cambiamento da sinistra o destra

In alternativa puoi usare opendiff (parte di Xcode Tools) che ti permette di unire due file o directory per creare un terzo file o directory.


79

Se stai effettuando piccoli commit frequenti, inizia guardando i commenti di commit con git log --merge. Quindi git diffti mostrerà i conflitti.

Per i conflitti che coinvolgono più di poche righe, è più facile vedere cosa sta succedendo in uno strumento GUI esterno. Mi piace l'opendiff - Git supporta anche vimdiff, gvimdiff, kdiff3, tkdiff, meld, xxdiff, emerge fuori dalla scatola e puoi installarne altri: git config merge.tool "your.tool"imposterai lo strumento scelto e poigit mergetool dopo una fusione fallita ti mostrerà le differenze nel contesto.

Ogni volta che modifichi un file per risolvere un conflitto, git add filenameaggiornerà l'indice e il tuo diff non lo mostrerà più. Quando tutti i conflitti vengono gestiti e i loro file sono stati modificati git add, git commitcompleterà la tua unione.


8
Usare "git add" è il vero trucco qui. Potresti non voler nemmeno impegnarti (forse vuoi stash), ma devi fare "git add" per completare l'unione. Penso che mergetool faccia l'aggiunta per te (anche se non è nella manpage), ma se fai l'unione manualmente, devi usare "git add" per completarlo (anche se non vuoi impegnarti).
nobar,

47

Guarda come sono presentati i conflitti o, in Git, ilgit merge documentazione per capire quali sono i marker di conflitto di unione.

Inoltre, la sezione Come risolvere i conflitti spiega come risolvere i conflitti:

Dopo aver visto un conflitto, puoi fare due cose:

  • Decidi di non unirti. Le uniche pulizie necessarie sono reimpostare il file di indice sul HEADcommit per invertire 2. e ripulire le modifiche dell'albero di lavoro apportate da 2. e 3 .; git merge --abortpuò essere usato per questo.

  • Risolvi i conflitti. Git segnerà i conflitti nell'albero di lavoro. Modifica i file in forma e git addli all'indice. Utilizzare git commitper sigillare l'affare.

Puoi risolvere il conflitto con una serie di strumenti:

  • Usa una fusione. git mergetoolper lanciare una fusione grafica che ti guiderà attraverso l'unione.

  • Guarda le differenze. git diffmostrerà un diff a tre vie, mettendo in evidenza i cambiamenti sia dal HEADe MERGE_HEADversioni.

  • Guarda le differenze da ogni ramo. git log --merge -p <path>mostrerà prima le differenze per la HEADversione e poi per la MERGE_HEADversione.

  • Guarda gli originali. git show :1:filenamemostra l'antenato comune, git show :2:filenamemostra la HEADversione e git show :3:filenamemostra la MERGE_HEADversione.

Puoi anche leggere informazioni su come unire gli indicatori di conflitto e come risolverli nella sezione del libro Pro Git Conflitti di unione di base .


42

Voglio la mia o la loro versione per intero, o voglio rivedere le singole modifiche e decidere per ognuna di esse.

Accetta completamente la mia o la loro versione :

Accetta la mia versione (locale, la nostra):

git checkout --ours -- <filename>
git add <filename>              # Marks conflict as resolved
git commit -m "merged bla bla"  # An "empty" commit

Accetta la loro versione (remota, loro):

git checkout --theirs -- <filename>
git add <filename>
git commit -m "merged bla bla"

Se si desidera eseguire l' esecuzione di tutti i file di conflitto :

git merge --strategy-option ours

o

git merge --strategy-option theirs

Rivedi tutte le modifiche e accettale singolarmente

  1. git mergetool
  2. Rivedi le modifiche e accetta una delle versioni per ognuna di esse.
  3. git add <filename>
  4. git commit -m "merged bla bla"

L'impostazione predefinita mergetoolfunziona nella riga di comando . Come utilizzare un mergetool da riga di comando dovrebbe essere una domanda separata.

È inoltre possibile installare lo strumento visivo per questo, ad esempio melded eseguire

git mergetool -t meld

Aprirà la versione locale (la nostra), la "base" o la versione "unita" (il risultato attuale della fusione) e la versione remota (la loro). Salva la versione unita quando hai finito, esegui git mergetool -t meldnuovamente fino a quando non ottieni "Nessun file deve essere unito", quindi vai ai passaggi 3. e 4.


Questo comando: git checkout --theirs - <nomefile> ha cambiato TUTTI i file nel loro, non solo <nomefile>
Donato il

In realtà mi sbagliavo. Questo aggiorna solo il file specificato.
Donato,

40

Per gli utenti Emacs che desiderano risolvere i conflitti di unione semi-manualmente:

git diff --name-status --diff-filter=U

mostra tutti i file che richiedono la risoluzione dei conflitti.

Apri uno di questi file uno per uno o tutti in una volta:

emacs $(git diff --name-only --diff-filter=U)

Quando si visita un buffer che richiede modifiche in Emacs, digitare

ALT+x vc-resolve-conflicts

Questo aprirà tre buffer (il mio, il loro e il buffer di output). Navigare premendo 'n' (regione successiva), 'p' (regione di previsione). Premere 'a' e 'b' per copiare rispettivamente la mia o la loro regione nel buffer di output. E / o modifica direttamente il buffer di output.

Al termine: premere 'q'. Emacs ti chiede se vuoi salvare questo buffer: sì. Dopo aver terminato un buffer contrassegnarlo come risolto eseguendo dal teriminale:

git add FILENAME

Al termine, digitare tutti i buffer

git commit

per finire l'unione.


33

Bonus:

Parlando di pull / fetch / merge nelle risposte sopra, vorrei condividere un trucco interessante e produttivo,

git pull --rebase

Questo comando sopra è il comando più utile nella mia vita git che ha fatto risparmiare un sacco di tempo.

Prima di inviare la modifica appena impegnata al server remoto, provare git pull --rebasepiuttosto git pulle manualemerge e sincronizzerà automaticamente le ultime modifiche del server remoto (con un fetch + merge) e metterà il tuo ultimo commit locale nella parte superiore nel registro git. Non è necessario preoccuparsi di estrazione / unione manuale.

In caso di conflitto, basta usare

git mergetool
git add conflict_file
git rebase --continue

Per i dettagli, consultare: http://gitolite.com/git-pull--rebase


32

Semplicemente, se sai bene che i cambiamenti in uno dei repository non sono importanti e vuoi risolvere tutti i cambiamenti a favore dell'altro, usa:

git checkout . --ours

per risolvere le modifiche a favore del tuo repository , o

git checkout . --theirs

per risolvere le modifiche a favore dell'altro o del repository principale .

Altrimenti dovrai utilizzare uno strumento di unione della GUI per scorrere i file uno alla volta, ad esempio lo strumento di unione p4mergeo scrivere il nome di qualcuno che hai già installato

git mergetool -t p4merge

e dopo aver finito un file, dovrai salvare e chiudere, quindi si aprirà quello successivo.


2
git checkout. - i loro hanno risolto il mio problema grazie
Ramesh Chand

se si preferisce risolvere manualmente i conflitti, provare ad aprire la cartella in Visual Studio Code, contrassegna i file con conflitti e colora le linee di conflitto all'interno di ognuno
Mohamed Selim

31

Seguire i passaggi seguenti per correggere i conflitti di unione in Git:

  1. Controlla lo stato Git: stato git

  2. Ottieni il patchset: git fetch (controlla la patch giusta dal tuo commit Git)

  3. Acquista un ramo locale (temp1 nel mio esempio qui): git checkout -b temp1

  4. Estrai i contenuti recenti dal master: git pull --rebase origin master

  5. Avvia il mergetool e controlla i conflitti e correggili ... e controlla le modifiche nel ramo remoto con il tuo ramo corrente: git mergetool

  6. Controlla di nuovo lo stato: stato git

  7. Elimina i file indesiderati creati localmente da mergetool, di solito mergetool crea file extra con estensione * .orig. Si prega di eliminare quel file in quanto è solo il duplicato e correggere le modifiche localmente e aggiungere la versione corretta dei file. aggiungi #your_changed_correct_files

  8. Controlla di nuovo lo stato: stato git

  9. Conferma le modifiche sullo stesso ID commit (questo evita un nuovo set di patch separato): git commit --amend

  10. Invia al ramo principale: git push (nel tuo repository Git)


28

Ci sono 3 passaggi:

  1. Trova quali file causano conflitti tramite comando

    git status
    
  2. Controlla i file, in cui troverai i conflitti contrassegnati come

    <<<<<<<<head
    blablabla
    
  3. Modificalo nel modo desiderato, quindi esegui il commit con i comandi

    git add solved_conflicts_files
    git commit -m 'merge msg'
    

Ha funzionato per me! Grazie!
Nuwan Jayawardene,

È necessario prestare attenzione se lo si fa durante rebase. Dovresti usare git rebase - continua invece di git commit
Samuel Dauzon,

27

È possibile correggere i conflitti di unione in diversi modi, come altri hanno spiegato in dettaglio.

Penso che la vera chiave sia sapere come fluiscono i cambiamenti con i repository locali e remoti. La chiave di ciò è capire i rami di tracciamento. Ho scoperto che penso al ramo di tracciamento come al 'pezzo mancante nel mezzo' tra me la mia directory locale, i file effettivi e il telecomando definito come origine.

Personalmente ho preso l'abitudine di 2 cose per evitare questo.

Invece di:

git add .
git commit -m"some msg"

Che ha due inconvenienti:

a) Vengono aggiunti tutti i file nuovi / modificati e ciò potrebbe includere alcune modifiche indesiderate.
b) Non riesci a rivedere prima l'elenco dei file.

Quindi invece faccio:

git add file,file2,file3...
git commit # Then type the files in the editor and save-quit.

In questo modo sei più deliberato su quali file vengono aggiunti e puoi anche rivedere l'elenco e pensare un po 'di più mentre usi l'editor per il messaggio. Trovo che migliora anche i miei messaggi di commit quando uso un editor a schermo intero anziché l' -mopzione.

[Aggiornamento - con il passare del tempo sono passato di più a:

git status # Make sure I know whats going on
git add .
git commit # Then use the editor

]

Inoltre (e più rilevante per la tua situazione), provo ad evitare:

git pull

o

git pull origin master.

perché pull implica un'unione e se hai modifiche locali che non volevi unire, puoi facilmente finire con un codice unito e / o unire conflitti per codice che non avrebbe dovuto essere unito.

Invece provo a fare

git checkout master
git fetch   
git rebase --hard origin/master # or whatever branch I want.

Potresti anche trovare utile questo:

git branch, fork, fetch, merge, rebase e clone, quali sono le differenze?


Ehi, ho capito un po 'la tua risposta. Ma dal momento che sono nuovo a confondere i conflitti con Github, penso che manchi qualcosa. Cosa succede alle tue modifiche locali quando lo fai git checkout mastere git fetch e git rebase --hard origin/master
Suhaib l'

Credo che dovresti aggiungere maggiori dettagli su cosa fare. Un altro esempio che mi confonde, di cui hai parlato nella tua risposta: lo faremo git add ., salverà le nostre modifiche locali in modo che possiamo seguire git checkout master? o sono due diversi scenari?
Suhaib,

@MichaelDurrant $ git rebase --hard origin/master b5a30cc159ba8dd error: unknown option hard 'utilizzo: git rebase [-i] [opzioni] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>] o: git rebase [-i] [ opzioni] [--exec <cmd>] [--onto <newbase>] --root [<branch>] o: git rebase --continue | --abort | --skip | --edit-todo `
likejudo

24

La risposta di CoolAJ86 riassume praticamente tutto. Nel caso in cui tu abbia cambiamenti in entrambi i rami nello stesso pezzo di codice dovrai fare un'unione manuale. Apri il file in conflitto in qualsiasi editor di testo e dovresti vedere la seguente struttura.

(Code not in Conflict)
>>>>>>>>>>>
(first alternative for conflict starts here)
Multiple code lines here
===========
(second alternative for conflict starts here)
Multiple code lines here too    
<<<<<<<<<<<
(Code not in conflict here)

Scegli una delle alternative o una combinazione di entrambi nel modo in cui vuoi che sia il nuovo codice, rimuovendo allo stesso tempo segni e parentesi angolari uguali.

git commit -a -m "commit message"
git push origin master

17
git log --merge -p [[--] path]

Non sembra funzionare sempre per me e di solito finisce per mostrare ogni commit che era diverso tra i due rami, questo succede anche quando si usa --per separare il percorso dal comando.

Quello che faccio per aggirare questo problema è aprire due righe di comando e in una corsa

git log ..$MERGED_IN_BRANCH --pretty=full -p [path]

e nell'altro

git log $MERGED_IN_BRANCH.. --pretty=full -p [path]

Sostituendo $MERGED_IN_BRANCHcon il ramo in cui mi sono unito e [path]con il file in conflitto. Questo comando registra tutti i commit, in forma di patch, tra ( ..) due commit. Se lasci un lato vuoto come nei comandi sopra, git userà automaticamente HEAD(il ramo in cui ti stai unendo in questo caso).

Ciò ti consentirà di vedere quali commit sono stati inseriti nel file nei due rami dopo che sono stati divergenti. Di solito rende molto più facile risolvere i conflitti.


16

utilizzando patience

Sono sorpreso che nessun altro abbia parlato della risoluzione dei conflitti utilizzando patiencela strategia ricorsiva di tipo merge. Per un conflitto di grande unione, usandopatience fornito buoni risultati per me. L'idea è che proverà ad abbinare i blocchi piuttosto che le singole linee.

Se ad esempio si modifica il rientro del programma, la strategia di unione Git predefinita a volte corrisponde a parentesi singole {che appartengono a funzioni diverse. Questo è evitato con patience:

git merge -s recursive -X patience other-branch

Dalla documentazione:

With this option, merge-recursive spends a little extra time to avoid 
mismerges that sometimes occur due to unimportant matching lines 
(e.g., braces from distinct functions). Use this when the branches to 
be merged have diverged wildly.

Confronto con l'antenato comune

Se hai un conflitto di unione e vuoi vedere ciò che gli altri avevano in mente durante la modifica del loro ramo, a volte è più facile confrontare il loro ramo direttamente con l'antenato comune (invece del nostro ramo). Per questo puoi usare merge-base:

git diff $(git merge-base <our-branch> <their-branch>) <their-branch>

Di solito, vuoi solo vedere le modifiche per un determinato file:

git diff $(git merge-base <our-branch> <their-branch>) <their-branch> <file>

Nel mio caso questo non ha risolto bene i conflitti di unione, poiché per qualche motivo ha mantenuto linee di configurazione duplicate nei progetti C #. Anche se era più amichevole di TUTTO IL FILE È DIFFERENTE, che avevo prima
Mathijs Segers

15

A partire dal 12 dicembre 2016, puoi unire le filiali e risolvere i conflitti su github.com

Pertanto, se non si desidera utilizzare la riga di comando o altri strumenti di terze parti offerti qui dalle risposte precedenti , utilizzare lo strumento nativo di GitHub.

Questo post sul blog spiega in dettaglio, ma le basi sono che quando si uniscono due rami tramite l'interfaccia utente, ora vedrai un'opzione di "risoluzione dei conflitti" che ti porterà a un editor che ti consente di affrontare questi conflitti di unione.

inserisci qui la descrizione dell'immagine


non si tratta di github, quindi ho votato in giù quella che ritengo una risposta molto scadente.
mschuett,

1
@mschuett ha ragione, la domanda è "come risolvere i conflitti in git", non "come risolvere i conflitti in github". C'è una differenza e ci sono già troppe persone che pensano che git e github siano la stessa cosa, quindi qualsiasi cosa che propaghi quella sensazione è sbagliata.
Patrick Mevzek,

15

Se desideri unire dal ramo (test) al master, puoi seguire questi passaggi:

Passaggio 1 : vai al ramo

git checkout test

Passaggio 2 :

git pull --rebase origin master

Passaggio 3 : se ci sono alcuni conflitti, vai a questi file per modificarlo.

Passaggio 4 : aggiungere queste modifiche

git add #your_changes_files

Passaggio 5 :

git rebase --continue

Passaggio 6 : se il conflitto persiste, tornare nuovamente al passaggio 3. Se non si verificano conflitti, attenersi alla seguente procedura:

git push origin +test

Step 7 : E poi non c'è conflitto tra test e master. Puoi usare la fusione direttamente.


13

Seguo sempre i passaggi seguenti per evitare conflitti.

  • git checkout master (Vieni nel ramo master)
  • git pull (aggiorna il tuo master per ottenere l'ultimo codice)
  • git checkout -b mybranch (Verifica un nuovo ramo e inizia a lavorare su quel ramo in modo che il tuo padrone rimanga sempre in cima al tronco.)
  • git add. AND git commit AND git push (sul tuo ramo locale dopo le modifiche)
  • git checkout master (Torna dal tuo master.)

Ora puoi fare lo stesso e mantenere il numero di filiali locali che desideri e lavorare simultaneamente mentre eseguo un checkout git alla tua filiale quando è necessario.


12

I conflitti di unione potrebbero verificarsi in diverse situazioni:

  • Quando si esegue "git fetch" e quindi "git merge"
  • Quando si esegue "git fetch" e quindi "git rebase"
  • Quando si esegue "git pull" (che in realtà è uguale a una delle condizioni sopra menzionate)
  • Quando si esegue "git stash pop"
  • Quando si applicano patch git (commit che vengono esportati in file da trasferire, ad esempio, via e-mail)

È necessario installare uno strumento di unione compatibile con Git per risolvere i conflitti. Personalmente uso KDiff3 e l'ho trovato utile e utile. Puoi scaricare la sua versione di Windows qui:

https://sourceforge.net/projects/kdiff3/files/

A proposito, se installi Git Extensions c'è un'opzione nella sua procedura guidata di installazione per installare Kdiff3.

Quindi installa git configs per usare Kdiff come suo mergetool:

$ git config --global --add merge.tool kdiff3
$ git config --global --add mergetool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
$ git config --global --add mergetool.kdiff3.trustExitCode false

$ git config --global --add diff.guitool kdiff3
$ git config --global --add difftool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
$ git config --global --add difftool.kdiff3.trustExitCode false

(Ricorda di sostituire il percorso con il percorso effettivo del file exe di Kdiff.)

Quindi ogni volta che incontri un conflitto di unione devi solo eseguire questo comando:

$git mergetool

Quindi apre Kdiff3 e cerca innanzitutto di risolvere automaticamente i conflitti di unione. La maggior parte dei conflitti verrebbe risolta spontaneamente e sarà necessario correggere il resto manualmente.

Ecco come appare Kdiff3:

Inserisci qui la descrizione dell'immagine

Quindi, una volta terminato, salva il file e passa al file successivo con conflitto e fai di nuovo la stessa cosa fino a quando tutti i conflitti non vengono risolti.

Per verificare se tutto è stato unito correttamente, esegui nuovamente il comando mergetool, dovresti ottenere questo risultato:

$git mergetool
No files need merging

8

Questa risposta è aggiungere un'alternativa per quegli utenti VIM come me che preferiscono fare tutto all'interno dell'editor.


TL; DR

inserisci qui la descrizione dell'immagine


Tpope ha ideato questo fantastico plugin per VIM chiamato fuggitivo . Una volta installato, è possibile eseguire :Gstatusper verificare i file in conflitto e :Gdiffper aprire Git in un'unione di 3 modi.

Una volta nella fusione a 3 vie, il fuggitivo ti permetterà di ottenere i cambiamenti di uno dei rami che stai unendo nel modo seguente:

  • :diffget //2, ottieni le modifiche dal ramo originale ( HEAD ):
  • :diffget //3, ottieni le modifiche dalla fusione del ramo:

Una volta terminata l'unione del file, digitare :Gwriteil buffer unito. Vimcasts ha pubblicato un ottimo video che spiega in dettaglio questi passaggi.


6

Gitlense per codice VS.

Puoi provare Gitlense per VS Code, sono le caratteristiche principali:

3. Risolvi facilmente i conflitti.

Mi piace già questa funzione:

inserisci qui la descrizione dell'immagine

2. Colpa della linea corrente.

inserisci qui la descrizione dell'immagine

3. Colpa della grondaia

inserisci qui la descrizione dell'immagine

4. Colpa della barra di stato

inserisci qui la descrizione dell'immagine

E ci sono molte funzionalità che puoi controllare qui .


5

git fetch
git verifica il tuo
master git rebase master

In questo passaggio proverai a risolvere il conflitto usando il tuo IDE preferito

Puoi seguire questo link per controllare ho per risolvere il conflitto nel file
https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/

git aggiungi
git rebase --continua
git commit - modifica
git push origine TESTA: refs / bozze / master (premi come una bozza)

Ora tutto va bene e troverai il tuo impegno in Gerrit

Spero che questo possa aiutare tutti riguardo a questo problema.


3

Prova Visual Studio Code per la modifica se non lo sei già. Quello che fa è dopo aver provato a fondere (e finire in conflitti di unione). Il codice SV rileva automaticamente i conflitti di unione.

Può aiutarti molto bene mostrando quali sono le modifiche apportate a quella originale e se dovresti accettare incomingo

current change(intendendo quello originale prima della fusione) '?.

Mi ha aiutato e può funzionare anche per te!

PS: Funzionerà solo se hai configurato git con il tuo codice e Visual Studio Code.


2

Un modo più sicuro per risolvere i conflitti è usare git-mediate (le soluzioni comuni suggerite qui sono piuttosto soggette a errori).

Vedi questo post per una rapida introduzione su come usarlo.


2

Per coloro che usano Visual Studio (2015 nel mio caso)

  1. Chiudi il tuo progetto in VS. Soprattutto nei grandi progetti VS tende a impazzire quando si fonde con l'interfaccia utente.

  2. Esegui l'unione nel prompt dei comandi.

    git checkout target_branch

    git merge source_branch

  3. Quindi apri il progetto in VS e vai a Team Explorer -> Branch. Ora c'è un messaggio che dice che Merge è in sospeso e i file in conflitto sono elencati proprio sotto il messaggio.

  4. Fai clic sul file in conflitto e avrai la possibilità di unire, confrontare, prendere la fonte, prendere la destinazione. Lo strumento di unione in VS è molto facile da usare.


Sto usando VS Code 2017 su un progetto molto grande e non ho bisogno di chiudere il progetto. Lo gestisce abbastanza bene :)
protoEvangelion

2

Se stai usando intelliJ come IDE Prova a unire parent al tuo ramo di

git checkout <localbranch>
git merge origin/<remotebranch>

Mostrerà tutti i conflitti come questo

A_MBPro: test anu $ git merge origin / Auto-merging src / test / java / com /.../ TestClass.java CONFLICT (contenuto): unisci conflitto in src / test / java / com /.../ TestClass.java

Ora nota che il file TestClass.java è mostrato in rosso in intelliJ. Verrà mostrato anche lo stato git

Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified:   src/test/java/com/.../TestClass.java

Apri il file in intelliJ, avrà sezioni con

  <<<<<<< HEAD
    public void testMethod() {
    }
    =======
    public void testMethod() { ...
    }
    >>>>>>> origin/<remotebranch>

dove HEAD sono le modifiche sulla filiale locale e l'origine / sono le modifiche dalla filiale remota. Qui tieni le cose che ti servono e rimuovi quelle che non ti servono, dopodiché i normali passaggi dovrebbero fare. Questo è

   git add TestClass.java
   git commit -m "commit message"
   git push

2

Sto usando il Visual Code di Microsoft per risolvere i conflitti. È molto semplice da usare. Tengo il mio progetto aperto nell'area di lavoro. Rileva ed evidenzia i conflitti, inoltre offre opzioni GUI per selezionare qualsiasi cambiamento che voglio mantenere da HEAD o in arrivo. inserisci qui la descrizione dell'immagine

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.