Saturday, July 6, 2013

Conflict Resolution with Vim Conflict Slides

The Conflict Slides Vim plugin allows you to lock to a conflict range and replace that whole range with individual sections inside the conflict markers. This has several advantages. For example, you are independent from how the other buffers are named and because modifications to the buffer are fully controlled, you gain some safety while exploring the conflict.

I recently added display helper functions that allow you to toggle the diff option in selected windows. That in turn makes it possible to see 2-way diffs at different points of the conflict resolution process. I am going to show you how such a procedure could look like.

There is more documentation on the Conflict Slides frontpage and the functions are documented in more detail in the plugin file.

The tutorial part focuses on Git somewhat, but as long as you have the same conflict markers, this should work with any VCS.

Setup

I would recommend to turn the folding off in the post-lock callback to mitigate jolting when changing content. You can turn the folding back on with the argument 'on' instead of 'off', and the folding can be toggled with the argument 'toggle'.

If your VCS offers to insert the base content into the markers, you should consider to turn that on. Otherwise the base slide is not available. In Git you can add the base content with the following command:

git config merge.conflictstyle diff3

Generally, I am using three diff windows with ours, dest, theirs content. That is the setup provided by vim-fugitive. You should really check out that plugin, if you haven't done so already. It is tremendously easy to find the commit for a line in a conflict (among many other things).

Example Mappings

Here are some mappings that extend the default mappings from Conflict Slides (CS) a bit. You can use this as a template for your own mappings. The ^[1-3] mappings do essentially turn the diff on in all 3 windows, except in the given window where the diff is toggled. This allows you to see a two-way diff for any combination of the three windows, as well as return to a three-way diff.

You can simply define a g:conflictslides_locked_mappings dictionary in your Vim configuration to override the one from CS. The top section in the following snippet is the same as in the plugin. Below that are a few mappings that allow you to insert a slide while turning diff on/off in selected windows. The first two of those mappings are useful immediately after you locked to a conflict to explore the changes in each parent.

There is nothing in there that cannot be done with the global mappings from above. So, it's just a template in case you want to create more convenient mappings with the mechanism provided by CS. You may need to adapt the window number in the calls if you use a different setup.

By pressing ^l you can lock to the one and only conflict in this file. This will produce a beautiful rainbow of colors.

The initial 3-way diff of the conflict

Now you can use the <space>b and <space><space>b mappings to see two-way diffs between the base slide and ours/theirs respectively. (The same can be accomplished with b and then ^1 or ^3)

Difference ours/base

Difference base/theirs

Aha! The conditional branch has been wrapped in a spinlock on our side and a very important call has been replaced by an even more important call on their side. If you are using Fugitive you can very conveniently open a blame view for their commit and try to find out more about that change.

Fugitive's blame view started from their modification

To resolve it you can take our side with <space>o, and append their side with T.

Spotting the surplus line in the difference dest/theirs

Because this is a two-way diff with theirs, the wrong call can be easily spotted. Let's unlock with e (for edit) and delete the wrong line. You can visualize the changes on each side by using the mappings ^1 and ^3.

Resolved difference ours/dest

Resolved difference dest/theirs

Resolve more

If you would like to resolve some more conflicts yourself, search the repository with the following command: