Gitの競合を理解して解決する方法

そこには、すべての開発者が見たくない言葉があります。それは競合です。😱Git(または他のバージョン管理システム)で作業しているときに、時折発生するマージの競合を回避する方法はありません。

しかし、開発者と話すとき、マージの競合のトピックに関して不安不快感があるとよく耳にします。

紛争への対処は、しばしば暗くて神秘的な場所のままです。物事がひどく壊れていて、(事態を悪化させることなく)それから抜け出す方法が不明確な状況です。

マージの競合が開発者の生活の避けられない部分であることは事実ですが、これらの状況での不快感は完全に任意です。

この記事での私の意図は、このトピックにいくらかの明確さをもたらすことです:競合が通常発生する方法と時期、それらが実際に何であるか、そしてそれらを解決する方法(または元に戻す方法)。

これらのことを正しく理解すると、マージの競合にはるかにリラックスして自信を持って対処できるようになります。😍

競合が発生する方法と時期

その名前はすでにそれを示しています:「マージの競合」は、異なるソースからのコミットを統合するプロセスで発生する可能性があります。

ただし、「統合」は「ブランチのマージ」だけに限定されないことに注意してください。また、リベースまたはインタラクティブリベースの場合、チェリーピックまたはプルの実行時、またはStashの再適用時にも発生する可能性があります。

これらのアクションはすべて、ある種の統合を実行します。そのときに、マージの競合が発生する可能性があります。

しかしもちろん、これらのアクションが毎回マージの競合を引き起こすわけではありません(神に感謝します!)。理想的には、これらの状況に陥ることはめったにありません。しかし、いつ競合が発生するのでしょうか。

実際、Gitのマージ機能はその最大の利点の1つです。Gitは通常、それ自体で物事を把握できるため、ブランチのマージはほとんどの場合簡単に機能します。

しかし、矛盾した変更加えられた状況や、テクノロジー何が正しいか間違っているかを判断できない状況があります。これらの状況は、単に人間からの決定を必要とします。

真の古典は、2つの異なるブランチで、2つのコミットでまったく同じコード行が変更されたときです。Gitには、どの変更を好むかを知る方法がありません。🤔

他にも同様の状況がいくつかあります。たとえば、あるブランチでファイルが変更され、別のブランチで削除された場合などですが、あまり一般的ではありません。

「タワー」GitのデスクトップGUIは、例えば、状況、これらの種類を可視化する良い方法があります。

競合がいつ発生したかを知る方法

心配しないでください。Gitは、競合が発生したときに非常に明確に通知します。😉  

まず、競合が原因でマージまたはリベースが失敗した場合など、状況すぐに通知されます。

$ 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は問題を非常に明確かつ迅速に伝えます。

  • ファイル「index.html」で競合が発生しました。
  • ファイル「error.html」で別の競合が発生しました。
  • そして最後に、競合のため、マージ操作は失敗しました。

これらは、コードを掘り下げて、何をしなければならないかを確認する必要がある状況です。

万が一、競合が発生したときにこれらの警告メッセージを見落とした場合、Gitは実行するたびにさらに通知します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

言い換えれば、マージの競合に気付かないことを心配しないでください。Gitは、それらを見落とさないようにします。

Gitの競合を元に戻して最初からやり直す方法

マージの競合には、一定の緊急性が伴います。そして当然のことながら、仕事を続ける前にそれらに対処する必要があります。

しかし、それらを無視することは選択肢ではありませんが、「マージの競合に対処する」ことは、必ずしもそれらを解決する必要があることを意味するわけではありません。それらを元に戻すことも可能です!

これは繰り返す価値があるかもしれません。マージの競合を元に戻し、以前の状態に戻るオプションが常にあります。これは、競合するファイルの解決をすでに開始していて、行き止まりになっている場合でも当てはまります。

このような状況では、競合が発生する前に、いつでも最初からやり直してクリーンな状態に戻ることができることを覚えておくとよいでしょう。

For this purpose, most commands come with an --abort option, for example git merge --abort and git rebase --abort:

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

This should give you the confidence that you really cannot mess up. You can always abort, return to a clean state, and start over.

What Conflicts Really Look Like in Git

Now, safe in the knowledge that nothing can break, let's see what a conflict really looks like under the hood. This will demystify those little buggers and, at the same time, help you lose respect for them and gain confidence in yourself.

As an example, let's look at the contents of the (currently conflicted) "index.html" file in an editor:

Git was kind enough to mark the problem area in the file, enclosing it in <<<<<<< HEAD and >>>>>>> [other/branch/name]. The content that comes after the first marker originates from our current working branch. Finally, a line with ======= characters separates the two conflicting changes.

How to Solve a Conflict in Git

Our job as developers now is to clean up these lines: after we're finished, the file has to look exactly as we want it to look.

It might be necessary to talk to the teammate who wrote the "other" changes and decide which code is actually correct. Maybe it's ours, maybe it's theirs - or maybe a mixture between the two.

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

Tobias Günther is the CEO of Tower, the popular Git desktop client that helps more than 100,000 developers around the world to be more productive with Git.