| *diff.txt* For Vim version 9.1. Last change: 2025 Jun 20 |
| |
| |
| VIM REFERENCE MANUAL by Bram Moolenaar |
| |
| |
| *diff* *vimdiff* *gvimdiff* *diff-mode* |
| This file describes the |+diff| feature: Showing differences between two to |
| eight versions of the same file. |
| |
| The basics are explained in section |08.7| of the user manual. |
| |
| 1. Starting diff mode |start-vimdiff| |
| 2. Viewing diffs |view-diffs| |
| 3. Jumping to diffs |jumpto-diffs| |
| 4. Copying diffs |copy-diffs| |
| 5. Diff options |diff-options| |
| |
| ============================================================================== |
| 1. Starting diff mode *start-vimdiff* |
| |
| The easiest way to start editing in diff mode is with the "vimdiff" command. |
| This starts Vim as usual, and additionally sets up for viewing the differences |
| between the arguments. > |
| |
| vimdiff file1 file2 [file3 [file4]] |
| |
| This is equivalent to: > |
| |
| vim -d file1 file2 [file3 [file4]] |
| |
| You may also use "gvimdiff" or "vim -d -g". The GUI is started then. |
| You may also use "viewdiff" or "gviewdiff". Vim starts in readonly mode then. |
| "r" may be prepended for restricted mode (see |-Z|). |
| |
| The second and following arguments may also be a directory name. Vim will |
| then append the file name of the first argument to the directory name to find |
| the file. |
| |
| By default an internal diff library will be used. When 'diffopt' or |
| 'diffexpr' has been set an external "diff" command will be used. This only |
| works when such a diff program is available. |
| |
| Diffs are local to the current tab page |tab-page|. You can't see diffs with |
| a window in another tab page. This does make it possible to have several |
| diffs at the same time, each in their own tab page. |
| |
| What happens is that Vim opens a window for each of the files. This is like |
| using the |-O| argument. This uses vertical splits. If you prefer horizontal |
| splits add the |-o| argument: > |
| |
| vimdiff -o file1 file2 [file3 [file4]] |
| |
| If you always prefer horizontal splits include "horizontal" in 'diffopt'. |
| |
| In each of the edited files these options are set: |
| |
| 'diff' on |
| 'scrollbind' on |
| 'cursorbind' on |
| 'scrollopt' includes "hor" |
| 'wrap' off, or leave as-is if 'diffopt' includes "followwrap" |
| 'foldmethod' "diff" |
| 'foldcolumn' value from 'diffopt', default is 2 |
| |
| These options are set local to the window. When editing another file they are |
| reset to the global value. |
| The options can still be overruled from a modeline when re-editing the file. |
| However, 'foldmethod' and 'wrap' won't be set from a modeline when 'diff' is |
| set. |
| See `:diffoff` for an easy way to revert the options. |
| |
| The differences shown are actually the differences in the buffer. Thus if you |
| make changes after loading a file, these will be included in the displayed |
| diffs. You might have to do ":diffupdate" now and then, not all changes are |
| immediately taken into account, especially when using an external diff command. |
| |
| In your .vimrc file you could do something special when Vim was started in |
| diff mode. You could use a construct like this: > |
| |
| if &diff |
| setup for diff mode |
| else |
| setup for non-diff mode |
| endif |
| |
| While already in Vim you can start diff mode in three ways. |
| |
| *E98* |
| :diffs[plit] {filename} *:diffs* *:diffsplit* |
| Open a new window on the file {filename}. The options are set |
| as for "vimdiff" for the current and the newly opened window. |
| Also see 'diffexpr'. |
| |
| *:difft* *:diffthis* |
| :difft[his] Make the current window part of the diff windows. This sets |
| the options like for "vimdiff". |
| |
| :diffp[atch] {patchfile} *E816* *:diffp* *:diffpatch* |
| Use the current buffer, patch it with the diff found in |
| {patchfile} and open a buffer on the result. The options are |
| set as for "vimdiff". |
| {patchfile} can be in any format that the "patch" program |
| understands or 'patchexpr' can handle. |
| Note that {patchfile} should only contain a diff for one file, |
| the current file. If {patchfile} contains diffs for other |
| files as well, the results are unpredictable. Vim changes |
| directory to /tmp to avoid files in the current directory |
| accidentally being patched. But it may still result in |
| various ".rej" files to be created. And when absolute path |
| names are present these files may get patched anyway. |
| Using the "patch" command is not allowed in |restricted-mode|. |
| |
| To make these commands use a vertical split, prepend |:vertical|. Examples: > |
| |
| :vert diffsplit main.c~ |
| :vert diffpatch /tmp/diff |
| |
| If you always prefer a vertical split include "vertical" in 'diffopt'. |
| |
| *E96* |
| There can be up to eight buffers with 'diff' set. |
| |
| Since the option values are remembered with the buffer, you can edit another |
| file for a moment and come back to the same file and be in diff mode again. |
| |
| *:diffo* *:diffoff* |
| :diffo[ff] Switch off diff mode for the current window. Resets related |
| options also when 'diff' was not set. |
| |
| :diffo[ff]! Switch off diff mode for the current window and in all windows |
| in the current tab page where 'diff' is set. Resetting |
| related options only happens in a window that has 'diff' set, |
| if the current window does not have 'diff' set then no options |
| in it are changed. |
| Hidden buffers are also removed from the list of diff'ed |
| buffers. |
| |
| The `:diffoff` command resets the relevant options to the values they had when |
| using `:diffsplit`, `:diffpatch`, `:diffthis`. or starting Vim in diff mode. |
| When using `:diffoff` twice the last saved values are restored. |
| Otherwise they are set to their default value: |
| |
| 'diff' off |
| 'scrollbind' off |
| 'cursorbind' off |
| 'scrollopt' without "hor" |
| 'wrap' on, or leave as-is if 'diffopt' includes "followwrap" |
| 'foldmethod' "manual" |
| 'foldcolumn' 0 |
| |
| 'foldenable' will most-likely be reset to off. That is when 'foldmethod' is |
| is restored to "manual". The folds themselves are not cleared but they should |
| not show up, resetting 'foldenable' is the best way to do that. |
| |
| ============================================================================== |
| 2. Viewing diffs *view-diffs* |
| |
| The effect is that the diff windows show the same text, with the differences |
| highlighted. When scrolling the text, the 'scrollbind' option will make the |
| text in other windows to be scrolled as well. With vertical splits the text |
| should be aligned properly. |
| |
| The alignment of text will go wrong when: |
| - 'wrap' is on, some lines will be wrapped and occupy two or more screen |
| lines |
| - folds are open in one window but not another |
| - 'scrollbind' is off |
| - changes have been made to the text |
| - "filler" is not present in 'diffopt', deleted/inserted lines makes the |
| alignment go wrong |
| |
| All the buffers edited in a window where the 'diff' option is set will join in |
| the diff. This is also possible for hidden buffers. They must have been |
| edited in a window first for this to be possible. To get rid of the hidden |
| buffers use `:diffoff!`. |
| |
| *:DiffOrig* *diff-original-file* |
| Since 'diff' is a window-local option, it's possible to view the same buffer |
| in diff mode in one window and "normal" in another window. It is also |
| possible to view the changes you have made to a buffer since the file was |
| loaded. Since Vim doesn't allow having two buffers for the same file, you |
| need another buffer. This command is useful: > |
| command DiffOrig vert new | set bt=nofile | r ++edit # | 0d_ |
| \ | diffthis | wincmd p | diffthis |
| (this is in |defaults.vim|). Use ":DiffOrig" to see the differences between |
| the current buffer and the file it was loaded from. |
| |
| A buffer that is unloaded cannot be used for the diff. But it does work for |
| hidden buffers. You can use ":hide" to close a window without unloading the |
| buffer. If you don't want a buffer to remain used for the diff do ":set |
| nodiff" before hiding it. |
| |
| *:dif* *:diff* *:diffupdate* |
| :dif[fupdate][!] Update the diff highlighting and folds. |
| |
| Vim attempts to keep the differences updated when you make changes to the |
| text. This mostly takes care of inserted and deleted lines. Changes within a |
| line and more complicated changes do not cause the differences to be updated. |
| To force the differences to be updated use: > |
| |
| :diffupdate |
| |
| If the ! is included Vim will check if the file was changed externally and |
| needs to be reloaded. It will prompt for each changed file, like `:checktime` |
| was used. |
| |
| Vim will show filler lines for lines that are missing in one window but are |
| present in another. These lines were inserted in another file or deleted in |
| this file. Removing "filler" from the 'diffopt' option will make Vim not |
| display these filler lines. |
| |
| |
| Folds are used to hide the text that wasn't changed. See |folding| for all |
| the commands that can be used with folds. |
| |
| The context of lines above a difference that are not included in the fold can |
| be set with the 'diffopt' option. For example, to set the context to three |
| lines: > |
| |
| :set diffopt=filler,context:3 |
| |
| |
| The diffs are highlighted with these groups: |
| |
| |hl-DiffAdd| DiffAdd Added (inserted) lines. These lines exist in |
| this buffer but not in another. |
| |hl-DiffChange| DiffChange Changed lines. |
| |hl-DiffText| DiffText Changed text inside a Changed line. Exact |
| behavior depends on the `inline:` setting in |
| 'diffopt'. |
| With `inline:` set to "simple", Vim finds the |
| first character that is different, and the |
| last character that is different (searching |
| from the end of the line). The text in |
| between is highlighted. This means that parts |
| in the middle that are still the same are |
| highlighted anyway. The 'diffopt' flags |
| "iwhite" and "icase" are used here. |
| With `inline:` set to "char" or "word", Vim |
| uses the internal diff library to perform a |
| detailed diff between the changed blocks and |
| highlight the exact difference between the |
| two. Will respect any 'diffopt' flag that |
| affects internal diff. |
| Not used when `inline:` is set to "none". |
| |hl-DiffTextAdd| DiffTextAdd Added text inside a Changed line. Similar to |
| DiffText, but used when there is no |
| corresponding text in other buffers. Not used |
| when `inline:` is set to "simple" or "none". |
| |hl-DiffDelete| DiffDelete Deleted lines. Also called filler lines, |
| because they don't really exist in this |
| buffer. |
| |
| ============================================================================== |
| 3. Jumping to diffs *jumpto-diffs* |
| |
| Two commands can be used to jump to diffs: |
| *[c* |
| [c Jump backwards to the previous start of a change. |
| When a count is used, do it that many times. |
| *]c* |
| ]c Jump forwards to the next start of a change. |
| When a count is used, do it that many times. |
| |
| It is an error if there is no change for the cursor to move to. |
| |
| ============================================================================== |
| 4. Diff copying *copy-diffs* *E99* *E100* *E101* *E102* *E103* |
| *merge* |
| There are two commands to copy text from one buffer to another. The result is |
| that the buffers will be equal within the specified range. |
| |
| *:diffg* *:diffget* |
| :[range]diffg[et] [bufspec] |
| Modify the current buffer to undo difference with another |
| buffer. If [bufspec] is given, that buffer is used. If |
| [bufspec] refers to the current buffer then nothing happens. |
| Otherwise this only works if there is one other buffer in diff |
| mode. |
| See below for [range]. |
| |
| *:diffpu* *:diffput* *E793* |
| :[range]diffpu[t] [bufspec] |
| Modify another buffer to undo difference with the current |
| buffer. Just like ":diffget" but the other buffer is modified |
| instead of the current one. |
| When [bufspec] is omitted and there is more than one other |
| buffer in diff mode where 'modifiable' is set this fails. |
| See below for [range]. |
| |
| *do* |
| [count]do Same as ":diffget" without range. The "o" stands for "obtain" |
| ("dg" can't be used, it could be the start of "dgg"!). Note: |
| this doesn't work in Visual mode. |
| If you give a [count], it is used as the [bufspec] argument |
| for ":diffget". |
| |
| *dp* |
| [count]dp Same as ":diffput" without range. Note: this doesn't work in |
| Visual mode. |
| If you give a [count], it is used as the [bufspec] argument |
| for ":diffput". |
| |
| |
| When no [range] is given, the diff at the cursor position or just above it is |
| affected. There can be deleted lines below the last line of the buffer. When |
| the cursor is on the last line in the buffer and there is no diff above this |
| line, and no [range] is given, the diff below the cursor position will be used |
| instead. |
| |
| When [range] is used, Vim tries to only put or get the specified lines. When |
| there are deleted lines, they will be used if they are between the lines |
| specified by [range]. |
| |
| To be able to put or get those lines to/from another buffer in a [range] it's |
| allowed to use 0 and the last line number plus one. This command gets all |
| diffs from the other buffer: > |
| |
| :0,$+1diffget |
| |
| Note that deleted lines are displayed, but not counted as text lines. You |
| can't move the cursor into them. To fill the deleted lines with the lines |
| from another buffer use ":diffget" on the line below them. |
| *E787* |
| When the buffer that is about to be modified is read-only and the autocommand |
| that is triggered by |FileChangedRO| changes buffers the command will fail. |
| The autocommand must not change buffers. |
| |
| The [bufspec] argument above can be a buffer number, a pattern for a buffer |
| name or a part of a buffer name. Examples: |
| |
| :diffget Use the other buffer which is in diff mode |
| :diffget 3 Use buffer 3 |
| :diffget v2 Use the buffer which matches "v2" and is in |
| diff mode (e.g., "file.c.v2") |
| |
| ============================================================================== |
| 5. Diff options *diff-options* |
| |
| Also see |'diffopt'| and the "diff" item of |'fillchars'|. |
| |
| *diff-slow* *diff_translations* |
| For very long lines, the diff syntax highlighting might be slow, especially |
| since it tries to match all different kind of localisations. To disable |
| localisations and speed up the syntax highlighting, set the global variable |
| g:diff_translations to zero: > |
| |
| let g:diff_translations = 0 |
| < |
| After setting this variable, reload the syntax script: > |
| |
| set syntax=diff |
| < |
| |
| |
| FINDING THE DIFFERENCES *diff-diffexpr* |
| |
| The 'diffexpr' option can be set to use something else than the internal diff |
| support or the standard "diff" program to compare two files and find the |
| differences. *E959* |
| |
| When 'diffexpr' is empty, Vim uses this command to find the differences |
| between file1 and file2: > |
| |
| diff file1 file2 > outfile |
| |
| The ">" is replaced with the value of 'shellredir'. |
| |
| The output of "diff" must be a normal "ed" style diff or a unified diff. A |
| context diff will NOT work. For a unified diff no context lines can be used. |
| Using "diff -u" will NOT work, use "diff -U0". |
| |
| This example explains the format that Vim expects for the "ed" style diff: > |
| |
| 1a2 |
| > bbb |
| 4d4 |
| < 111 |
| 7c7 |
| < GGG |
| --- |
| > ggg |
| |
| The "1a2" item appends the line "bbb". |
| The "4d4" item deletes the line "111". |
| The "7c7" item replaces the line "GGG" with "ggg". |
| |
| When 'diffexpr' is not empty, Vim evaluates it to obtain a diff file in the |
| format mentioned. These variables are set to the file names used: |
| |
| v:fname_in original file |
| v:fname_new new version of the same file |
| v:fname_out where to write the resulting diff file |
| |
| Additionally, 'diffexpr' should take care of "icase" and "iwhite" in the |
| 'diffopt' option. 'diffexpr' cannot change the value of 'lines' and |
| 'columns'. |
| |
| The advantage of using a function call without arguments is that it is faster, |
| see |expr-option-function|. |
| |
| Example (this does almost the same as 'diffexpr' being empty): > |
| |
| set diffexpr=MyDiff() |
| function MyDiff() |
| let opt = "" |
| if &diffopt =~ "icase" |
| let opt = opt .. "-i " |
| endif |
| if &diffopt =~ "iwhite" |
| let opt = opt .. "-b " |
| endif |
| silent execute "!diff -a --binary " .. opt .. v:fname_in .. " " .. v:fname_new .. |
| \ " > " .. v:fname_out |
| redraw! |
| endfunction |
| |
| The "-a" argument is used to force comparing the files as text, comparing as |
| binaries isn't useful. The "--binary" argument makes the files read in binary |
| mode, so that a CTRL-Z doesn't end the text on DOS. |
| |
| The `redraw!` command may not be needed, depending on whether executing a |
| shell command shows something on the display or not. |
| |
| If the 'diffexpr' expression starts with s: or |<SID>|, then it is replaced |
| with the script ID (|local-function|). Example: > |
| set diffexpr=s:MyDiffExpr() |
| set diffexpr=<SID>SomeDiffExpr() |
| Otherwise, the expression is evaluated in the context of the script where the |
| option was set, thus script-local items are available. |
| |
| *E810* *E97* |
| Vim will do a test if the diff output looks alright. If it doesn't, you will |
| get an error message. Possible causes: |
| - The "diff" program cannot be executed. |
| - The "diff" program doesn't produce normal "ed" style diffs (see above). |
| - The 'shell' and associated options are not set correctly. Try if filtering |
| works with a command like ":!sort". |
| - You are using 'diffexpr' and it doesn't work. |
| If it's not clear what the problem is set the 'verbose' option to one or more |
| to see more messages. |
| |
| The self-installing Vim for MS-Windows includes a diff program. If you don't |
| have it you might want to download a diff.exe. For example from |
| http://gnuwin32.sourceforge.net/packages/diffutils.htm. |
| |
| |
| USING PATCHES *diff-patchexpr* |
| |
| The 'patchexpr' option can be set to use something else than the standard |
| "patch" program. |
| |
| When 'patchexpr' is empty, Vim will call the "patch" program like this: > |
| |
| patch -o outfile origfile < patchfile |
| |
| This should work fine with most versions of the "patch" program. Note that a |
| CR in the middle of a line may cause problems, it is seen as a line break. |
| |
| If the default doesn't work for you, set the 'patchexpr' to an expression that |
| will have the same effect. These variables are set to the file names used: |
| |
| v:fname_in original file |
| v:fname_diff patch file |
| v:fname_out resulting patched file |
| |
| The advantage of using a function call without arguments is that it is faster, |
| see |expr-option-function|. |
| |
| Example (this does the same as 'patchexpr' being empty): > |
| |
| set patchexpr=MyPatch() |
| function MyPatch() |
| :call system("patch -o " .. v:fname_out .. " " .. v:fname_in .. |
| \ " < " .. v:fname_diff) |
| endfunction |
| |
| Make sure that using the "patch" program doesn't have unwanted side effects. |
| For example, watch out for additionally generated files, which should be |
| deleted. It should just patch the file and nothing else. |
| Vim will change directory to "/tmp" or another temp directory before |
| evaluating 'patchexpr'. This hopefully avoids that files in the current |
| directory are accidentally patched. Vim will also delete files starting with |
| v:fname_in and ending in ".rej" and ".orig". |
| |
| If the 'patchexpr' expression starts with s: or |<SID>|, then it is replaced |
| with the script ID (|local-function|). Example: > |
| set patchexpr=s:MyPatchExpr() |
| set patchexpr=<SID>SomePatchExpr() |
| Otherwise, the expression is evaluated in the context of the script where the |
| option was set, thus script-local items are available. |
| |
| |
| DIFF FUNCTION EXAMPLES *diff-func-examples* |
| |
| Some examples for using the |diff()| function to compute the diff indices |
| between two Lists of strings are below. |
| > |
| " some lines are changed |
| :echo diff(['abc', 'def', 'ghi'], ['abx', 'rrr', 'xhi'], {'output': 'indices'}) |
| [{'from_idx': 0, 'from_count': 3, 'to_idx': 0, 'to_count': 3}] |
| |
| " few lines added at the beginning |
| :echo diff(['ghi'], ['abc', 'def', 'ghi'], {'output': 'indices'}) |
| [{'from_idx': 0, 'from_count': 0, 'to_idx': 0, 'to_count': 2}] |
| |
| " few lines removed from the beginning |
| :echo diff(['abc', 'def', 'ghi'], ['ghi'], {'output': 'indices'}) |
| [{'from_idx': 0, 'from_count': 2, 'to_idx': 0, 'to_count': 0}] |
| |
| " few lines added in the middle |
| :echo diff(['abc', 'jkl'], ['abc', 'def', 'ghi', 'jkl'], {'output': 'indices'}) |
| [{'from_idx': 1, 'from_count': 0, 'to_idx': 1, 'to_count': 2}] |
| |
| " few lines removed in the middle |
| :echo diff(['abc', 'def', 'ghi', 'jkl'], ['abc', 'jkl'], {'output': 'indices'}) |
| [{'from_idx': 1, 'from_count': 2, 'to_idx': 1, 'to_count': 0}] |
| |
| " few lines added at the end |
| :echo diff(['abc'], ['abc', 'def', 'ghi'], {'output': 'indices'}) |
| [{'from_idx': 1, 'from_count': 0, 'to_idx': 1, 'to_count': 2}] |
| |
| " few lines removed from the end |
| :echo diff(['abc', 'def', 'ghi'], ['abc'], {'output': 'indices'}) |
| [{'from_idx': 1, 'from_count': 2, 'to_idx': 1, 'to_count': 0}] |
| |
| " disjointed changes |
| :echo diff(['ab', 'def', 'ghi', 'jkl'], ['abc', 'def', 'ghi', 'jk'], {'output': 'indices', 'context': 0}) |
| [{'from_idx': 0, 'from_count': 1, 'to_idx': 0, 'to_count': 1}, |
| {'from_idx': 3, 'from_count': 1, 'to_idx': 3, 'to_count': 1}] |
| |
| " disjointed changes with context length 1 |
| :echo diff(['ab', 'def', 'ghi', 'jkl'], ['abc', 'def', 'ghi', 'jk'], {'output': 'indices', 'context': 1}) |
| [{'from_idx': 0, 'from_count': 4, 'to_idx': 0, 'to_count': 4}] |
| |
| < |
| |
| vim:tw=78:ts=8:noet:ft=help:norl: |