Bisakah saya melihat perubahan sebelum saya menyimpan file saya di Vim?

135

Saya menggunakan Vim. Saya membuka file. Saya mengeditnya dan saya ingin melihat apa yang telah saya edit sebelum menyimpannya.

Bagaimana saya bisa melakukan ini di Vim?

teerapap
sumber

Jawaban:

57

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

Berikut adalah fungsi dan perintah untuk melihat perbedaan antara file yang saat ini diedit dan versi yang tidak dimodifikasi dalam sistem file. Cukup letakkan ini di vimrc Anda atau di direktori plugin, buka file, buat beberapa modifikasi tanpa menyimpannya, dan lakukan :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()

Untuk keluar dari tampilan diff Anda dapat menggunakan :diffoffperintah.

Di bawah ini adalah fungsi yang serupa, diadaptasi untuk meniru 'cvs diff'perintah ...

Bill Lynch
sumber
7
@ luc-hermitte Bukankah alternatif :w !diff % -unggul ketika Anda menggunakan vim pada kotak yang selalu berubah dan besar yang Anda tidak dapat dengan mudah mengubah .vimrc untuk? (Asalkan mereka memiliki diff diinstal.)
thomanski
1
Vim bukan alat harapan terakhir. Yang akan bekerja ketika tidak ada lagi yang tersedia. Ini adalah alat kerja utama saya.
Luc Hermitte
12
Hanya memasok tautan bukanlah jawaban
Skurpi
3
Jawaban Chaos lebih unggul dan dalam jawaban Tobias, penjelasannya lengkap.
Avi Cohen
1
Bisakah Anda menambahkan beberapa konten, bukan hanya sebuah tautan? SO pedoman ...
Błażej Michalik
160
:w !diff % -
kekacauan
sumber
4
Apakah ada cara untuk melakukan ini dengan vimdiff? Saya mencoba: w! Vimdiff% - tetapi tidak berhasil.
Joe J
14
Adakah yang bisa menjelaskannya? Saya tidak mengerti apa yang terjadi. Saya mengerti Anda tidak setuju diff. %merujuk ke filepath yang saat ini terbuka. Mengapa semua ini merupakan argumen untuk :wperintah? Juga, bagaimana cara -ditugaskan ke konten buffer yang berfungsi? Apakah itu otomatis dalam vim, bahwa isi buffer (atau mungkin rentang tertentu dalam buffer) ditugaskan untuk stdin untuk perintah shell?
Nathan Wallace
9
@NathanWallace: Ini argumen :wkarena kami sedang menulis file ke perintah (on stdin). Dalam perintah, -suruh dibaca dari stdin.
kekacauan
14
Atau gunakan :w !git diff % -untuk versi berwarna, jika Anda sudah menginstal git!
Dergachev
5
@Ergachev saya mendapatkan kesalahan fatal: bad flag '-' used after filenameketika saya menjalankan :w !git diff % -.
Grayscale
100

Karena beberapa orang bertanya tentang penjelasan untuk perintah itu

:w !diff % -

Inilah upaya saya untuk menulis jawaban yang lebih terperinci:

Saya berasumsi bahwa Anda bekerja pada sistem dengan catdan echodiinstal (misalnya, hampir semua GNU / Linux, Mac OS, BSD dan sistem seperti UNIX lainnya).

Perintah di atas berfungsi sebagai berikut:

  1. Sintaks untuk menyimpan file di vim adalah:

    :w <filename>
    
  2. Sintaks untuk menjalankan perintah shell di vim adalah:

    :!<command>
    
  3. Di dalam lingkungan shell yang dikeluarkan oleh vim %kebetulan menunjuk ke nama file saat ini. Anda dapat memverifikasi ini dengan menjalankan yang berikut:

    :!echo %
    

    Ini akan menampilkan nama file (atau kesalahan, jika vim dijalankan tanpa nama file).

    Menggunakan cat, kami juga dapat menampilkan konten file:

    :!cat %
    

    Ini harus mengembalikan konten file dalam keadaan terakhir disimpan atau kesalahan jika tidak pernah disimpan.

  4. Program diff dapat membaca dari input standar (stdin). Halaman manualnya menyatakan sebagai berikut:

    [...] Jika FILE adalah '-', baca input standar. [...]

  5. Menjalankan perintah save tanpa nama file tetapi perintah shell di belakangnya menyebabkan vim untuk menulis konten file ke stdin dari shell bukannya menyimpannya dalam file fisik. Anda dapat memverifikasi ini dengan mengeksekusi

    :w !cat
    

    Ini harus selalu mencetak file konten saat ini (yang seharusnya ditulis ke file).

Menyatukannya (atau tl; dr): File "disimpan" ke stdin, diff dijalankan dengan nama file dan stdin sebagai input.

Mengetahui yang ini juga bisa membandingkan file dengan vimdiff melakukan sesuatu seperti ini - ini hanya ide yang tidak ingin Anda lakukan:

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

(Kemudian buka hanya baca dan tutup vimdiff menggunakan :qall)

Tobias Heinicke
sumber
Pendekatan yang lebih waras untuk menggunakan vimdiff adalah membuat skrip shell yang berisi yang berikut ini vim - -c ":vnew $1 |windo diffthis", menjadikannya dapat dieksekusi, menyimpannya di PATH sebagai contoh vimdiffWithStdindan kemudian membandingkan dengan perintah berikut dalam vim::w !vimdiffWithStdin %
Tobias Heinicke
Bahkan lebih sederhana: :w !vimdiff % /dev/stdin. Saya tidak tahu apakah ada trik serupa untuk windows.
deft_code
12

Saya selalu suka perubahan - bagus, sederhana, bekerja.

Benteng
sumber
Ini bekerja jauh lebih baik daripada opsi yang lebih tinggi. Ini memberikan kemampuan untuk mengubahnya.
Steven Lu
1
@ SevenLu - Meh ... apa yang bisa kamu lakukan? Bagaimanapun, senang Anda menyukainya. Saya merasa lebih praktis daripada pendekatan lain.
Benteng
Saya, saya melakukan @Steven kedua, perubahan yang Anda sarankan sangat baik. Terima kasih!
AS
Ini juga dapat diinstal sebagai plugin dari pengembang yang sama: github.com/jmcantrell/vim-diffchanges
Sumanth Lingappa
plugin yang bagus, tetapi tidak menghapus tambalan yang dibuatnya setelah itu? Sunting: Buruk saya! Itu benar. Saya menggunakannya dengan cara yang salah. Saya harus menggunakan :DiffChangesDiffToggle.
aderchox
10

dari 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
0x89
sumber
... seperti yang didokumentasikan di vimdoc.sourceforge.net/htmldoc/diff.html#:DiffOrig . Keuntungan lebih dari ini w !diff % -adalah bahwa ia bekerja sumber lebih jauh juga (misalnya: vim sftp://example.com/foo.txt)
Lekensteyn
1
Saya suka ini lebih baik karena kita melihat perbedaan tepat di dalam buffer vim itu sendiri daripada di terminal
Niko Bellic
Bagaimana Anda kembali normal setelah Anda selesai memeriksa perbedaannya?
Niko Bellic
Anda dapat menyingkirkan klausa if dengan mengganti perintah dengan perintah! (lihat: h E174)
elig
@NikoBellic Pertama tutup jendela "lama" (ditandai sebagai penyangga awal) dengan ': q'. Anda dapat mengubah antar windows dengan mengetuk ctrl-W dua kali saat dalam mode normal. Kemudian Anda dapat mematikan diff dengan menulis: diffoff
brunch875
2

Sumber berikut ini dan gunakan: perintah 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()
Mykola Golubyev
sumber
2

Tidak persis apa yang Anda cari tetapi SCMDiff.vim sangat keren. Satu penekanan tombol, dan ini akan menyoroti file Anda saat ini dengan revisi kepala di repo kontrol sumber. Ini dimaksudkan untuk bekerja dengan banyak SCMS. Saya menggunakannya dengan terpaksa.

prestomation
sumber
2

Ada sebuah plugin, berdasarkan jawaban yang berbeda di sini: https://github.com/gangleri/vim-diffsaved

Ini memberikan :w !diff % -metode dan yang lebih terlibat diffthis.

Terlepas dari undotree memungkinkan ini juga, tetapi juga lebih banyak (berbeda antara pos pemeriksaan yang berbeda). Mirip dengan Gundo .

kebiru-biruan
sumber
1

Saya dapat merekomendasikan plugin histwin .

Meskipun tidak berbeda dengan versi file yang disimpan saat ini (seperti jawaban lainnya), ia dapat mengubah perubahan sejak Anda mulai mengedit , dan bahkan memutar ulang perubahan Anda secara berurutan. Perbedaannya terlihat jika Anda menyimpan perantara.

Selain itu, ini menampilkan daftar semua membatalkan cabang sejarah dan memungkinkan Anda untuk beralih atau berbeda di antara mereka.

PS: Walaupun plugin tidak secara otomatis melacak momen dalam riwayat edit sejak setiap perubahan file, Anda dapat secara eksplisit "menandai" saat ketika Anda menyimpan file tersebut sehingga nantinya Anda dapat melakukannya, jika Anda menginginkannya. Mungkin ini bisa otomatis?

catchmeifyoutry
sumber
1

Jika Anda ingin menggunakan vim untuk perbandingan seperti di vimdiff, Anda dapat melakukan sesuatu seperti ini:

Edit .vimrc Anda dan tambahkan:

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

Dari sana, Anda akan melihat perubahan Anda dan dapat keluar dari tampilan diff menggunakan qallseperti di vimdiff dengan menekan F8 dalam mode perintah. Ganti F8 dengan tombol apa saja yang Anda suka.

Sunting: Ditambahkan -M untuk melarang modifikasi apa pun, karena tidak menyimpan.

Tobias Heinicke
sumber
Perintah ini mulai bekerja untuk saya, ini menunjukkan saya sisi yang berdampingan. Namun, segera setelah saya mencoba dan mengedit apa pun jendela vim menjadi gila. Saya mulai mengetik dan saya mendapatkan prompt bash di belakang kata-kata dalam vim di kedua sisi layar. Jadi sepertinya menampilkan diff, tetapi kemudian vim crash. Selain itu, saya mendapatkan kesalahan ini Vim: Error reading input, exiting...setiap ide apa yang salah di sini?
Trevor
@ Trevor: Saya hanya bisa menebak apa masalahnya. Memang tidak menghemat untuk melakukan modifikasi saat berbeda seperti ini. Karenanya saya telah menambahkan parameter "-M" untuk melarangnya sama sekali. Maaf.
Tobias Heinicke
1

git mendukung perintah berikut

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

petakan ke perintah dengan menambahkan berikut ini ke ~ / .vimrc Anda

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

Sekarang mengeksekusi :GitDiffmenjadi perintah kecil yang berguna untuk dengan cepat menampilkan diff sebelum setiap save.

CyclicUniverse
sumber
0

Anda dapat membuat vim membuat cadangan terakhir dan cadangan asli dengan:

:set backup
:set patchmode=.orig 

Setelah itu, Anda dapat membukanya secara terpisah:

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

Dan dari sana lakukan:

:vimdiff in each buffer

Jika Anda mati karena tidak ada sisa makanan tetapi ingin vimdiff, Anda juga dapat melakukan:

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

dan kemudian lakukan: bedakan ini pada setiap split

chipfall
sumber
0

Perubahan yang baru saja Anda edit [ buffer ], yaitu yang berbeda dari versi yang disimpan terakhir (dalam direktori kerja ), ini mungkin berbeda dengan versi indeks terakhir ( Git ). Saya memetakan keduanya:

" 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()

Contoh vimdiff vs Gdiff.

  • vimdiff: : vimdiff
  • Gdiff: Gdiff Melakukan perubahan, Anda hanya melihat Gdiff, apa yang mungkin, atau mungkin memiliki perubahan yang sama dengan vimdiff: melakukan perubahan, Anda hanya melihat Gdiff, apa yang mungkin, atau mungkin TIDAK memiliki perubahan yang sama dengan vimdiff

Selanjutnya, untuk mempermudah vimdifffile homonim di jalur lain:

    " 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
Xopi García
sumber
1
Kita bisa membuat 1 peta yang mengeksekusi: a Gdiffjika memungkinkan dan sebaliknya (mis. Bukan proyek Git) kemudian melakukan a :vimdiff. Dengan try-catch-endtry. Namun cara ini :DiffWithSaveddalam proyek Git kurang.
Xopi García
-2

Ikuti saran di atas saya gunakan git diff yang sangat saya sukai:

:w !git diff  % -
Alex
sumber