Integrating Kaleidoscope 2 with Git

What is Kaleidoscope?

I assume you already know what Git is, so let’s have a look at what Kaleidoscope is. Kaleidoscope is a file comparison app by Black Pixel for OS X. Just like any other file comparison tool worth its salt, it lets you view file differences and merge those differences in case of conflicts.

What sets Kaleidoscope apart from many other file comparison tools is that it can handle image files in addition to text files. It also integrates well with other apps, such as Versions or Tower. And if all else fails, there’s always Kaleidoscope’s command line tool ksdiff, which is precisely what we’re going to use.

At the time of this writing, Kaleidoscope 2 is in beta and offered by Black Pixel for half its regular price. We’ll be using the Kaleidoscope 2 beta version in this tutorial.

Integrating Kaleidoscope with Git – The Short Answer

If you know your way around git and merge tools, let me give you the quick and easy way to integrate Kaleidoscope with Git:

  1. Download, install and run Kaleidoscope
  2. Select “Kaleidoscope” -> “Integration…”
  3. Choose “Git, Command-line integration” and click both “Install” and “Configure”
  4. Done. Next time you enter git mergetool, Kaleidoscope will start.

A Word About Conflicts

When we’re talking about integrating Kaleidoscope with Git, we’re not only talking about using it as a diff tool to review file differences. The real fun begins when using Kaleidoscope as a merge tool to help us resolve merge conflicts.

Unfortunately, my experience with version control has been that often developers don’t know or don’t care about conflicts. Or they’re afraid of them. I used to work on a team with a guy who told me he never resolves conflicts. He just accepted one version as the correct  one and then fixed the bugs later when they appeared. Don’t do that!

Conflicts are a good thing and nothing to be afraid of. They show that people have been working. Conflicts happen if people have edited the same parts (lines) of files and are trying to merge these commits or branches. The version control software cannot handle that problem. Whose change is the right one? Only the team members can decide that, so the version control software says “I’ve got a conflict on line x. You guys fix that.” And merge tools like Kaleidoscope are there to help us with that.

Let’s Get Started

Obviously, we need both Git and Kaleidoscope, so please download and install both programs, if you haven’t already done so.

Now start Kaleidoscope and select “Integration…” from the Kaleidoscope menu, which brings up the Integration dialog:

Kaleidoscope's Integration Dialog

Kaleidoscope’s Integration Dialog

Click both the “Install” and “Configure” buttons as highlighted in the screen shot and you’re all set. Kaleidoscope if set up to work with seamlessly with Git!

But how to use it?

It All Starts With a Repository

In order to see what Kaleidoscope can do for us, we need a Git repository to produce some conflicts in. If you already got one lying around, you can use that, or follow along as we quickly set up a testing repository.

Let’s start the terminal application (/Applications/Utilities/Terminal or search for Terminal in Spotlight). Terminal starts in your home directory, which is fine for our exercise. Initialise a Git repository in a new directory called “repo”, like so:

mkdir repo && cd repo && git init

We now are in the repo directory which contains an empty Git repository. Within the repo directory, create a new file called hello.cpp with this content:

#include <iostream>

using namespace std;

int main(int argc, char ** argv) {

 cout << "Hello, World!" << endl;

 return 0;
}

Once that’s done, stage and commit the hello.cpp file:

git add hello.cpp && git commit -m "Adding hello.cpp"

We now have a fully working repository with one source code file. If you enter git branch in the terminal, Git tells you that you have one branch called master. Let’s create a development branch:

git checkout -b develop master && git checkout master

We’ve created a new branch from our master branch and immediately returned to the master branch. Let’s make a change to hello.cpp on the master branch by changing the console output from “Hello, World!” to “Hello, Git!”:

cout << "Hello, Git!" << endl;

Stage and commit the changes:

git add hello.cpp && git commit -m "Amending message on master branch"

We now have committed changes in hello.cpp on the master branch that the development branch knows nothing about. It is a good practice to frequently merge the stable branch in the development branch. But we’re not going to do that now, because we do want a conflict. Check out the development branch:

git checkout develop

Once on the development branch, open up your editor and you’ll see that the message is still “Hello, World!”. Change it to “Hello, Kaleidoscope!”, save the file, stage and commit it, then return to the master branch:

git add hello.cpp && git commit -m "Amending message on develop branch" && git checkout master

We have not only created two versions of hello.cpp in their respective branches, but we’ve also edited the same line of code with different results. When trying to merge the branches, Git will abort the merge because of an unresolved conflict. Let’s try it:

git merge --no-ff develop

If all steps have been followed correctly, Git will now complain about the conflict:

Auto-merging hello.cpp
CONFLICT (content): Merge conflict in hello.cpp
Automatic merge failed; fix conflicts and then commit the result.

We could open the hello.cpp file in a text editor or IDE and fix the conflict by searching the markers. In a file and program as tiny as this example, that would be fairly easy. However, once your codebase is a bit larger and you’ve got conflicts in several files much longer than hello.cpp, the manual process is tiresome and error-prone. That’s the point where merge tools join the game. They parse source code files and visualise the conflicts for us to resolve it. The git command to open the merge tool in case of a conflict is:

git mergetool

Since we’ve configured Kaleidoscope to be the default merge tool used by Git, the program will launch instantly and load both amended versions of hello.cpp, along with a third source code view:

Kaleidoscope's Merge View of hello.cpp

Kaleidoscope’s Merge View of hello.cpp

The source file in the left hand side swimlane is labelled LOCAL. We’re currently on the master branch, therefore local refers to the version of hello.cpp in the master branch. The right hand side source file is labelled REMOTE, which refers to the branch being merged into the local branch, in our case the develop branch.

The source file displayed in the middle lane is the merge result. Depending on what choices we make, the merge result will be different and the middle lane gives us a preview of the final result.

We only have one conflict. If we had further conflicts, we could select them using the controls on the bottom right hand side corner. There’s no need for that in our example, so let’s proceed and decide how to get out of the mess we’ve gotten ourselves into.

Kaleidoscope's Merge Menu

Kaleidoscope’s Merge Menu

We could choose either the code from LOCAL or the one from REMOTE, and in many cases this is the best thing to do. Kaleidoscope gives us a couple of options. Via the “Merge” menu, we can select to choose one version or both versions in a given order.

Alternatively, we could quickly choose one version or the other by using the buttons below the merge result lane, or one of the keyboard shortcuts from the merge menu.

But there’s yet another option we have. For sake of argument, let’s assume that the sales department on having the message “Hello, Git!”, while the marketing department prefers to greet Kaleidoscope. Both departments agree on the compromise to amend the message to read “Hello, Git and Kaleidosope!”

Directly Editing the Merge Result

Directly Editing the Merge Result

We can’t do that by choosing one side or the other and saving the merge. Fortunately, Kaleidoscope allows us to directly edit the merge result in case none of the two options is entirely correct. Simply put your cursor on line 7 in the middle lane and type away. Once you’re done editing, save the file and quit Kaleidoscope.

Back in the terminal, call git status and you’ll notice there’s a modified version of hello.cpp already staged, as well as an untracked file hello.cpp.orig which holds the pre-merge state of hello.cpp on the master branch. Let’s remove the orig file and commit our merge:

rm -fv hello.cpp.orig && git commit

See how we’re not providing a commit message? We don’t need that, because Git creates  its own commit message in case of a merge. We’re grateful and save the default commit message. The merge is complete and if we open hello.cpp, we see that it contains the new and improved message.

That’s it, we’re done! We now could (and should) merge the master branch back into the develop branch and we’ll find there are absolutely no problems in doing it:

git checkout develop && git merge --no-ff master

Conclusion

Integrating Kaleidoscope 2 with Git is a breeze and can be achieved in no time. Using a proper merge tool to aid in dealing with conflicts is crucial if you’re working on any but the most trivial software projects.

Kaleidoscope 2 isn’t free, but it’s money well spent. If you cannot afford the program, I would advise to give KDiff3 a try. It’s not the prettiest merge tool of them all, but it works flawlessly and has been tested in battle for many years now.

4 thoughts on “Integrating Kaleidoscope 2 with Git

  1. Mike

    Jurg,

    I noticed when doing diffs, if a new file is created (and untracked in git), it does not come up in Kaleidoscope. Now this is obvious because there is nothing to diff against, however I guess I would like to see it diff against a blank page, just to give a chance for one more review. Is this possible?

    Reply
    1. Mike

      Nevermind – if you do a `git add .`, followed by a `git difftool –cached` that will show everything. Cheers!

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.