Differences between revisions 3 and 12 (spanning 9 versions)
Revision 3 as of 2010-05-12 18:52:12
Size: 2331
Editor: JudeNagurney
Comment: fixing typos
Revision 12 as of 2016-07-24 18:47:02
Size: 7370
Comment: fix internal wiki link
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
== Using Vim as a merge program for Mercurial ==
Vim's [[http://www.vim.org/htmldoc/diff.html|diff mode]] (aka "vimdiff") allows vim to be used to do hg merges.
<<TableOfContents(2)>>
Line 4: Line 3:
Here's my favorite way to use vim to do mercurial merges. = Using Vim as a Merge Program for Mercurial =
Line 6: Line 5:
Configuration: In your ''~/.hgrc'' file, add the following: == VIM internal vimdiff mode ==

Vim's [[http://www.vim.org/htmldoc/diff.html|diff mode]] (aka `vimdiff`) allows Vim to be used to do a `hg merge`.

Here's one way to use Vim to do Mercurial merges.

To configure, add the following to your `~/.hgrc` file:
Line 16: Line 21:
The 'args' command opens all 4 version of 'file': 'file~base' = common ancestor, 'file.orig' = local tree's version, 'file' = merge result (i.e. resolve your conflicts into this file: it's the one that hg considers the 'fixed' version when you're done), and 'file~other' = version from the other tree, that you're merging from. Since you are typically most interested in the 'file' and 'file~other' buffers (and since vim's keyboard shortcuts for :diffget ("do") and :diffput ("dp") only work when two buffers are open), we close the windows for the other two buffers. They're still around, though: if the merge is complex and you want to see them, use :bnext/:bprev.
Line 18: Line 22:
If you are unfamiliar with vim's diff mode, you may find ":help diff" useful to read (see in particular the ":diffget" and ":diffput" commands). Also, diff mode by default uses folds, so "help folding" may be useful. When presenting a merge, Vim will show two windows side by side (unless the configuration has been changed to show them stacked vertically). You may even get Vim's exuberant colour choices:
Line 20: Line 24:
'''If things go terribly wrong:''' quit vim via ":cq". It won't save, and will return an error code, so mercurial will not consider the file merged yet, and you can try again via "hg resolve filename" (hg resolve -l to see list of files, in case you get '''really''' confused). If you decide you hate using vimdiff, for instance, you can ":cq", set 'ui.merge = internal:merge" in your .hgrc, and run resolve, and you'll be back to merging via "<<<<<<<" and ">>>>>>>" marks in the file. So you can try vimdiff out as a merge tool without getting into a world of pain if you don't like/understand it. || '''The merge result''' || '''The "other" version''' ||
|| ''This window will be the one you work in to get the desired merge'' || ''This window provides desirable content from the other version'' ||
||<style="background-color: #0dd; color: #00d; font-family: monospace"> ||<style="background-color: #d00; color: #fff; font-family: monospace">content provided by this version || ''additions to consider'' ||
||<style="background-color: #d00; color: #fff; font-family: monospace">content provided by this version ||<style="background-color: #0dd; color: #00d; font-family: monospace"> || ''deletions to consider'' ||
||<style="background-color: #d0d; color: #fff; font-family: monospace">changed content ||<style="background-color: #d0d; color: #fff; font-family: monospace"> modified content || ''character-level changes to consider'' ||
Line 22: Line 30:
There has been some confusion on da internets about using Vim's [[http://www.vim.org/scripts/script.php?script_id=102|DifDiff]] extension to do hg merges. DirDiff can be used for [[http://mercurial.selenic.com/wiki/ExtdiffExtension|fancy "hg diff" browsing]] (a great way to look at patches), but will not work with "hg merge". In preparing the merge result, the objective is to copy differing regions from the other version. This can be done by navigating to a region in a window and then...
Line 24: Line 32:
''See 'man hgrc' for a full explanation of configuring hgrc files'' ||<-3> || '''In the merge result window''' || '''In the other version window''' ||
||<|2 style="background-color: #d00"> ||<|2 style="background-color: #d0d"> ||<|2> || Use the `do` (`:diffget`) command to get the region from the other version. ||<|2> ||
|| This is useful when either accepting character-level changes or deletions from the other version... ||
||<|2 style="background-color: #d00"> ||<|2 style="background-color: #d0d"> ||<|2 style="background-color: #0dd"> ||<|2> || Use the `dp` (`:diffput`) command to put the region into the merge result. ||
|| This is useful when either accepting character-level changes or additions from the other version. ||
||<|3 style="background-color: #d00"> ||<|3 style="background-color: #d0d"> ||<|3> || When you want to keep one or more lines of a diff... ||<|3> ||
|| Either use `:M,Ndiffput` (where `M` and `N` are start and end line numbers) to put the good lines in the other version. Then use `do` (`:diffget`) to get the resulting "good" diff. ||
|| Or first copy the good lines, use `do` (`:diffget`) to get the other version's region, then reintroduce the good lines. ||

To navigate:

 * To move between windows use `Ctrl-W` and a cursor key.
 * Where text has been folded, possibly after regions have been copied, use `zo` to open the fold (and show the hidden text) and `zc` to close the fold (and hide the text again).

Once the merge operations have been performed, the buffers can be written out.

=== 3 way diffs ===
If you'd like your diff window to look like a kdiff3 merge window (showing base, local, other, and merged... with one of them stretching across the bottom), use the following line
{{{
vimdiff.args = -d $base $local $output $other -c "wincmd J"
}}}
The first version listed (in this case $base) will be placed at the bottom of the screen. All four vim windows will be linked.

=== The technical details ===

The `args` command opens all 4 versions of `file`, defined as follows:

 * `file~base` - the common ancestor
 * `file.orig` - the local tree's version
 * `file` - the merge result (you resolve your conflicts into this file: it's the one that `hg` considers the 'fixed' version when you're done)
 * `file~other` - the version from the other tree that you're merging from

Since you are typically most interested in the `file` and `file~other` buffers (and since Vim's keyboard shortcuts for `:diffget` (`do`) and `:diffput` (`dp`) only work when two buffers are open), we close the windows for the other two buffers (but see below). They're still around, though: if the merge is complex and you want to see them, use `:bnext` and `:bprev`.

If you are unfamiliar with Vim's diff mode, you may find `:help diff` useful to read (see in particular the `:diffget` and `:diffput` commands). Also, diff mode by default uses folds, so `:help folding` may be useful.

=== More Useful 3-Way Diff ===

The following config makes vimdiff works nicely (and maybe git-like) out of the box:

{{{
[merge-tools]
vimdiff.executable = vimdiff
vimdiff.args = -f -d $output -M $local $base $other -c "wincmd J" -c "set modifiable" -c "set write"
vimdiff.premerge = keep
}}}

The right settings are:

 1. `-M` -- makes all opened files unmodifiable

 2. `-c "set modifiable" -c "set write"` enables modifications of only single file which is a result of merge, in combination with #1 it makes `:diffput` work

 3. `vimdiff.premerge = keep` -- does initial merge and leaves `<<<<` and `>>>>` markers in conflict areas

=== If things go terribly wrong ===

Quit Vim via `:cq`. It won't save, and it will return an error code, so Mercurial will not consider the file merged yet, and you can try again via `hg resolve filename` (`hg resolve -l` to see list of files, in case you get '''really''' confused).

If you decide you hate using `vimdiff`, for instance, you can issue a `:cq`, set...

{{{
ui.merge = internal:merge
}}}

...in your `.hgrc`, and run `hg resolve`, and you'll be back to merging via `<<<<<<<` and `>>>>>>>` marks in the file. So you can try `vimdiff` out as a merge tool without getting into a world of pain if you don't like/understand it.


== Splice extension ==
VIM's vimdiff mode is not primarily meant to be used as a merge program and thus has some drawbacks. Even during simple merge it's not easy to tell which window is which (where is the result of the merge, what is common ancestor, etc.). Once the merge is more complicated, viewing four files at once in diff mode is very confusing too. Fortunately Steve Losh has written VIM plugin called '''splice''' http://www.vim.org/scripts/script.php?script_id=4026. It helps you to cope with complex merge easier by allowing you to intuitively switch between various views of the merge in progress and by providing navigation toolbar you are always sure to know what file you are looking at. The homepage contains introductory video (just be warned, '''splice''' was named "threesome" in the past and the video does not reflect the name change). '''Splice''' can be used for merging conflicts in many other version control systems too.

== DirDiff and merging ==

There has been some confusion about using Vim's [[http://www.vim.org/scripts/script.php?script_id=102|DirDiff]] extension to do a `hg merge`. !DirDiff can be used for [[ExtdiffExtension|fancy "hg diff" browsing]] (a great way to look at patches), but will not work with `hg merge`.

(!) See `man hgrc` for a full explanation of configuring `hgrc` files.

Using Vim as a Merge Program for Mercurial

VIM internal vimdiff mode

Vim's diff mode (aka vimdiff) allows Vim to be used to do a hg merge.

Here's one way to use Vim to do Mercurial merges.

To configure, add the following to your ~/.hgrc file:

[ui]
merge = vimdiff

[merge-tools]
vimdiff.executable = vim
vimdiff.args = -d $base $local $output $other +close +close

When presenting a merge, Vim will show two windows side by side (unless the configuration has been changed to show them stacked vertically). You may even get Vim's exuberant colour choices:

The merge result

The "other" version

This window will be the one you work in to get the desired merge

This window provides desirable content from the other version

content provided by this version

additions to consider

content provided by this version

deletions to consider

changed content

modified content

character-level changes to consider

In preparing the merge result, the objective is to copy differing regions from the other version. This can be done by navigating to a region in a window and then...

In the merge result window

In the other version window

Use the do (:diffget) command to get the region from the other version.

This is useful when either accepting character-level changes or deletions from the other version...

Use the dp (:diffput) command to put the region into the merge result.

This is useful when either accepting character-level changes or additions from the other version.

When you want to keep one or more lines of a diff...

Either use :M,Ndiffput (where M and N are start and end line numbers) to put the good lines in the other version. Then use do (:diffget) to get the resulting "good" diff.

Or first copy the good lines, use do (:diffget) to get the other version's region, then reintroduce the good lines.

To navigate:

  • To move between windows use Ctrl-W and a cursor key.

  • Where text has been folded, possibly after regions have been copied, use zo to open the fold (and show the hidden text) and zc to close the fold (and hide the text again).

Once the merge operations have been performed, the buffers can be written out.

3 way diffs

If you'd like your diff window to look like a kdiff3 merge window (showing base, local, other, and merged... with one of them stretching across the bottom), use the following line

vimdiff.args = -d $base $local $output $other -c "wincmd J"

The first version listed (in this case $base) will be placed at the bottom of the screen. All four vim windows will be linked.

The technical details

The args command opens all 4 versions of file, defined as follows:

  • file~base - the common ancestor

  • file.orig - the local tree's version

  • file - the merge result (you resolve your conflicts into this file: it's the one that hg considers the 'fixed' version when you're done)

  • file~other - the version from the other tree that you're merging from

Since you are typically most interested in the file and file~other buffers (and since Vim's keyboard shortcuts for :diffget (do) and :diffput (dp) only work when two buffers are open), we close the windows for the other two buffers (but see below). They're still around, though: if the merge is complex and you want to see them, use :bnext and :bprev.

If you are unfamiliar with Vim's diff mode, you may find :help diff useful to read (see in particular the :diffget and :diffput commands). Also, diff mode by default uses folds, so :help folding may be useful.

More Useful 3-Way Diff

The following config makes vimdiff works nicely (and maybe git-like) out of the box:

[merge-tools]
vimdiff.executable = vimdiff
vimdiff.args = -f -d $output -M $local $base $other -c "wincmd J" -c "set modifiable" -c "set write"
vimdiff.premerge = keep

The right settings are:

  1. -M -- makes all opened files unmodifiable

  2. -c "set modifiable" -c "set write" enables modifications of only single file which is a result of merge, in combination with #1 it makes :diffput work

  3. vimdiff.premerge = keep -- does initial merge and leaves <<<< and >>>> markers in conflict areas

If things go terribly wrong

Quit Vim via :cq. It won't save, and it will return an error code, so Mercurial will not consider the file merged yet, and you can try again via hg resolve filename (hg resolve -l to see list of files, in case you get really confused).

If you decide you hate using vimdiff, for instance, you can issue a :cq, set...

ui.merge = internal:merge

...in your .hgrc, and run hg resolve, and you'll be back to merging via <<<<<<< and >>>>>>> marks in the file. So you can try vimdiff out as a merge tool without getting into a world of pain if you don't like/understand it.

Splice extension

VIM's vimdiff mode is not primarily meant to be used as a merge program and thus has some drawbacks. Even during simple merge it's not easy to tell which window is which (where is the result of the merge, what is common ancestor, etc.). Once the merge is more complicated, viewing four files at once in diff mode is very confusing too. Fortunately Steve Losh has written VIM plugin called splice http://www.vim.org/scripts/script.php?script_id=4026. It helps you to cope with complex merge easier by allowing you to intuitively switch between various views of the merge in progress and by providing navigation toolbar you are always sure to know what file you are looking at. The homepage contains introductory video (just be warned, splice was named "threesome" in the past and the video does not reflect the name change). Splice can be used for merging conflicts in many other version control systems too.

DirDiff and merging

There has been some confusion about using Vim's DirDiff extension to do a hg merge. DirDiff can be used for fancy "hg diff" browsing (a great way to look at patches), but will not work with hg merge.

(!) See man hgrc for a full explanation of configuring hgrc files.

MergingWithVim (last edited 2016-07-24 18:47:02 by ThomasDeSchampheleire)