Interactive patch from external .diff file - linux

Is there a command or program for Linux that allows to patch the source code interactively, printing every chunk on the screen and waiting for acknowledgement before applying it to the file?
Something like git add -p, but taking the changes from another .diff file?

You can always write script in shell/ruby/python that reads that file line by line and prompts adding diff between file signatures.
It can accept name of diff file as parameter or you can put two hashes and make a patch inside a script.
More so you can call that script git-command-name, put it in your user/bin folder and git will recognise command-name as git command.
On the other hand (just an idea) can you manipulate creation of .diff ? Maybe you can use format-patch and on applying stop after every commit diff?

Although not interactive, another option is to manually edit the .diff file and remove any changes you don't want.
If you open a diff file in emacs and put the editor in diff-mode you can edit patches and emacs will try to update the hunk markers. (Emacs will open .diff files in diff-mode automatically.)
To update markers manually after making changes do C-c C-w to regenerate the hunk.
To apply hunks one by one do C-c C-a. To reverse-apply do C-u C-c C-a. You can also M-x diff-tell-file-name to apply them to a different file.
I found patch original patch.diff to be more reliable than patch < patch.diff and patch files created with diff -u to be easier to work with.
Information also documented here.
UPDATE [5.21.21]:
C-c C-s lets you split up hunks which is very useful for manually editing. Sometimes C-c C-w (diff-ignore-whitespace-hunk) does not do what you intended, so the safest bet is to split the hunks and let emacs update the headers automatically. This is especially useful when keeping lines unchanged; just split into a hunk and delete to remove the change.

Related

How do I accept both changes in vimdiff hunk?

When resolving merge conflicts, a fairly common pattern is that both I and another person have modified a list or some other section of code which commonly gets appended to. Such as:
global.registerFeature(fc);
global.registerFeature(fb);
global.registerFeature(fa);
<<<<<<<
global.registerFeature(aNewFeature);
=======
global.registerFeature(anotherNewFeature);
>>>>>>>
When I look at a merge conflict like this in vimdiff, vim gives me options for choosing one or the other. But what I want to do is apply both diffs. I usually just resort to editing the merged file directly (just deleting the merge markers); but is there an easier way to do this in vimdiff?
To combine changes from both the target and merge branches in a single command:
You can just delete the lines with Git conflict markers. The following two methods will delete all lines that start with:
<<<<<<<
=======
>>>>>>>
Method 1: Manually Entering and Executing a Command
:g/^<\{7}\|^|\{7}\|^=\{7}\|^>\{7}/d
Method 2: Implementing a User Defined Command
"Delete all Git conflict markers
"Creates the command :GremoveConflictMarkers
function! RemoveConflictMarkers() range
echom a:firstline.'-'.a:lastline
execute a:firstline.','.a:lastline . ' g/^<\{7}\|^|\{7}\|^=\{7}\|^>\{7}/d'
endfunction
"-range=% default is whole file
command! -range=% GremoveConflictMarkers <line1>,<line2>call RemoveConflictMarkers()
Vim diffget and diffput will only choose one branch or the other. So the only real solution other than the one given above is to manually yank and paste from both files into the working copy.
I'm not sure exactly what version control system you are using, but here is a guide for using Vim to do merges with Mercurial: https://www.mercurial-scm.org/wiki/MergingWithVim
You should be able to do something similar with whatever you are using, although keep in mind that vimdiff is not really meant for complicated merges, so it will be a bit kludgy. That same page links to the splice plugin, which is supposed to help with doing complex merges.

call vi from within vim (useful for svn commit)

I am using RedHat EL 5. I use gvim 7.1 compiled using GTK. What I want is to be able to do an svn commit (which uses vi/vim) from within gvim. Currently the only problem is that I get output which is garbled.
For example, calling :!vi produces this from within gvim:
[7;1H~
[8;1H~
[9;1H~
[10;1H~
[11;1H~
[12;1H~
[13;1H~
[14;1H~
[15;1H~
[16;1H~
[
17;1H~
[18;1H~
[19;1H~
[20;1H~
[21;1H~
[22;1H~
[23;1H~
[24;1H~
[25;1H~
[26;1H~
[27;1H~
[28;1H~
[29;1H~
[30;1H~
[31
;1H~
[32;1H~
[33;1H~
[34;1H~
[35;1H~
[36;1H~
[37;1H~
[38;1H~
[39;1H~
[15;42HVIM - Vi IMproved[17;43Hversion
7.0.237[18;39Hby Bram Moolenaar et al.[19;29HVim is open source and freely distributable[21;36HHe
lp poor children in Uganda![22;28Htype :help iccf<Enter> for information [24;28Htype :q<En
ter> to exit [25;28Htype :help<Enter> or <F1> for on-line help[26;28Htyp
e :help version7<Enter> for version info[1;1H
How do I configure vi/vim/gvim to solve this problem and thereby enable my svn commits to look proper when called from gvim.
Thank you,
Nachum
Don't use vi as the command, use gvim -f instead.
The problem is that vi (or vim in a console) requires a terminal that can do stuff like move the cursor around, etc. gvim's pty is a very basic ASCII-only terminal.
Plain old vim doesn't have this issue because it just pipes the subporcess directly to your terminal, hence all of the escape sequences still work.
You can use gvim -f instead, so that a new gvim window will pop up for your commit message. (the -f prevents backgrounding) This isn't exactly what you asked for (since you get a new window) but it's the closest you can get to what you asked for without adding full terminal support to vim.
I use VCSCommand, a nice VCS wrapper that works with SVN, GIT and others. :VCSCommit or ,cc opens a new window under the current one, lets you type your message and does the actual commit on write. Sure that's one more plugin in your setup but the conveniance may be worth it. It is for me.

Can I get a versioned recovery from a VIM swap file?

I have a file x.cpp which a while ago contained, say, "AAAAAAA".
I accidentally copied over it with another file containing, say, "BBBBBBB".
PANIC!
Hang on, let's look at .x.cpp.swp -- there's a load of binary junk then "BBBBBBB" then more junk then "AAAAAAA", so it looks like the swap file contains both versions. Hooray!
So, how do I recover the "AAAAAAAA" version? If I do vim -r then I get "BBBBBBB". Unfortunately, I can't recover-then-hit-undo. Is there an incantation? Can I hack the swap file?
Massive gratitude if you know a trick here.
No, but if you use Vim 7.3+ you can enable undofiles
To get started:
:he undo-persistence
That way you can navigate the undo tree even after a (involuntary) close of your editor.
So yes, the usual trick of going back in time, yanking, going forward in time, pasting will work even after the editor was restarted.
100g- (locate text, yank into register), 100g+ (locate destination, put register).

Use vimdiff to replace entire file?

I'm using vimdiff for a git merge. Is there a quick way to select 1 file to use, right now i'm just selecting everything from one buffer, replacing the $MERGE with that, and then saving. I guess I can macro that, but was wondering if there is a better way.
Thanks!
Several ways:
:%diffput
to do 'put' all changes from the current buffer to the 'other' buffer. This makes it easy with three-way diffs:
:%diffput OURS
The 'OURS' pattern will match uniquely on buffernames participating in the current diff
All the above can be done in reverse, substituting do or :diffget
You should take a look at Tim Pope's Fugitive plugin. It's a really usefull plugin.
When you run Gdiff in a conflicted file, 3 files are opened - target, merged and working copy. You would switch to the file you want to save, and execute Gwrite! to save that file.
There is a whole Vimcast explaining how to resolve merge conflicts with this plugin(And other 5 vimcasts explaining more about Fugitive.vim).
I think :%diffget LO or :%diffget RE is what you need.
Note: you need to run it in the MERGED part of vim windows. You can move cursor around the windows using Ctrl+w;←/↑/→/↓
Make sure that all participating buffers are in diff mode (see :h start-vimdiff on how to start diff mode)
Do v for VISUAL MODE in the Base
Select the whole file (press Page Down all the way)
Write : then diffget <buffer number/name> (: ls will list all buffers, generally in vimdiff they are from right to left 1-3 or 4 if 3 way diff)
Afterwards just : wqa and you are done
Alternatively, after step 0., one could do :%diffget <buffer number> to get all changes from the specified buffer as :diffget also accepts ranges. (See :% and :diffget.)
The reverse would also work: :%diffput <buffer> will send all changes to buffer number, making the two buffers have the same content.

How to automat editing of several files in Vim?

I have a multitude of files in each of which I want to, say, delete lines 1 through 55, add a comment leader (e.g., //) on lines 25 through 35, and then save the changes to a new file.
How can I do this automatically with Vim alone or together with the help of a Bash script?
Despite the fact that using ed or sed is a common practice1
in such cases, sometimes using Vim is much more convenient. Indeed,
instead of writing an ed-like script somewhat blindly, it is often
easier to first perform the desired manipulations with one of the
files interactively in Vim:
vim -w log.vim file1.txt
and then repeat it on the rest of the files:
for f in file*.txt; do vim -s log.vim "$f"; done
For your example use case, the log.vim file will likely have
contents similar to the following:
gg55dd:25,35s/^/\/\/ /
:w %_new
:q!
Note that to save the file with new name you should not type it
directly, but rather use the % substitution, as shown above—otherwise
all the modifications of all the following files will be saved to the
same file, overwriting its contents every time. Alternatively, you can
duplicate the files beforehand and then edit the copies in place
(saving each of them by simply issuing the :w command without
arguments).
The advantage of this approach is that you can make all of the changes
interactively, ensuring that you are getting the intended result at
least on one of the files, before the edits are performed for the rest
of them.
1 Of course, you can use Vim in an ed-like fashion, too:
for f in file*.txt; do vim -c '1,55d|25,35s/^/\/\/ /|w! '"${f}_new"'|q!' "$f"; done
You can accomplish this elegantly with ed, the unix line editor, the ancestor of vi.
fix_file () {
ed -s "$1" <<-'EOF'
1,55d
25,35s_.*_// &_
wq
EOF
}
Now, for each file F you need, just execute fix_file F.

Resources