Vimにファイルを保存する前に変更を確認できますか?


135

私はVimを使用しています。ファイルを開きます。編集して、保存する前に編集した内容を確認したいと思います。

Vimでこれを行うにはどうすればよいですか?

回答:


57

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'コマンドを模倣するように適合された同様の関数です...


7
@ luc-hermitte :w !diff % -.vimrcを簡単に変更できない、絶え間なく変化する多数のボックスでvimを使用している場合、代替の優れた方法ではありませんか?(diffがインストールされている場合)
thomanski 2012年

1
Vimは最後の希望のツールではありません。他に何も利用できないときに機能するもの。それは私の主な作業ツールです。
Luc Hermitte、2012年

12
リンクを提供するだけでは実際の答えは得られません
Skurpi '20

3
カオスの答えは優れており、トビアスの答えでは、説明は完全です。
Avi Cohen

1
リンクだけでなく、コンテンツを追加していただけますか?SOガイドライン...
BłażejMichalik

160
:w !diff % -

4
vimdiffでこれを行う方法はありますか?私は:w!vimdiff%を試しましたが、成功しませんでした。
ジョーJ

14
誰かがそれを説明できますか?何が起こっているのかわかりません。あなたがに砲撃を浴びていると聞きましたdiff%現在開いているファイルパスを参照します。なぜこれが:wコマンドの引数なのですか?また、どのように-作業バッファーの内容に割り当てられますか?それはvimで自動ですか、バッファーの内容(またはおそらくバッファー内の特定の範囲)がシェルコマンドの標準入力に割り当てられますか?
Nathan Wallace

9
@NathanWallace::wコマンド(stdin)にファイルを書き込んでいるため、これは引数です。コマンドで、-から読み取るように指示しますstdin
2013年

14
または:w !git diff % -、gitがインストールされている場合は、カラーバージョンに使用します。
Dergachev 2015年

5
@Dergachev fatal: bad flag '-' used after filename実行するとエラーが発生します:w !git diff % -
グレースケール2018

100

一部の人々はコマンドの説明について尋ねたので

:w !diff % -

これが、より詳細な回答を書くための私の試みです。

私はあなたがシステム上で作業していると仮定していますcatし、echo(例えば、ほぼすべてのGNU / Linuxの、マックOS、BSDや他のUNIXライクなシステム)をインストール。

上記のコマンドは次のように機能します。

  1. vimでファイルを保存するための構文は次のとおりです。

    :w <filename>
    
  2. vimでシェルコマンドを実行するための構文は次のとおりです。

    :!<command>
    
  3. vimによって発行されたシェル環境内では、%たまたま現在のファイル名を指しています。これを確認するには、次のコマンドを実行します。

    :!echo %
    

    これにより、ファイル名(または、ファイル名なしでvimが実行された場合はエラー)が出力されます。

    catを使用して、ファイルの内容を出力することもできます。

    :!cat %
    

    これは、最後に保存された状態のファイルコンテンツ、または一度も保存されていない場合はエラーを返します。

  4. プログラムdiffは標準入力(stdin)から読み取ることができます。マニュアルページには次のように記載されています。

    [...] FILEが '-'の場合、標準入力を読み取ります。[...]

  5. ファイル名なしでsaveコマンドを実行すると、その背後でシェルコマンドが実行されるため、vimはファイルの内容を物理ファイルに保存するのではなく、シェルのstdinに書き込みます。これを確認するには、

    :w !cat
    

    これにより、常にファイルの現在のコンテンツが印刷されます(代わりにファイルに書き込まれます)。

まとめる(またはtl; dr):ファイルはstdinに「保存」され、diffはファイル名とstdinを入力として実行されます。

これを知っていれば、ファイルをvimdiffと比較して次のようなことを行うこともできます。これは、これを実行したくないアイデアにすぎません。

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

(次に、読み取り専用で開き、vimdiffを閉じます:qall


使用はvimdiffに対するより健全なアプローチは、以下を含有するシェルスクリプトを作成することになるvim - -c ":vnew $1 |windo diffthis"例えばようPATHにそれを保存し、それを実行作製vimdiffWithStdinし、次いでVIMで次のコマンドと比較する::w !vimdiffWithStdin %
トビアスHeinicke

さらにシンプル::w !vimdiff % /dev/stdin。Windowsにも同様のトリックが存在するかどうかはわかりません。
deft_code 2015年

12

私はいつもdiffchangesが好きです -素晴らしく、シンプルで、うまくいきます。


これは、より高く支持されているオプションよりも、LOTに優れています。これにより、それを切り替えることができます。
Steven Lu

1
@StevenLu-えっと...何ができる?とにかく、あなたがそれを気に入ってうれしいです。他のアプローチよりも実用的だと思います。
2013年

私、私は@Stevenの2番目を行います。提案されたdiffchangesは素晴らしいです。ありがとう!
2016

これは同じ開発者からのプラグインとしてインストールすることもできます:github.com/jmcantrell/vim-diffchanges
Sumanth Lingappa

素敵なプラグインですが、後で作成するパッチは削除されませんか?編集:私の悪い!します。私はそれを間違った方法で使用していました。私は使用しなければなりませんでした:DiffChangesDiffToggle
aderchox

10

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
Lekensteyn '27

1
ターミナルではなくvimバッファー自体の内部に違いが見られるので、私はこのほうが好きです
Niko Bellic

違いを調べ終わったら、どうやって通常に戻りますか?
Niko Bellic 2017

commandをcommandで置き換えることにより、if句を取り除くことができます!(:h E174を参照)
elig

@NikoBellic最初に、「:q」で「古い」ウィンドウ(スクラッチバッファーとしてマークされている)を閉じます。通常モードでctrl-Wを2回タップすると、ウィンドウを切り替えることができます。次に、:diffoff
brunch875

2

以下をソースにして: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()

2

あなたが探しているものと完全に一致しているわけではありませんが、SCMDiff.vimは本当にクールです。キーを1回押すと、ソース管理リポジトリの現在のファイルの最新リビジョンが差分ハイライト表示されます。多くのSCMSで動作することを意味します。perforceで使用します。


2

ここにさまざまな答えに基づいたプラグインがあります:https : //github.com/gangleri/vim-diffsaved

それは:w !diff % -方法とより複雑なdiffthisものを提供します。

このundotreeとは別に、これも可能ですが、はるかに多くのことが可能です(さまざまなundoチェックポイント間の差異)。Gundoに似ています。


1

histwinプラグインをお勧めします。

他の回答と同様に、現在保存されているファイルのバージョンとは異なりますが、編集を開始してからの変更vimdiffしたり、変更を順番に再生したりすることもできます。違いは、途中で保存するかどうかを示します。

さらに、すべての元に戻す履歴ブランチのリストを表示し、それらを切り替えたり比較したりできます。

PS:プラグインはすべてのファイル変更以降、編集履歴の瞬間を自動的に追跡しませんが、必要に応じて、後でファイルをvimdiffできるように、ファイルを保存する瞬間に明示的に「タグ付け」できます。多分これは自動化できますか?


1

vimdiffのように比較にvimを使用したい場合は、次のようにすることができます。

.vimrcを編集して、以下を追加します。

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

そこから変更qallが表示され、コマンドモードでF8を押すことにより、vimdiffのようにdiffビューを終了できます。F8を任意のキーに置き換えます。

編集:保存されていないため、変更を許可しない-Mが追加されました。


このコマンドが機能し始め、差分を並べて表示します。しかし、何かを編集しようとすると、vimウィンドウが狂ってしまいます。入力を開始すると、画面の両側にあるvimの単語の後ろにbashプロンプトが表示されます。そのため、差分を表示しているように見えますが、vimがクラッシュします。さらに、このエラーが発生Vim: Error reading input, exiting...しましたが、ここで何が問題になっていますか?
Trevor

@Trevor:私は問題が何であるかを推測することしかできませんでした。このようにdiffしている間、変更を加えることは確かに保存されません。したがって、「-M」パラメータを追加して、完全に許可しないようにしました。ごめんなさい。
Tobias Heinicke 2014年

1

gitは次のコマンドをサポートしています

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

〜/ .vimrcに以下を追加してコマンドにマッピングします

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

これで、実行:GitDiffは便利な小さなコマンドになり、保存する前に差分をすばやく表示できます。


0

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を実行します


0

編集した変更[ buffer ]、つまり最後に保存されたバージョン(作業ディレクトリ内)と異なる変更は、最後のインデックスバージョン(Git)と異なる場合があります。私は両方をマッピングしました:

" Find diff inbetween currrent buffer and ... A{last index version} vs B{last saved version in working directory}
"  - A{last 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>
"  - B{last 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: :vimdiff
  • Gdiff: グディフ 変更をコミットすると、Gmdiffのみが表示されます。vimdiffと同じか、または同じように変更される可能性があります。 変更をコミットすると、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

1
実行する1つのマップを作成することもできます。Gdiff可能であれば、(Gitプロジェクトではないなどの)それからを実行し:vimdiffます。とtry-catch-endtry。しかし:DiffWithSaved、Gitプロジェクトではこの方法が欠けています。
XopiGarcía

-2

上記に従って、私がとても好きなgit diffを使用することを提案します:

:w !git diff  % -
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.