codekingpro/portable-devtools
114k
1*diff.txt* For Vim version 9.2. Last change: 2026 Feb 142 3 4 VIM REFERENCE MANUAL by Bram Moolenaar5 6 7 *diff* *vimdiff* *gvimdiff* *diff-mode*8This file describes the |+diff| feature: Showing differences between two to9eight versions of the same file.10 11The basics are explained in section |08.7| of the user manual.12 131. Starting diff mode |start-vimdiff|142. Viewing diffs |view-diffs|153. Jumping to diffs |jumpto-diffs|164. Copying diffs |copy-diffs|175. Diff anchors |diff-anchors|186. Diff options |diff-options|19 20==============================================================================211. Starting diff mode *start-vimdiff*22 23The easiest way to start editing in diff mode is with the "vimdiff" command.24This starts Vim as usual, and additionally sets up for viewing the differences25between the arguments. >26 27 vimdiff file1 file2 [file3 [file4]]28 29This is equivalent to: >30 31 vim -d file1 file2 [file3 [file4]]32 33You may also use "gvimdiff" or "vim -d -g". The GUI is started then.34You may also use "viewdiff" or "gviewdiff". Vim starts in readonly mode then.35"r" may be prepended for restricted mode (see |-Z|).36 37The second and following arguments may also be a directory name. Vim will38then append the file name of the first argument to the directory name to find39the file.40 41By default an internal diff library will be used. When 'diffopt' or42'diffexpr' has been set an external "diff" command will be used. This only43works when such a diff program is available.44 45Diffs are local to the current tab page |tab-page|. You can't see diffs with46a window in another tab page. This does make it possible to have several47diffs at the same time, each in their own tab page.48 49What happens is that Vim opens a window for each of the files. This is like50using the |-O| argument. This uses vertical splits. If you prefer horizontal51splits add the |-o| argument: >52 53 vimdiff -o file1 file2 [file3 [file4]]54 55If you always prefer horizontal splits include "horizontal" in 'diffopt'.56 57In each of the edited files these options are set:58 59 'diff' on60 'scrollbind' on61 'cursorbind' on62 'scrollopt' includes "hor"63 'wrap' off, or leave as-is if 'diffopt' includes "followwrap"64 'foldmethod' "diff"65 'foldcolumn' value from 'diffopt', default is 266 67These options are set local to the window. When editing another file they are68reset to the global value.69The options can still be overruled from a modeline when re-editing the file.70However, 'foldmethod' and 'wrap' won't be set from a modeline when 'diff' is71set.72See `:diffoff` for an easy way to revert the options.73 74The differences shown are actually the differences in the buffer. Thus if you75make changes after loading a file, these will be included in the displayed76diffs. You might have to do ":diffupdate" now and then, not all changes are77immediately taken into account, especially when using an external diff78command.79 80In your .vimrc file you could do something special when Vim was started in81diff mode. You could use a construct like this: >82 83 if &diff84 setup for diff mode85 else86 setup for non-diff mode87 endif88 89While already in Vim you can start diff mode in three ways.90 91 *E98*92:diffs[plit] {filename} *:diffs* *:diffsplit*93 Open a new window on the file {filename}. The options are set94 as for "vimdiff" for the current and the newly opened window.95 Also see 'diffexpr'.96 97 *:difft* *:diffthis*98:difft[his] Make the current window part of the diff windows. This sets99 the options like for "vimdiff".100 101:diffp[atch] {patchfile} *E816* *:diffp* *:diffpatch*102 Use the current buffer, patch it with the diff found in103 {patchfile} and open a buffer on the result. The options are104 set as for "vimdiff".105 {patchfile} can be in any format that the "patch" program106 understands or 'patchexpr' can handle.107 Note that {patchfile} should only contain a diff for one file,108 the current file. If {patchfile} contains diffs for other109 files as well, the results are unpredictable. Vim changes110 directory to /tmp to avoid files in the current directory111 accidentally being patched. But it may still result in112 various ".rej" files to be created. And when absolute path113 names are present these files may get patched anyway.114 Using the "patch" command is not allowed in |restricted-mode|.115 116To make these commands use a vertical split, prepend |:vertical|. Examples: >117 118 :vert diffsplit main.c~119 :vert diffpatch /tmp/diff120 121If you always prefer a vertical split include "vertical" in 'diffopt'.122 123 *E96*124There can be up to eight buffers with 'diff' set.125 126Since the option values are remembered with the buffer, you can edit another127file for a moment and come back to the same file and be in diff mode again.128 129 *:diffo* *:diffoff*130:diffo[ff] Switch off diff mode for the current window. Resets related131 options also when 'diff' was not set.132 133:diffo[ff]! Switch off diff mode for the current window and in all windows134 in the current tab page where 'diff' is set. Resetting135 related options only happens in a window that has 'diff' set,136 if the current window does not have 'diff' set then no options137 in it are changed.138 Hidden buffers are also removed from the list of diff'ed139 buffers.140 141The `:diffoff` command resets the relevant options to the values they had when142using `:diffsplit`, `:diffpatch`, `:diffthis`, or starting Vim in diff mode.143When using `:diffoff` twice the last saved values are restored.144Otherwise they are set to their default value:145 146 'diff' off147 'scrollbind' off148 'cursorbind' off149 'scrollopt' without "hor"150 'wrap' on, or leave as-is if 'diffopt' includes "followwrap"151 'foldmethod' "manual"152 'foldcolumn' 0153 154'foldenable' will most-likely be reset to off. That is when 'foldmethod' is155is restored to "manual". The folds themselves are not cleared but they should156not show up, resetting 'foldenable' is the best way to do that.157 158==============================================================================1592. Viewing diffs *view-diffs*160 161The effect is that the diff windows show the same text, with the differences162highlighted. When scrolling the text, the 'scrollbind' option will make the163text in other windows to be scrolled as well. With vertical splits the text164should be aligned properly.165 166The alignment of text will go wrong when:167- 'wrap' is on, some lines will be wrapped and occupy two or more screen168 lines169- folds are open in one window but not another170- 'scrollbind' is off171- changes have been made to the text172- "filler" is not present in 'diffopt', deleted/inserted lines makes the173 alignment go wrong174 175All the buffers edited in a window where the 'diff' option is set will join in176the diff. This is also possible for hidden buffers. They must have been177edited in a window first for this to be possible. To get rid of the hidden178buffers use `:diffoff!`.179 180 *:DiffOrig* *diff-original-file*181Since 'diff' is a window-local option, it's possible to view the same buffer182in diff mode in one window and "normal" in another window. It is also183possible to view the changes you have made to a buffer since the file was184loaded. Since Vim doesn't allow having two buffers for the same file, you185need another buffer. This command is useful: >186 command DiffOrig vert new | set bt=nofile | r ++edit # | 0d_187 \ | diffthis | wincmd p | diffthis188(this is in |defaults.vim|). Use ":DiffOrig" to see the differences between189the current buffer and the file it was loaded from.190 191A buffer that is unloaded cannot be used for the diff. But it does work for192hidden buffers. You can use ":hide" to close a window without unloading the193buffer. If you don't want a buffer to remain used for the diff do ":set194nodiff" before hiding it.195 196 *:dif* *:diff* *:diffupdate*197:dif[fupdate][!] Update the diff highlighting and folds.198 199Vim attempts to keep the differences updated when you make changes to the200text. This mostly takes care of inserted and deleted lines. Changes within a201line and more complicated changes do not cause the differences to be updated.202To force the differences to be updated use: >203 204 :diffupdate205 206If the ! is included Vim will check if the file was changed externally and207needs to be reloaded. It will prompt for each changed file, like `:checktime`208was used.209 210Vim will show filler lines for lines that are missing in one window but are211present in another. These lines were inserted in another file or deleted in212this file. Removing "filler" from the 'diffopt' option will make Vim not213display these filler lines.214 215 216Folds are used to hide the text that wasn't changed. See |folding| for all217the commands that can be used with folds.218 219The context of lines above a difference that are not included in the fold can220be set with the 'diffopt' option. For example, to set the context to three221lines: >222 223 :set diffopt=filler,context:3224 225 226The diffs are highlighted with these groups:227 228|hl-DiffAdd| DiffAdd Added (inserted) lines. These lines exist in229 this buffer but not in another.230|hl-DiffChange| DiffChange Changed lines.231|hl-DiffText| DiffText Changed text inside a Changed line. Exact232 behavior depends on the `inline:` setting in233 'diffopt'.234 With `inline:` set to "simple", Vim finds the235 first character that is different, and the236 last character that is different (searching237 from the end of the line). The text in238 between is highlighted. This means that parts239 in the middle that are still the same are240 highlighted anyway. The 'diffopt' flags241 "iwhite" and "icase" are used here.242 With `inline:` set to "char" or "word", Vim243 uses the internal diff library to perform a244 detailed diff between the changed blocks and245 highlight the exact difference between the246 two. Will respect any 'diffopt' flag that247 affects internal diff.248 Not used when `inline:` is set to "none".249|hl-DiffTextAdd| DiffTextAdd Added text inside a Changed line. Similar to250 DiffText, but used when there is no251 corresponding text in other buffers. Not used252 when `inline:` is set to "simple" or "none".253|hl-DiffDelete| DiffDelete Deleted lines. Also called filler lines,254 because they don't really exist in this255 buffer.256 257==============================================================================2583. Jumping to diffs *jumpto-diffs*259 260Two commands can be used to jump to diffs:261 *[c*262 [c Jump backwards to the previous start of a change.263 When a count is used, do it that many times.264 *]c*265 ]c Jump forwards to the next start of a change.266 When a count is used, do it that many times.267 268It is an error if there is no change for the cursor to move to.269 270==============================================================================2714. Diff copying *copy-diffs* *E99* *E100* *E101* *E102* *E103*272 *merge*273There are two commands to copy text from one buffer to another. The result is274that the buffers will be equal within the specified range.275 276 *:diffg* *:diffget*277:[range]diffg[et] [bufspec]278 Modify the current buffer to undo difference with another279 buffer. If [bufspec] is given, that buffer is used. If280 [bufspec] refers to the current buffer then nothing happens.281 Otherwise this only works if there is one other buffer in diff282 mode.283 See below for [range].284 285 *:diffpu* *:diffput* *E793*286:[range]diffpu[t] [bufspec]287 Modify another buffer to undo difference with the current288 buffer. Just like ":diffget" but the other buffer is modified289 instead of the current one.290 When [bufspec] is omitted and there is more than one other291 buffer in diff mode where 'modifiable' is set this fails.292 See below for [range].293 294 *do*295[count]do Same as ":diffget" without range. The "o" stands for "obtain"296 ("dg" can't be used, it could be the start of "dgg"!). Note:297 this doesn't work in Visual mode.298 If you give a [count], it is used as the [bufspec] argument299 for ":diffget".300 301 *dp*302[count]dp Same as ":diffput" without range. Note: this doesn't work in303 Visual mode.304 If you give a [count], it is used as the [bufspec] argument305 for ":diffput".306 307 308When no [range] is given, the diff at the cursor position or just above it is309affected. There can be deleted lines below the last line of the buffer. When310the cursor is on the last line in the buffer and there is no diff above this311line, and no [range] is given, the diff below the cursor position will be used312instead.313 314When [range] is used, Vim tries to only put or get the specified lines. When315there are deleted lines, they will be used if they are between the lines316specified by [range].317 318To be able to put or get those lines to/from another buffer in a [range] it's319allowed to use 0 and the last line number plus one. This command gets all320diffs from the other buffer: >321 322 :0,$+1diffget323 324Note that deleted lines are displayed, but not counted as text lines. You325can't move the cursor into them. To fill the deleted lines with the lines326from another buffer use ":diffget" on the line below them.327 *E787*328When the buffer that is about to be modified is read-only and the autocommand329that is triggered by |FileChangedRO| changes buffers the command will fail.330The autocommand must not change buffers.331 332The [bufspec] argument above can be a buffer number, a pattern for a buffer333name or a part of a buffer name. Examples:334 335 :diffget Use the other buffer which is in diff mode336 :diffget 3 Use buffer 3337 :diffget v2 Use the buffer which matches "v2" and is in338 diff mode (e.g., "file.c.v2")339 340==============================================================================3415. Diff anchors *diff-anchors*342 343Diff anchors allow you to control where the diff algorithm aligns and344synchronize text across files. Each anchor matches each other in each file,345allowing you to control the output of a diff.346 347This is useful when a change involves complicated edits. For example, if a348function was moved to another location and further edited. By default, the349algorithm aims to create the smallest diff, which results in that entire350function being considered to be deleted and added on the other side, making it351hard to see what the actual edit on it was. You can use diff anchors to pin352that function so the diff algorithm will align based on it.353 354To use it, set anchors using 'diffanchors' which is a comma-separated list of355{address} in each file, and then add "anchor" to 'diffopt'. Internally, Vim356splits each file up into sections split by the anchors. It performs the diff357on each pair of sections separately before merging the results back.358 359Setting 'diffanchors' will update the diff immediately. If an anchor is tied360to a mark, and you change what the mark is pointed to, you need to manually361call |:diffupdate| afterwards to get the updated diff results.362 363Example:364 365Let's say we have the following files, side-by-side. We are interested in the366change that happened to the function `foo()`, which was both edited and moved.367 368File A: >369 int foo() {370 int n = 1;371 return n;372 }373 374 int g = 1;375 376 int bar(int a) {377 a *= 2;378 a += 3;379 return a;380 }381<File B: >382 int bar(int a) {383 a *= 2;384 a += 3;385 return a;386 }387 388 int foo() {389 int n = 999;390 return n;391 }392 393 int g = 1;394<395A normal diff will usually align the diff result as such: >396 397 int foo() { |----------------398 int n = 1; |----------------399 return n; |----------------400 } |----------------401 |----------------402 int g = 1; |----------------403 |----------------404 int bar(int a) {|int bar(int a) {405 a *= 2; | a *= 2;406 a += 3; | a += 3;407 return a; | return a;408 } |}409 ----------------|410 ----------------|int foo() {411 ----------------| int n = 999;412 ----------------| return n;413 ----------------|}414 ----------------|415 ----------------|int g = 1;416<417What we want is to instead ask the diff to align on `foo()`: >418 419 ----------------|int bar(int a) {420 ----------------| a *= 2;421 ----------------| a += 3;422 ----------------| return a;423 ----------------|}424 ----------------|425 int foo() { |int foo() {426 int n = 1; | int n = 999;427 return n; | return n;428 } |}429 |430 int g = 1; |int g = 1;431 |----------------432 int bar(int a) {|----------------433 a *= 2; |----------------434 a += 3; |----------------435 return a; |----------------436 } |----------------437<438 439Below are some ways of setting diff anchors to get the above result. In each440example, 'diffopt' needs to have `anchor` set for this to take effect.441 442Marks: Set the |'a| mark on the `int foo()` lines in each file first before443setting the anchors: >444 set diffanchors='a445 446Pattern: Specify the anchor using a |pattern| (see |:/|). Here, we make sure447to always start search from line 1 for consistency: >448 set diffanchors=1/int\ foo(/449<450Selection: Use visual mode to select the entire `foo()` function body in each451file. Here, we use two anchors. This does a better job of making sure only452the function bodies are anchored against each other but not the lines after453it. Note the `'>+1` below. The "+1" is necessary as we want the split to454happen below the last line of the function, not above: >455 set diffanchors='<,'>+1456<457Manually set two anchors using line numbers via buffer-local options: >458 setlocal diffanchors=1,5459 wincmd w460 setlocal diffanchors=7,11461<462==============================================================================4636. Diff options *diff-options*464 465Also see 'diffopt' and the "diff" item of 'fillchars'.466 467 *diff-slow* *diff_translations*468For very long lines, the diff syntax highlighting might be slow, especially469since it tries to match all different kind of localisations. To disable470localisations and speed up the syntax highlighting, set the global variable471g:diff_translations to zero: >472 473 let g:diff_translations = 0474<475After setting this variable, reload the syntax script: >476 477 set syntax=diff478<479 480 481FINDING THE DIFFERENCES *diff-diffexpr*482 483The 'diffexpr' option can be set to use something else than the internal diff484support or the standard "diff" program to compare two files and find the485differences. *E959*486 487When 'diffexpr' is empty, Vim uses this command to find the differences488between file1 and file2: >489 490 diff file1 file2 > outfile491 492The ">" is replaced with the value of 'shellredir'.493 494The output of "diff" must be a normal "ed" style diff or a unified diff. A495context diff will NOT work. For a unified diff no context lines can be used.496Using "diff -u" will NOT work, use "diff -U0".497 498This example explains the format that Vim expects for the "ed" style diff: >499 500 1a2501 > bbb502 4d4503 < 111504 7c7505 < GGG506 ---507 > ggg508 509The "1a2" item appends the line "bbb".510The "4d4" item deletes the line "111".511The "7c7" item replaces the line "GGG" with "ggg".512 513When 'diffexpr' is not empty, Vim evaluates it to obtain a diff file in the514format mentioned. These variables are set to the file names used:515 516 v:fname_in original file517 v:fname_new new version of the same file518 v:fname_out where to write the resulting diff file519 520Additionally, 'diffexpr' should take care of "icase" and "iwhite" in the521'diffopt' option. 'diffexpr' cannot change the value of 'lines' and522'columns'.523 524The advantage of using a function call without arguments is that it is faster,525see |expr-option-function|.526 527Example (this does almost the same as 'diffexpr' being empty): >528 529 set diffexpr=MyDiff()530 function MyDiff()531 let opt = ""532 if &diffopt =~ "icase"533 let opt = opt .. "-i "534 endif535 if &diffopt =~ "iwhite"536 let opt = opt .. "-b "537 endif538 silent execute "!diff -a --binary " .. opt .. v:fname_in .. " " .. v:fname_new ..539 \ " > " .. v:fname_out540 redraw!541 endfunction542 543The "-a" argument is used to force comparing the files as text, comparing as544binaries isn't useful. The "--binary" argument makes the files read in binary545mode, so that a CTRL-Z doesn't end the text on DOS.546 547The `redraw!` command may not be needed, depending on whether executing a548shell command shows something on the display or not.549 550If the 'diffexpr' expression starts with s: or |<SID>|, then it is replaced551with the script ID (|local-function|). Example: >552 set diffexpr=s:MyDiffExpr()553 set diffexpr=<SID>SomeDiffExpr()554Otherwise, the expression is evaluated in the context of the script where the555option was set, thus script-local items are available.556 557 *E810* *E97*558Vim will do a test if the diff output looks alright. If it doesn't, you will559get an error message. Possible causes:560- The "diff" program cannot be executed.561- The "diff" program doesn't produce normal "ed" style diffs (see above).562- The 'shell' and associated options are not set correctly. Try if filtering563 works with a command like ":!sort".564- You are using 'diffexpr' and it doesn't work.565If it's not clear what the problem is set the 'verbose' option to one or more566to see more messages.567 568The self-installing Vim for MS-Windows includes a diff program. If you don't569have it you might want to download a diff.exe. For example from570http://gnuwin32.sourceforge.net/packages/diffutils.htm.571 572 573USING PATCHES *diff-patchexpr*574 575The 'patchexpr' option can be set to use something else than the standard576"patch" program.577 578When 'patchexpr' is empty, Vim will call the "patch" program like this: >579 580 patch -o outfile origfile < patchfile581 582This should work fine with most versions of the "patch" program. Note that a583CR in the middle of a line may cause problems, it is seen as a line break.584 585If the default doesn't work for you, set the 'patchexpr' to an expression that586will have the same effect. These variables are set to the file names used:587 588 v:fname_in original file589 v:fname_diff patch file590 v:fname_out resulting patched file591 592The advantage of using a function call without arguments is that it is faster,593see |expr-option-function|.594 595Example (this does the same as 'patchexpr' being empty): >596 597 set patchexpr=MyPatch()598 function MyPatch()599 :call system("patch -o " .. v:fname_out .. " " .. v:fname_in ..600 \ " < " .. v:fname_diff)601 endfunction602 603Make sure that using the "patch" program doesn't have unwanted side effects.604For example, watch out for additionally generated files, which should be605deleted. It should just patch the file and nothing else.606 Vim will change directory to "/tmp" or another temp directory before607evaluating 'patchexpr'. This hopefully avoids that files in the current608directory are accidentally patched. Vim will also delete files starting with609v:fname_in and ending in ".rej" and ".orig".610 611If the 'patchexpr' expression starts with s: or |<SID>|, then it is replaced612with the script ID (|local-function|). Example: >613 set patchexpr=s:MyPatchExpr()614 set patchexpr=<SID>SomePatchExpr()615Otherwise, the expression is evaluated in the context of the script where the616option was set, thus script-local items are available.617 618 619DIFF FUNCTION EXAMPLES *diff-func-examples*620 621Some examples for using the |diff()| function to compute the diff indices622between two Lists of strings are below.623>624 " some lines are changed625 :echo diff(['abc', 'def', 'ghi'], ['abx', 'rrr', 'xhi'], {'output': 'indices'})626 [{'from_idx': 0, 'from_count': 3, 'to_idx': 0, 'to_count': 3}]627 628 " few lines added at the beginning629 :echo diff(['ghi'], ['abc', 'def', 'ghi'], {'output': 'indices'})630 [{'from_idx': 0, 'from_count': 0, 'to_idx': 0, 'to_count': 2}]631 632 " few lines removed from the beginning633 :echo diff(['abc', 'def', 'ghi'], ['ghi'], {'output': 'indices'})634 [{'from_idx': 0, 'from_count': 2, 'to_idx': 0, 'to_count': 0}]635 636 " few lines added in the middle637 :echo diff(['abc', 'jkl'], ['abc', 'def', 'ghi', 'jkl'], {'output': 'indices'})638 [{'from_idx': 1, 'from_count': 0, 'to_idx': 1, 'to_count': 2}]639 640 " few lines removed in the middle641 :echo diff(['abc', 'def', 'ghi', 'jkl'], ['abc', 'jkl'], {'output': 'indices'})642 [{'from_idx': 1, 'from_count': 2, 'to_idx': 1, 'to_count': 0}]643 644 " few lines added at the end645 :echo diff(['abc'], ['abc', 'def', 'ghi'], {'output': 'indices'})646 [{'from_idx': 1, 'from_count': 0, 'to_idx': 1, 'to_count': 2}]647 648 " few lines removed from the end649 :echo diff(['abc', 'def', 'ghi'], ['abc'], {'output': 'indices'})650 [{'from_idx': 1, 'from_count': 2, 'to_idx': 1, 'to_count': 0}]651 652 " disjointed changes653 :echo diff(['ab', 'def', 'ghi', 'jkl'], ['abc', 'def', 'ghi', 'jk'], {'output': 'indices', 'context': 0})654 [{'from_idx': 0, 'from_count': 1, 'to_idx': 0, 'to_count': 1},655 {'from_idx': 3, 'from_count': 1, 'to_idx': 3, 'to_count': 1}]656 657 " disjointed changes with context length 1658 :echo diff(['ab', 'def', 'ghi', 'jkl'], ['abc', 'def', 'ghi', 'jk'], {'output': 'indices', 'context': 1})659 [{'from_idx': 0, 'from_count': 4, 'to_idx': 0, 'to_count': 4}]660 661<662 663 vim:tw=78:ts=8:noet:ft=help:norl:664 