Merging in Git is Kinda Rough
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!
August 9th, 2008

