Vraag Hoe samenvoegconflicten in Git op te lossen


Is er een goede manier om uit te leggen hoe je samenvoegconflicten in Git kunt oplossen?


4123
2017-10-02 11:31


oorsprong


antwoorden:


Proberen: git mergetool

Het opent een GUI die je door elk conflict leidt, en je kunt kiezen hoe je wilt samenvoegen. Soms vereist het een beetje handbewerking achteraf, maar meestal is het genoeg op zich. Het is veel beter dan het hele ding met de hand te doen, zeker.

Zoals bij @JoshGlover commentaar:

De opdracht opent niet noodzakelijk een GUI tenzij u er een installeert. hardlopen git mergetool voor mij resulteerde in vimdiff gebruikt worden. U kunt in plaats daarvan een van de volgende hulpmiddelen installeren om het te gebruiken: meld, opendiff, kdiff3, tkdiff, xxdiff, tortoisemerge, gvimdiff, diffuse, ecmerge, p4merge, araxis, vimdiff, emerge.

Hieronder is de voorbeeldprocedure te gebruiken vimdiff voor op te lossen samenvoegconflicten. Gebaseerd op deze link

Stap 1: Voer de volgende opdrachten uit in uw terminal

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

Hiermee wordt vimdiff ingesteld als het standaard samenvoeghulpprogramma.

Stap 2: Voer het volgende commando uit in terminal

git mergetool

Stap 3: U ziet een vimdiff-display in het volgende formaat

  +----------------------+
  |       |      |       |
  |LOCAL  |BASE  |REMOTE |
  |       |      |       |
  +----------------------+
  |      MERGED          |
  |                      |
  +----------------------+

Deze 4 weergaven zijn

LOCAL - dit is een bestand van de huidige branch

BASE - gemeenschappelijke voorouder, hoe het bestand er vóór beide wijzigingen uitzag

REMOTE - bestand dat u invoegt in uw branche

SAMENGESTELD - resultaat samenvoegen, dit wordt opgeslagen in de repository

U kunt tussen deze weergaven navigeren met behulp van ctrl+w. U kunt rechtstreeks de SAMENGESTELDE weergave bereiken met ctrl+w gevolgd door j.

Meer info over vimdiff navigatie hier en hier

Stap 4. U kunt de SAMENGESTELDE weergave op de volgende manier bewerken

Als u wijzigingen wilt ontvangen van REMOTE

:diffg RE  

Als u wijzigingen wilt ontvangen van BASE

:diffg BA  

Als u wijzigingen wilt ontvangen van LOCAL

:diffg LO 

Stap 5. Opslaan, afsluiten, vastleggen en opruimen

:wqa opslaan en afsluiten van vi

git commit -m "message"

git clean Verwijder extra bestanden (bijvoorbeeld * .orig) gemaakt met een diff-tool.


2415
2017-10-02 17:50



Hier is een waarschijnlijke use-case, vanaf de top:

Je gaat enkele veranderingen aanbrengen, maar oeps, je bent niet up-to-date:

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.

U wordt dus up-to-date en probeert het opnieuw, maar heeft een conflict:

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.

Dus u besluit de wijzigingen te bekijken:

git mergetool

Oh mij, oh my, stroomopwaarts veranderde sommige dingen, maar gewoon om mijn veranderingen te gebruiken ... nee ... hun veranderingen ...

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

En dan proberen we een laatste keer

git pull origin master

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

Ta-da!


1607
2017-08-04 17:04



Ik merk dat samenvoegingshulpprogramma's me zelden helpen het conflict of de resolutie te begrijpen. Meestal kijk ik meer succesvol naar de conflictmarkers in een teksteditor en gebruik ik git log als een aanvulling.

Hier zijn een paar tips:

Tip een

Het beste dat ik heb gevonden is om de "diff3" -stijl voor samenvoegconflicten te gebruiken:

git config merge.conflictstyle diff3

Dit levert conflictmarkers op zoals dit:

<<<<<<<
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.
>>>>>>>

Het middelste deel is hoe de gemeenschappelijke voorouder eruit zag. Dit is handig omdat je het kunt vergelijken met de bovenste en onderste versies om een ​​beter beeld te krijgen van wat er in elke branche is veranderd, waardoor je een beter idee krijgt van wat het doel van elke verandering was.

Als het conflict maar een paar regels is, maakt dit het conflict over het algemeen heel duidelijk. (Weten hoe je een conflict oplost, is heel anders, je moet weten waar andere mensen aan werken. Als je in de war bent, is het waarschijnlijk het beste om die persoon gewoon in je kamer te bellen zodat ze kunnen zien wat je zoekt op.)

Als het conflict langer is, knip en plak ik elk van de drie secties in drie afzonderlijke bestanden, zoals 'mine', 'common' en 'theirs'.

Vervolgens kan ik de volgende opdrachten uitvoeren om de twee diff-knuppels te bekijken die het conflict hebben veroorzaakt:

diff common mine
diff common theirs

Dit is niet hetzelfde als het gebruik van een samenvoeghulpprogramma, omdat een samenvoeghulpprogramma ook alle niet-conflicterende diff-hunks zal bevatten. Ik vind dat om af te leiden.

Tip twee

Iemand heeft dit al genoemd, maar het begrijpen van de intentie achter elke diff-hunk is over het algemeen zeer nuttig om te begrijpen waar een conflict vandaan komt en hoe ermee om te gaan.

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

Dit toont alle commits die dat bestand hebben aangeraakt tussen de gemeenschappelijke voorouder en de twee hoofden die u aan het samenvoegen bent. (Dus het bevat geen commits die al in beide takken bestaan ​​voordat ze worden samengevoegd.) Hiermee kun je diff hunks negeren die duidelijk geen factor zijn in je huidige conflict.

Tip drie

Verifieer uw wijzigingen met geautomatiseerde hulpmiddelen.

Als u geautomatiseerde tests hebt, voer die uit. Als je een ... hebt pluis, voer dat uit. Als het een buildable project is, bouw het dan voordat je commit, etc. In alle gevallen moet je een beetje testen om er zeker van te zijn dat je wijzigingen niets hebben gebroken. (Heck, zelfs een samenvoeging zonder conflicten kan de werkcode breken.)

Tip vier

Vooruit plannen; communiceren met collega's.

Door vooruit te plannen en op de hoogte te zijn van waar anderen aan werken, kan het voorkomen van samenvoegingsconflicten worden voorkomen en / of kunnen ze eerder worden opgelost - terwijl de details nog vers in het geheugen liggen.

Als u bijvoorbeeld weet dat u en een andere persoon beiden aan verschillende refactoring werken, die beide dezelfde reeks bestanden zullen beïnvloeden, moet u van tevoren met elkaar praten en een beter idee krijgen van welke soorten wijzigingen elk van u is making. U kunt veel tijd en moeite besparen als u de geplande wijzigingen serieel uitvoert in plaats van parallel.

Voor grote refactorings die een groot stuk code doorsnijden, zou je serieus moeten overwegen om serieel te werken: iedereen stopt met werken aan dat gedeelte van de code terwijl een persoon de volledige refactoring uitvoert.

Als je niet serieel kunt werken (vanwege tijdsdruk, misschien), dan kan communiceren over verwachte fusieconflicten je ten minste helpen de problemen eerder op te lossen terwijl de details nog vers in het geheugen liggen. Als een medewerker bijvoorbeeld een disruptieve reeks commits maakt in de loop van een periode van een week, kun je ervoor kiezen om diezelfde branche een of twee keer per dag gedurende die week te fuseren / rebasen. Op die manier kun je, als je wel weet dat er sprake is van samenvoegings- / rebaseconflicten, deze sneller oplossen dan wanneer je een paar weken wacht om alles samen te voegen in één grote klomp.

Tip vijf

Als u niet zeker bent van een samenvoeging, forceer het dan niet.

Samenvoegen kan overweldigend zijn, vooral wanneer er veel conflicterende bestanden zijn en de conflictmarkeringen honderden regels beslaan. Vaak nemen we bij het schatten van softwareprojecten niet genoeg tijd voor overheaditems, zoals het verwerken van een foute merge, dus het voelt als een echte sleur om verschillende uren te besteden aan het ontleden van elk conflict.

Op de lange termijn zijn vooruit plannen en bewust zijn van waar anderen aan werken de beste tools om te anticiperen op samenvoegconflicten en bereid je voor om ze op te lossen in minder tijd.


683
2017-09-28 21:08



  1. Identificeer welke bestanden in conflict zijn (Git zou je dit moeten vertellen).

  2. Open elk bestand en onderzoek de diff's; Git markeert ze. Hopelijk zal het duidelijk zijn welke versie van elk blok moet worden bewaard. Misschien moet je dit bespreken met mede-ontwikkelaars die de code hebben gepleegd.

  3. Zodra u het conflict in een bestand hebt opgelost git add the_file.

  4. Zodra je het hebt opgelost alle conflicten git rebase --continue of welke opdracht dan ook Git zei te doen wanneer je klaar bent.


321
2017-10-02 12:41



Bekijk de antwoorden in Stack Overflow-vraag Een fusie afbreken in Git, vooral Charles Bailey's antwoord die laat zien hoe de verschillende versies van het bestand met problemen kunnen worden bekeken, bijvoorbeeld

# 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

97
2017-10-03 15:15



Samenvoegconflicten vinden plaats wanneer tegelijkertijd wijzigingen in een bestand worden aangebracht. Hier is hoe het op te lossen.

git CLI

Hier volgen enkele eenvoudige stappen om te doen wanneer u in een conflictsituatie terechtkomt:

  1. Let op de lijst met conflicterende bestanden met: git status (onder Unmerged paths sectie).
  2. Los de conflicten afzonderlijk op voor elk bestand op een van de volgende manieren:

    • Gebruik GUI om de conflicten op te lossen: git mergetool (de makkelijkste manier).

    • Gebruik: om een ​​externe / andere versie te accepteren: git checkout --theirs path/file. Hiermee worden alle lokale wijzigingen geweigerd die u voor dat bestand hebt gedaan.

    • Gebruik: om onze lokale / onze versie te accepteren: git checkout --ours path/file

      Maar je moet voorzichtig zijn, omdat op afstand veranderingen die conflicten werden gedaan om een ​​of andere reden.

      Verwant: Wat is de precieze betekenis van "de onze" en "de hunne" in git?

    • Bewerk de conflicterende bestanden handmatig en zoek naar het codeblok ertussen <<<<</>>>>> kies vervolgens de versie van boven of onder =====. Zien: Hoe conflicten worden gepresenteerd.

    • Pad- en bestandsnaamconflicten kunnen worden opgelost door git add/git rm.

  3. Beoordeel tot slot de bestanden die gereed zijn voor commit met behulp van: git status.

    Als je nog steeds bestanden hebt onder Unmerged paths, en je hebt het conflict handmatig opgelost, laat Git dan weten dat je het hebt opgelost door: git add path/file.

  4. Als alle conflicten met succes zijn opgelost, verbindt u de wijzigingen door: git commit -a en druk op de afstandsbediening zoals gebruikelijk.

Zie ook: Een samenvoegconflict oplossen vanaf de opdrachtregel bij GitHub

DiffMerge

Ik heb het met succes gebruikt DiffMerge die bestanden visueel kan vergelijken en samenvoegen op Windows, macOS en Linux / Unix.

Het kan grafisch de veranderingen tussen 3 bestanden tonen en het maakt automatische samenvoeging mogelijk (wanneer dat veilig is) en volledige controle over het bewerken van het resulterende bestand.

DiffMerge

Afbeeldingsbron: DiffMerge (Screenshot van Linux)

Gewoon downloaden en uitvoeren in repo als:

git mergetool -t diffmerge .

MacOS

Op macOS kunt u installeren via:

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

En waarschijnlijk (indien niet meegeleverd) hebt u de volgende extra eenvoudige wrapper nodig die in uw PATH is geplaatst (bijv. /usr/bin):

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

Dan kunt u de volgende sneltoetsen gebruiken:

  • -alt-omhoog/naar beneden om naar vorige / volgende wijzigingen te gaan.
  • -alt-Links/Rechts om verandering van links of rechts te accepteren

Als alternatief kunt u gebruiken opendiff (onderdeel van Xcode Tools) waarmee je twee bestanden of mappen samen kunt voegen om een ​​derde bestand of map te maken.


88
2017-08-05 14:29



Als je regelmatig kleine commits maakt, begin dan met het bekijken van de commit-opmerkingen met git log --merge. Dan git diff zal je de conflicten laten zien.

Voor conflicten met meer dan een paar regels is het eenvoudiger om te zien wat er in een externe GUI-tool gebeurt. Ik hou van opendiff - Git ondersteunt ook vimdiff, gvimdiff, kdiff3, tkdiff, meld, xxdiff, emerge out of the box en je kunt anderen installeren: git config merge.tool "your.tool" zal uw gekozen hulpmiddel instellen en dan git mergetool na een mislukte samenvoeging zie je de diff in context.

Telkens wanneer u een bestand bewerkt om een ​​conflict op te lossen, git add filename zal de index bijwerken en uw diff zal het niet meer tonen. Wanneer alle conflicten zijn afgehandeld en hun bestanden zijn geweest git add-ed, git commit voltooit je samenvoeging.


73
2017-10-02 16:11



Zien Hoe conflicten worden gepresenteerd of, in Git, de git merge documentatie om te begrijpen wat merge conflictmarkers zijn.

Ook de Conflicten oplossen In dit gedeelte wordt uitgelegd hoe u de conflicten oplost:

Nadat u een conflict hebt gezien, kunt u twee dingen doen:

  • Besluit om niet samen te voegen. De enige opschoonacties die u nodig hebt, zijn het indexbestand opnieuw instellen op de HEAD verplichten om 2. om te keren en werkwijzigingen op te schonen die gemaakt zijn door 2. en 3 .; git merge --abort kan hiervoor worden gebruikt.

  • Los de conflicten op. Git markeert de conflicten in de werkboom. Bewerk de bestanden in vorm en git add ze naar de index. Gebruik git commit om de deal af te sluiten.

Je kunt het conflict met een aantal hulpmiddelen doorlopen:

  • Gebruik een mergetool. git mergetool om een ​​grafische mergetool te starten die je door de samenvoeging heen zal werken.

  • Kijk naar de diff. git diff toont een drievoudig verschil, waarbij veranderingen van beide worden gemarkeerd HEAD en MERGE_HEAD versies.

  • Kijk naar de diff's van elke tak. git log --merge -p <path> zal diffs als eerste tonen voor de HEAD versie en dan de MERGE_HEAD versie.

  • Kijk naar de originelen. git show :1:filename toont de gemeenschappelijke voorouder, git show :2:filename toont de HEAD versie en git show :3:filename toont de MERGE_HEAD versie.

U kunt ook lezen over merge conflictmarkers en hoe u ze kunt oplossen in de Pro Git boek sectie Basisconflicten samenvoegen.


43
2017-07-14 18:34



Voor Emacs gebruikers die samenvoegconflicten semi-handmatig willen oplossen:

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

toont alle bestanden die een conflictoplossing vereisen.

Open elk van die bestanden één voor één of allemaal tegelijk door:

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

Wanneer u een buffer bezoekt die bewerkingen in Emacs vereist, typt u

ALT+x vc-resolve-conflicts

Hierdoor worden drie buffers (mine, theirs en de uitvoerbuffer) geopend. Navigeer door op 'n' (volgende regio), 'p' (previsieregio) te drukken. Druk op 'a' en 'b' om mijn of hun regio naar de uitvoerbuffer te kopiëren. En / of bewerk de uitvoerbuffer direct.

Wanneer u klaar bent: druk op 'q'. Emacs vraagt ​​je of je deze buffer wilt opslaan: ja. Na het afronden van een buffer markeert het als opgelost door uit de teriminal te lopen:

git add FILENAME

Wanneer u klaar bent met alle buffers type

git commit

om de samenvoeging te beëindigen.


36
2018-02-22 23:04



Volg de volgende stappen om samenvoegconflicten in Git op te lossen:

  1. Controleer de Git-status: git status

  2. Verkrijg de patchset: git fetch (check de juiste patch uit je Git commit)

  3. Afrekenen bij een lokaal filiaal (temp1 in mijn voorbeeld hier): git checkout -b temp1

  4. Trek de recente inhoud van de master: git pull --rebase originemeester

  5. Start de mergetool en controleer de conflicten en herstel ze ... en controleer de wijzigingen in de externe branch met uw huidige branch: Git mergetool

  6. Controleer de status opnieuw:   git status

  7. Verwijder de ongewenste bestanden die lokaal zijn gemaakt door mergetool, meestal maakt mergetool een extra bestand met extensie * .orig. Verwijder dat bestand, want dat is alleen het duplicaat en wijzig de wijzigingen lokaal en voeg de juiste versie van uw bestanden toe. git voeg #your_changed_correct_files toe

  8. Controleer de status opnieuw: git status

  9. Zet de wijzigingen in dezelfde commit-id (dit vermijdt een nieuwe aparte patch-set): git commit --amend

  10. Push naar de hoofdtak: git push (naar je Git repository)


28
2018-04-16 07:02



Gewoon, als je goed weet dat veranderingen in een van de repositories niet belangrijk is, en alle veranderingen ten gunste van de andere willen oplossen, gebruik dan:

git checkout . --ours

om veranderingen ten gunste van jouw repositoryof

git checkout . --theirs

om veranderingen op te lossen ten gunste van de andere of de hoofdrepository.

Of anders zult u een GUI-samenvoeghulpmiddel moeten gebruiken om één voor één door de bestanden te bladeren, bijvoorbeeld de samenvoegfunctie p4merge, of schrijf iemands naam die u al hebt geïnstalleerd

git mergetool -t p4merge

en nadat je een bestand hebt voltooid, moet je opslaan en sluiten, zodat de volgende wordt geopend.


27
2018-01-26 17:42