ฉันจะเห็นการเปลี่ยนแปลงก่อนบันทึกไฟล์ใน Vim ได้หรือไม่


138

ฉันใช้ Vim ฉันเปิดไฟล์ ฉันแก้ไขและฉันต้องการดูสิ่งที่ฉันแก้ไขก่อนที่จะบันทึก

ฉันจะทำสิ่งนี้ใน Vim ได้อย่างไร?

คำตอบ:


59

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 % -ดีกว่าเมื่อคุณใช้ vim บนกล่องที่เปลี่ยนแปลงตลอดเวลาและมีจำนวนมากที่คุณไม่สามารถเปลี่ยน. vimrc ได้อย่างง่ายดาย? (หากมีการติดตั้งต่างกัน)
thomanski

1
กลุ่มไม่ใช่เครื่องมือของความหวังสุดท้าย สิ่งที่จะทำงานเมื่อไม่มีสิ่งอื่นใด เป็นเครื่องมือหลักในการทำงานของฉัน
Luc Hermitte

12
การส่งลิงค์ไม่ใช่คำตอบจริงๆ
Skurpi

3
คำตอบของ Chaos นั้นเหนือกว่าและในคำตอบของ Tobias คำอธิบายนั้นสมบูรณ์
Avi Cohen

1
คุณช่วยเพิ่มเนื้อหาแทนลิงก์ได้ไหม แนวทางปฏิบัติ ...
Błażej Michalik

166
:w !diff % -

4
มีวิธีทำ vimdiff ไหม ฉันพยายาม: w! vimdiff% - แต่ไม่ประสบความสำเร็จ
Joe J

15
ใครช่วยอธิบายที ฉันไม่เข้าใจว่าเกิดอะไรขึ้น diffเราเข้าใจว่าคุณปลอกกระสุนออกไป %หมายถึง filepath ที่เปิดอยู่ในปัจจุบัน เหตุใดทั้งหมดนี้จึงเป็นการโต้แย้ง:wคำสั่ง นอกจากนี้จะ-กำหนดให้กับเนื้อหาของบัฟเฟอร์การทำงานได้อย่างไร? เป็นแบบกลุ่มโดยอัตโนมัติหรือไม่ที่เนื้อหาของบัฟเฟอร์ (หรืออาจเป็นช่วงเฉพาะในบัฟเฟอร์) ได้รับการกำหนดให้กับ stdin สำหรับคำสั่งเชลล์?
Nathan Wallace

10
@NathanWallace: เป็นข้อโต้แย้ง:wเนื่องจากเรากำลังเขียนไฟล์ไปยังคำสั่ง (on stdin) ในคำสั่งที่บอกว่ามันอ่านจาก- stdin
วุ่นวาย

15
หรือใช้:w !git diff % -สำหรับเวอร์ชัน colorized หากคุณติดตั้งคอมไพล์แล้ว!
Dergachev

5
@Dergachev ฉันได้รับข้อผิดพลาดเมื่อฉันทำงานfatal: bad flag '-' used after filename :w !git diff % -
Grayscale

101

เพราะบางคนถามเกี่ยวกับคำอธิบายสำหรับคำสั่ง

:w !diff % -

นี่คือความพยายามของฉันในการเขียนคำตอบโดยละเอียด:

ฉันสมมติว่าคุณกำลังทำงานกับระบบที่มีcatและechoติดตั้ง (เช่นเกือบทุกระบบ GNU / Linux, Mac OS, BSD และระบบอื่น ๆ ที่คล้าย UNIX)

คำสั่งดังกล่าวทำงานดังนี้:

  1. ไวยากรณ์สำหรับการบันทึกไฟล์ในกลุ่มคือ:

    :w <filename>
    
  2. ไวยากรณ์สำหรับการเรียกใช้คำสั่งเชลล์ในกลุ่มคือ:

    :!<command>
    
  3. ภายในสภาพแวดล้อมเชลล์ที่ออกโดยกลุ่ม%จะชี้ไปที่ชื่อไฟล์ปัจจุบัน คุณสามารถตรวจสอบได้โดยดำเนินการดังต่อไปนี้:

    :!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จากนั้นเปรียบเทียบกับคำสั่งต่อไปนี้ในกลุ่ม::w !vimdiffWithStdin %
Tobias Heinicke

ง่ายยิ่งขึ้น: :w !vimdiff % /dev/stdin. ฉันไม่รู้ว่ามีเคล็ดลับที่คล้ายกันสำหรับ windows หรือไม่
deft_code

12

ฉันชอบความแตกต่างเสมอ- ดีเรียบง่ายใช้งานได้


วิธีนี้ใช้งานได้ดีกว่าตัวเลือกที่มีการโหวตสูงมากขึ้น ซึ่งจะช่วยให้สามารถสลับได้
Steven Lu

1
@StevenLu - เม ... ทำอะไรได้บ้าง? ไม่ว่าในกรณีใด ๆ ดีใจที่คุณชอบ ฉันพบว่ามันใช้งานได้จริงมากกว่าวิธีอื่น ๆ
Rook

ฉันฉันทำที่สอง @Steven การเปลี่ยนแปลงที่คุณแนะนำนั้นยอดเยี่ยมมาก ขอบคุณ!
AS

นอกจากนี้ยังสามารถติดตั้งเป็นปลั๊กอินจากผู้พัฒนารายเดียวกัน: 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

1
ฉันชอบสิ่งนี้ดีกว่าเพราะเราเห็นความแตกต่างภายใน vim buffer เองแทนที่จะอยู่ในเทอร์มินัล
Niko Bellic

คุณจะกลับสู่ภาวะปกติได้อย่างไรเมื่อคุณตรวจสอบความแตกต่างเสร็จแล้ว?
Niko Bellic

คุณสามารถกำจัด if clause ได้โดยแทนที่คำสั่งด้วย command! (ดู: h E174)
ออก

@NikoBellic ก่อนอื่นให้ปิดหน้าต่าง "old" (ทำเครื่องหมายเป็น scratch buffer) ด้วย ": q" คุณสามารถเปลี่ยนระหว่างหน้าต่างได้โดยแตะ ctrl-W สองครั้งขณะอยู่ในโหมดปกติ จากนั้นคุณสามารถปิดความแตกต่างโดยเขียนว่า: 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นั้นยอดเยี่ยมจริงๆ กดปุ่มเดียวและไฮไลต์ไฟล์ปัจจุบันของคุณต่างกันด้วยการแก้ไขส่วนหัวใน repo การควบคุมแหล่งที่มา หมายถึงการทำงานกับ SCMS จำนวนมาก ฉันใช้มันกับ perforce


2

มีปลั๊กอินตามคำตอบต่างๆที่นี่: https://github.com/gangleri/vim-diffsaved

จะให้:w !diff % -วิธีการและอีกdiffthisวิธีหนึ่งที่เกี่ยวข้อง

นอกจากundotreeนั้นยังอนุญาตให้ทำสิ่งนี้ได้เช่นกัน แต่ยังมีอีกมากมาย (แตกต่างระหว่างจุดตรวจเลิกทำที่แตกต่างกัน) คล้ายกับGundo


1

ฉันสามารถแนะนำปลั๊กอินhistwin

แม้ว่าจะไม่แตกต่างจากไฟล์เวอร์ชันที่บันทึกไว้ในปัจจุบัน (เช่นคำตอบอื่น ๆ ) แต่ก็สามารถเปลี่ยนแปลงได้เป็นกลุ่มตั้งแต่คุณเริ่มแก้ไขและยังเล่นซ้ำการเปลี่ยนแปลงตามลำดับ ความแตกต่างแสดงให้เห็นว่าคุณบันทึกกลางหรือไม่

นอกจากนี้ยังแสดงรายการสาขาประวัติการเลิกทำทั้งหมดและช่วยให้คุณสามารถสลับหรือแตกต่างกันได้

PS: แม้ว่าปลั๊กอินจะไม่ติดตามช่วงเวลาในประวัติการแก้ไขโดยอัตโนมัติเนื่องจากทุกไฟล์มีการเปลี่ยนแปลง แต่คุณสามารถ "แท็ก" อย่างชัดเจนในช่วงเวลาที่คุณบันทึกไฟล์เพื่อที่คุณจะสามารถ vimdiff กับมันในภายหลังได้หากคุณต้องการ บางทีอาจเป็นไปโดยอัตโนมัติ?


1

หากคุณต้องการใช้ vim เพื่อเปรียบเทียบเช่นใน vimdiff คุณสามารถทำสิ่งนี้ได้:

แก้ไข. vimrc ของคุณและเพิ่ม:

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

จากตรงนั้นคุณจะเห็นการเปลี่ยนแปลงของคุณและสามารถออกจากมุมมองที่แตกต่างได้โดยใช้qalllike ใน vimdiff โดยกด F8 ในโหมดคำสั่ง แทนที่ F8 ด้วยคีย์ที่คุณต้องการ

แก้ไข: เพิ่ม -M เพื่อไม่อนุญาตให้แก้ไขใด ๆ เนื่องจากไม่ได้บันทึก


คำสั่งนี้เริ่มทำงานสำหรับฉันมันแสดงให้ฉันเห็นความแตกต่างเคียงข้างกัน อย่างไรก็ตามทันทีที่ฉันพยายามแก้ไขอะไรก็ตามหน้าต่างกลุ่มก็จะบ้าคลั่ง ฉันเริ่มพิมพ์และได้รับข้อความทุบหลังคำเป็นกลุ่มที่ด้านใดด้านหนึ่งของหน้าจอ ดูเหมือนว่าจะแสดงความแตกต่าง แต่แล้วกลุ่มก็ล่ม นอกจากนี้ฉันได้รับข้อผิดพลาดนี้Vim: Error reading input, exiting...ว่าเกิดอะไรขึ้นที่นี่?
Trevor

@Trevor: ฉันเดาได้แค่ว่าปัญหาคืออะไร แน่นอนมันไม่ได้บันทึกที่จะทำการแก้ไขใด ๆ ในขณะที่แตกต่างกันเช่นนี้ ดังนั้นฉันจึงเพิ่มพารามิเตอร์ "-M" เพื่อไม่อนุญาตทั้งหมด ขออภัย.
Tobias Heinicke

1

git รองรับคำสั่งต่อไปนี้

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

แมปกับคำสั่งโดยเพิ่มสิ่งต่อไปนี้ใน ~ / .vimrc ของคุณ

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

ตอนนี้การเรียกใช้งาน:GitDiffกลายเป็นคำสั่งเล็ก ๆ ที่มีประโยชน์ในการแสดงความแตกต่างอย่างรวดเร็วก่อนบันทึกแต่ละครั้ง


0

คุณสามารถสร้างกลุ่มสร้างการสำรองข้อมูลล่าสุดและการสำรองข้อมูลต้นฉบับด้วย:

: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

แล้วทำ: แตกต่างกันในแต่ละแยก


0

การเปลี่ยนแปลงที่คุณเพิ่งแก้ไข [ บัฟเฟอร์ ] นั่นคือการเปลี่ยนแปลงที่แตกต่างจากเวอร์ชันที่บันทึกไว้ล่าสุด (ในการทำงานของ dir ectory) สิ่งเหล่านี้อาจแตกต่างกับเวอร์ชันดัชนีล่าสุด ( 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 vs Gdiff

  • vimdiff: : vimdiff
  • Gdiff: Gdiff ยอมรับการเปลี่ยนแปลงคุณจะเห็นเฉพาะ Gdiff สิ่งที่อาจมีหรืออาจมีการเปลี่ยนแปลงเช่นเดียวกับ 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 ขาด
Xopi García

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.