我可以在将文件保存到 Vim 之前查看更改吗?

Posted

技术标签:

【中文标题】我可以在将文件保存到 Vim 之前查看更改吗?【英文标题】:Can I see changes before I save my file in Vim? 【发布时间】:2009-04-14 20:41:16 【问题描述】:

我使用 Vim。 我打开一个文件。我对其进行了编辑,我想在保存之前查看我编辑的内容。

如何在 Vim 中做到这一点?

【问题讨论】:

【参考方案1】:
:w !diff % -

【讨论】:

有没有办法用 vimdiff 做到这一点?我试过 :w !vimdiff % - 但没有成功。 有人能解释一下吗?我不明白发生了什么。我了解您正在向diff 发起攻击。 % 指当前打开的文件路径。为什么这一切都是:w 命令的参数?另外,- 是如何分配给工作缓冲区的内容的?在 vim 中是自动的,缓冲区的内容(或者缓冲区中的特定范围)被分配给 stdin 以用于 shell 命令? @NathanWallace:这是:w 的一个参数,因为我们正在将文件写入命令(在stdin)。在命令中,- 告诉它从stdin 读取。 如果你安装了 git,或者使用:w !git diff % - 获得彩色版本! @Dergachev 我在运行:w !git diff % - 时收到错误fatal: bad flag '-' used after filename【参考方案2】:

因为有人问了命令的解释

:w !diff % -

这是我尝试写一个更详细的答案:

我假设您正在使用安装了 catecho 的系统(例如几乎所有 GNU/Linux、Mac OS、BSD 和其他类 UNIX 系统)。

上述命令的作用如下:

    在vim中保存文件的语法是:

    :w <filename>
    

    vim中执行shell命令的语法是:

    :!<command>
    

    在vim发出的shell环境中%恰好指向当前文件名。您可以通过执行以下操作来验证这一点:

    :!echo %
    

    这应该输出文件名(或错误,如果 vim 运行时没有文件名)。

    使用cat我们也可以输出文件的内容:

    :!cat %
    

    这应该返回上次保存状态的文件内容,如果从未保存过,则返回错误。

    程序 diff 能够从标准输入 (stdin) 读取。它的手册页声明如下:

    [...] 如果 FILE 是“-”,则读取标准输入。 [...]

    在没有文件名的情况下执行保存命令,而是在其后面执行 shell 命令会导致 vim 将文件内容写入 shell 的标准输入,而不是将其保存在物理文件中。您可以通过执行来验证这一点

    :w !cat
    

    这应该总是打印文件的当前内容(本来应该被写入文件)。

把它放在一起(或 tl;dr):文件“保存”到标准输入,diff 以文件名和标准输入作为输入运行。

知道这一点也可以用 vimdiff 做类似的事情来比较文件 - 这只是你不想这样做的一个想法:

:w !cat > /tmp/tempFile && vimdiff /tmp/tempFile % && rm /tmp/tempFile

(然后使用:qall打开只读并关闭vimdiff)

【讨论】:

使用 vimdiff 的更明智的方法是创建一个包含以下 vim - -c ":vnew $1 |windo diffthis" 的 shell 脚本,使其可执行,将其保存在 PATH 中,例如 vimdiffWithStdin,然后与以下命令进行比较在 vim 中::w !vimdiffWithStdin % 更简单::w !vimdiff % /dev/stdin。我不知道windows是否存在类似的技巧。【参考方案3】:

http://vim.wikia.com/wiki/Diff_current_buffer_and_the_original_file

这是一个函数和命令,用于查看当前编辑的文件与其在文件系统中的未修改版本之间的差异。把它放在你的 vimrc 或插件目录中,打开一个文件,进行一些修改而不保存它们,然后执行:DiffSaved

function! s:DiffWithSaved()
  let filetype=&ft
  diffthis
  vnew | r # | normal! 1Gdd
  diffthis
  exe "setlocal bt=nofile bh=wipe nobl noswf ro ft=" . filetype
endfunction
com! DiffSaved call s:DiffWithSaved()

要退出差异视图,您可以使用:diffoff 命令。

下面是一个类似的函数,适应模仿'cvs diff'命令...

【讨论】:

@luc-hermitte 当您在无法轻易更改 .vimrc 的不断变化和大量的盒子上使用 vim 时,替代 :w !diff % - 不是更好吗? (只要他们安装了 diff。) Vim 不是最后希望的工具。在没有其他可用的情况下可以使用的一种。这是我的主要工作工具。 仅仅提供一个链接并不是真正的答案 Chaos 的回答是优越的,在 Tobias 的回答中,解释是完整的。 您能否添加一些内容而不仅仅是一个链接? SO指南...【参考方案4】:

我一直很喜欢diffchanges - 不错,简单,有效。

【讨论】:

这比投票率更高的选项好很多。这提供了切换它的能力。 @StevenLu - 嗯......你能做什么?无论如何,很高兴你喜欢它。我发现它比其他方法更实用。 我,我是第二个@Steven,你建议的 diffchanges 非常好。谢谢! 这也可以安装为来自同一开发者的插件:github.com/jmcantrell/vim-diffchanges 不错的插件,但它不会删除它之后创建的补丁?编辑:我的坏!确实如此。我以错误的方式使用它。我不得不使用:DiffChangesDiffToggle【参考方案5】:

来自 vimrc_example.vim:

" Convenient command to see the difference between the current buffer and the
" file it was loaded from, thus the changes you made.
if !exists(":DiffOrig")
  command DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis
          \ | wincmd p | diffthis
endif

【讨论】:

...如vimdoc.sourceforge.net/htmldoc/diff.html#:DiffOrig 所述。与w !diff % - 相比,它的优势在于它也适用于远程源(例如:vim sftp://example.com/foo.txt 我更喜欢这个,因为我们在 vim 缓冲区本身而不是终端中看到了差异 检查完差异后如何恢复正常? 您可以通过将命令替换为命令来摆脱 if 子句! (见:h E174) @NikoBellic 首先用 ':q' 关闭“旧”窗口(标记为暂存缓冲区)。在正常模式下,您可以通过按两次 ctrl-W 在窗口之间进行切换。然后你可以通过编写 :diffoff 来关闭 diff【参考方案6】:

git 支持以下命令

:w !git diff --no-index -- % -

通过将以下内容添加到您的 ~/.vimrc 将其映射到命令

command GitDiff execute "w !git diff --no-index -- % -"

现在执行:GitDiff 成为一个方便的小命令,可以在每次保存前快速显示差异。

【讨论】:

【参考方案7】:

获取以下内容并使用 :DIFF 命令

function! s:diff()
    let tmpa = tempname()
    let tmpb = tempname()
    earlier 100h
    exec 'w '.tmpa
    later 100h
    exec 'w '.tmpb
    update
    exec 'tabnew '.tmpa
    diffthis
    vert split
    exec 'edit '.tmpb
    diffthis
endfunction
command! -nargs=0 DIFF call <SID>diff()

【讨论】:

【参考方案8】:

不完全是你要找的东西,但SCMDiff.vim 真的很酷。一个按键,它会在源代码管理存储库中使用 head 修订版本突出显示您当前的文件。它适用于许多 SCMS。我将它与 perforce 一起使用。

【讨论】:

【参考方案9】:

这里有一个插件,根据不同的答案:https://github.com/gangleri/vim-diffsaved

它提供了:w !diff % -方法和更多涉及的diffthis方法。

除了undotree 也允许这样做,但还有更多(不同撤消检查点之间的差异)。类似于Gundo。

【讨论】:

【参考方案10】:

我可以推荐histwin 插件。

虽然它与文件的 当前保存 版本没有差异(就像其他答案一样),但它可以 vimdiff 自从您开始编辑后发生的变化,甚至 按顺序重播您的更改。如果您中间保存,差异就会显示出来。

此外,它还显示所有撤消历史分支的列表,并允许您在它们之间切换或区分。

PS:虽然插件不会在每次文件更改后自动跟踪编辑历史记录中的时刻,但您可以明确地“标记”保存文件的时刻,以便以后可以根据需要使用它进行 vimdiff。也许这可以自动化?

【讨论】:

【参考方案11】:

如果你想像 vimdiff 一样使用 vim 进行比较,你可以这样做:

编辑你的 .vimrc 并添加:

nmap <F8> :w !vim -M -R - -c ":vnew % \| windo diffthis"<CR><CR>

从那里您将看到您的更改,并可以使用qall 退出差异视图,就像在 vimdiff 中一样,在命令模式下按 F8。用你喜欢的任何键替换 F8。

编辑:添加 -M 以禁止任何修改,因为它不保存。

【讨论】:

这个命令开始为我工作,它并排显示差异。但是,一旦我尝试编辑任何内容,vim 窗口就会发疯。我开始输入,屏幕两侧的 vim 中的单词后面出现 bash 提示。所以它似乎显示了差异,但随后 vim 崩溃了。此外,我收到此错误Vim: Error reading input, exiting... 任何想法这里出了什么问题? @Trevor:我只能猜测问题出在哪里。像这样进行差异化时进行任何修改确实不值得。因此,我添加了“-M”参数以完全禁止它。对不起。【参考方案12】:

您可以使用以下命令使 vim 创建最后一个备份和原始备份:

:set backup
:set patchmode=.orig 

之后,您可以拆分打开它们:

:vsp %:p~ or :vsp %:.orig

然后从那里做:

:vimdiff in each buffer

如果你不喜欢吃剩菜但想要 vimdiff,你也可以这样做:

ggVGy    # copy the whole buffer
:vnew    # open a split
CTRL-W w # switch to it
shift-P  # paste at start

然后在每次拆分时执行 :diffthis

【讨论】:

【参考方案13】:

您刚刚编辑的更改 [buffer],即与上次保存的版本(在 工作目录ectory 中)不同的更改,这些可能与上次索引版本不同(Git)。我都映射了:

" Find diff inbetween currrent buffer and ... Alast index version vs Blast saved version in working directory
"  - Alast index version: the file as you last commited it
    " git diff to vimdiff against the index version of the file:
    nnoremap <leader>gd <Esc>:Gvdiff<CR><Esc>:echo "currentBuffer vs lastIndexVersion (last commited)"<CR>
"  - Blast saved version in working directory: the file you last :w,
"   not neccesary commited it (not commited for sure if it is in NO git project)
    " https://vim.fandom.com/wiki/Diff_current_buffer_and_the_original_file
    nnoremap <leader>gd2 <Esc>:DiffSaved<CR><Esc>:echo "currentBuffer vs lastSaved (not neccesary equal to last commited)"<CR>
    function! s:DiffWithSaved()
        let filetype=&ft
        diffthis
        vnew | r # | normal! 1Gdd
        diffthis
        exe "setlocal bt=nofile bh=wipe nobl noswf ro ft=" . filetype
    endfunction
    com! DiffSaved call s:DiffWithSaved()

vimdiff 与 Gdiff 的示例。

vimdiff: Gdiff: 提交更改时,您只会看到 Gdiff,可能或可能与 vimdiff 有相同的更改:

另外,方便vimdiff同名文件在其他路径:

    " vimdiff homonym file 
   nnoremap <leader>dh  <Esc>:vsplit %:p:h/../__/%:t <bar> :windo diffthis<Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left>
        "E.g."$ vim /path01/proj02_pg064/processorder.php
        ":vsplit %:p:h/../proj01_pg05/%:t | :windo diffthis

【讨论】:

一个人可以只创建一个执行的地图:如果可能,一个Gdiff,否则(例如不是一个Git项目)然后执行一个:vimdiff。与try-catch-endtry。但是这种方式:DiffWithSaved在一个Git项目中是缺少的。【参考方案14】:

按照上述建议我使用我非常喜欢的 git diff:

:w !git diff  % -

【讨论】:

以上是关于我可以在将文件保存到 Vim 之前查看更改吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在将上传的文件保存到目录之前重命名?

打开vim后怎样编写c/c++/java文件即编译运行 编写完后如何保存 保存路径在哪 路径是不是可更改

vim不保存退出

如何在将密码保存到用户模型 Django 之前对其进行加密?

我可以在保存之前检查下载的图像是不是损坏吗?

如何异步保存vim远程文件?