Како разумети и решити сукобе у Гит-у

Ето, реч коју сваки програмер мрзи да види: сукоб. Јуст Једноставно се не може заобићи повремени сукоб спајања током рада са Гит-ом (или другим системима за контролу верзија).

Али кад разговарам са програмерима, често чујем да око теме сукоба спајања постоји осећај анксиозности или непријатности .

Руковање сукобима често остаје мрачно, мистериозно место: ситуација у којој су ствари тешко сломљене и нејасно је како се из тога изаћи (а да се ствари не погоршају).

Иако је истина да су сукоби при спајању неизбежни део живота програмера, нелагодност у овим ситуацијама је потпуно необавезна.

Намера ми је да овим чланком укажем на јаснију тему: како и када се сукоби обично јављају, шта су заправо и како их решити - или поништити.

Када правилно разумете ове ствари, моћи ћете да се носите са сукобима стапања на много опуштенији и сигурнији начин. ?

Како и када се јављају сукоби

Име већ говори: „сукоби спајања“ могу се десити у процесу интегрисања урезивања из другог извора.

Имајте на уму, међутим, да „интеграција“ није ограничена само на „спајање грана“. То се такође може догодити приликом поновног подношења базе или интерактивног поновног подношења, приликом извођења трке или повлачења или чак приликом поновног наношења Стасх-а.

Све ове акције извршавају неку врсту интеграције - и тада се могу догодити сукоби при спајању.

Али наравно, ове акције не резултирају сукобом спајања сваки пут (хвала Богу!). Идеално би било да се у овим ситуацијама нађете врло ретко. Али када се тачно јављају сукоби?

Заправо, Гит-ове могућности спајања су једна од његових највећих предности: спајање грана већину времена ради без напора, јер Гит обично може сам да схвати ствари.

Али постоје ситуације у којима су направљене контрадикторне промене - и где технологија једноставно не може да одлучи шта је исправно или не. Ове ситуације једноставно захтевају одлуку од човека.

Прави класик је када је потпуно исти ред кода промењен у два урезивања, у две различите гране. Гит никако не може знати коју промену више волите! ?

Постоје и неке друге, сличне ситуације - на пример када је датотека измењена у једној грани и избрисана у другој - али су нешто ређе.

На пример, ГУИ за радну површину Гит „Товер“ има леп начин да визуализује ове врсте ситуација:

Како знати када је дошло до сукоба

Не брините: Гит ће вам врло јасно рећи када се сукоб десио. ?  

Прво ће вас одмах обавестити у ситуацији , на пример када спајање или пребаза података не успе због сукоба:

$ git merge develop Auto-merging index.html CONFLICT (content): Merge conflict in index.html CONFLICT (modify/delete): error.html deleted in HEAD and modified in develop. Version develop of error.html left in tree. Automatic merge failed; fix conflicts and then commit the result.

Као што можете видети из горњег примера, када сам покушао да извршим спајање, створио сам сукоб спајања - и Гит врло јасно и брзо саопштава проблем:

  • Дошло је до сукоба у датотеци „индек.хтмл“.
  • Дошло је до још једног сукоба у датотеци „еррор.хтмл“.
  • И коначно, због сукоба, операција спајања није успела.

То су ситуације у којима морамо да закопамо у код и видимо шта треба учинити.

У мало вероватном случају да сте превидели ове поруке упозорења када се сукоб догодио, Гит вас додатно обавештава кад год трчите git status:

$ git status On branch main You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add/rm ..." as appropriate to mark resolution) deleted by us: error.html both modified: index.html

Другим речима: не брините ако не приметите сукобе спајања. Гит се брине да их не можете превидети.

Како поништити сукоб у Гит-у и започети испочетка

Сукоби око спајања долазе са одређеном атмосфером хитности. И с правом: мораћете да се позабавите њима пре него што наставите са послом.

Али иако њихово игнорисање није опција, „бављење конфликтима спајања“ не значи нужно да их морате решити. Њихово поништавање је такође могуће!

Ово би можда било вредно поновити: увек увек имате могућност да поништите сукоб спајања и вратите се у стање раније. Ово је тачно чак и када сте већ започели решавање сукобљених датотека и нашли се у ћорсокаку.

У овим ситуацијама је сјајно имати на уму да увек можете почети испочетка и вратити се у чисто стање пре него што се сукоб уопште догодио.

У ту сврху, већина наредби долази са --abortопцијом, на пример git merge --abortи git rebase --abort:

$ git merge --abort $ git status On branch main nothing to commit, working tree clean

Ово би вам требало дати самопоуздање да заиста не можете да забрљате. Увек можете прекинути, вратити се у чисто стање и почети испочетка.

Како у Гит-у заиста изгледају сукоби

Сада, сигурни у сазнање да се ништа не може сломити, погледајмо како заиста изгледа сукоб испод хаубе. Ово ће демистификовати те мале барабе, а истовремено ће вам помоћи да изгубите поштовање према њима и стекнете поверење у себе.

Као пример, погледајмо садржај (тренутно сукобљене) датотеке „индек.хтмл“ у уређивачу:

Гит је био љубазан да означи проблематично подручје у датотеци, затварајући је у <<<<<<< HEADи >>>>>>> [other/branch/name]. Садржај који долази након првог маркера потиче из наше тренутне радне гране. Коначно, ред са =======знаковима раздваја две сукобљене промене.

Како решити конфликт у Гит-у

Наш посао програмера је сада да очистимо ове редове: након што завршимо, датотека мора изгледати тачно онако како ми желимо.

Можда ће бити потребно разговарати са саиграчем који је написао „остале“ промене и одлучити који је код у ствари тачан. Можда је наше, можда је њихово - или можда мешавина између њих двоје.

This process - cleaning up the file and making sure it contains what we actually want - doesn't have to involve any magic. You can do this simply by opening your text editor or IDE and starting to making your changes.

Often, however, you'll find that this is not the most efficient way. That's when dedicated tools can save time and effort:

  • Git GUI Tools: Some of the graphical user interfaces for Git can be helpful when solving conflicts. The Tower Git GUI, for example, offers a dedicated "Conflict Wizard" that helps visualize and solve the situation:
  • Dedicated Merge Tools: For more complicated conflicts, it can be great to have a dedicated "Diff & Merge Tool" at hand. You can configure your tool of choice using the "git config" command. (Consult your tool's documentation for detailed instructions.) Then, in case of a conflict, you can invoke it by simply typing git mergetool. As an example, here's a screenshot of "Kaleidoscope" on macOS:

After cleaning up the file - either manually or in a Git GUI or Merge Tool - we have to commit this like any other change:

  • By using git add on the (previously) conflicted file, we inform Git that the conflict has been solved.
  • When all conflicts have been solved and added to the Staging Area, you need to complete the resolution by creating a regular commit.

How to Become More Confident and Productive

Many years ago, when I started using version control, merge conflicts regularly freaked me out: I was afraid that, finally, I had managed to break things for good. ?

Only when I took the time to truly understand what was going on under the hood was I able to deal with conflicts confidently and efficiently.

The same was true, for example, when dealing with mistakes: only once I learned how to undo mistakes with Git was I able to become more confident and productive in my work.

I highly recommend taking a look at the free "First Aid Kit for Git", a collection of short videos about how to undo and recover from mistakes with Git.

Have fun becoming a better programmer!

About the Author

Тобиас Гунтхер је извршни директор компаније Товер, популарног Гит клијента за рачунаре који помаже више од 100.000 програмера широм света да буду продуктивнији са Гитом.