I like git, but sometimes I get lost when a merge conflict happens. I usually flail my way through. Here are some of my moves.
I give you a conflict. I’ll commit a file into master, create a topic branch and change it, and then change it again back in master.
$ git init
$ vi foo.rb # puts "Hello world."
$ git add .
$ git commit
$ git co -b topic
$ vi foo.rb # puts "Goodbye world."
$ git commit -a
$ git co master
$ vi foo.rb # puts "Wake up world."
$ git commit -a
When I merge topic into master, I get the conflict:
$ git merge topic
Auto-merged foo.rb
CONFLICT (content): Merge conflict in foo.rb
Automatic merge failed; fix conflicts and then commit the result.
The working file doesn’t look too bad.
<<<<<<< HEAD:foo.rb
puts "Wake up world."
=======
puts "Goodbye world."
>>>>>>> topic:foo.rb
Unfortunately, my code is usually freakish spaghetti, so the working file looks more like an ASCII port of Centipede. I liked how Subversion dumped copies of the conflicting files so I could see each side of the conflict. Git doesn’t give you these, but you can get them. Here’s the hard way, but it illustrates somes some lower-level interrogation commands and the nutty fundamentals of Git:
$ git ls-tree master foo.rb
100644 blob ff128a16618164a0edaa7d3259bb02cbd7917a32 foo.rb
$ git cat-file blob ff128a16618164a0edaa7d3259bb02cbd7917a32
puts "Wake up world."
git ls-tree topic foo.rb
100644 blob 6e96df5f6d698f9e1d62d588c1ce84a299bbdba9 foo.rb
$ git cat-file blob 6e96df5f6d698f9e1d62d588c1ce84a299bbdba9
puts "Goodbye world."
Here’s an easier way to get at the object names involved in the conflict:
$ git ls-files -u
100644 e76947b1956d226e09c800639e526b7a986fa64c 1 foo.rb
100644 ff128a16618164a0edaa7d3259bb02cbd7917a32 2 foo.rb
100644 6e96df5f6d698f9e1d62d588c1ce84a299bbdba9 3 foo.rb
Clearly, 1 is the common ancestor, 2 is master and 3 is topic. Ok, maybe not so clear. Anyway, let’s take the topic:
git cat-file blob 6e96df5f6d698f9e1d62d588c1ce84a299bbdba9 > foo.rb
git-diff doesn’t show what I’d expect:
$ git diff
diff --cc foo.rb
index ff128a1,6e96df5..0000000
--- a/foo.rb
+++ b/foo.rb
But if I add it, it makes more sense:
$ git add .
$ git diff --cached
diff --git a/foo.rb b/foo.rb
index ff128a1..6e96df5 100644
--- a/foo.rb
+++ b/foo.rb
@@ -1 +1 @@
-puts "Wake up world."
+puts "Goodbye world."
I’ll just commit it and move on with life:
$ git commit
Ok, I guess merging in Git is not that bad. I’m sure you’ve got a slick way of merging with Git. Please share!
Update
I submitted some small patches to the git-merge documentation. I think it is helpful, but now that I’ve learned more about Git, I think there is so much more that could be said!