Ignore Emacs auto-generated files in a diff - emacs

How do I make diff ignore temporary files like foo.c~? Is there a configuration file that will make ignoring temporaries the default?
More generally: what's the best way to generate a "clean" patch off a tarball? I do this rarely enough (submitting a bug fix to an OSS project by email) that I always struggle with it...
EDIT: OK, the short answer is
diff -ruN -x *~ ...
Is there a better answer? E.g., can this go in a configuration file?

This doesn't strictly answer your question, but you can avoid the problem by configuring Emacs to use a specific directory to keep the backup files in. There are different implementations for Emacs or XEmacs.
In GNU Emacs
(defvar user-temporary-file-directory
(concat temporary-file-directory user-login-name "/"))
(make-directory user-temporary-file-directory t)
(setq backup-by-copying t)
(setq backup-directory-alist
`(("." . ,user-temporary-file-directory)
(,tramp-file-name-regexp nil)))
(setq auto-save-list-file-prefix
(concat user-temporary-file-directory ".auto-saves-"))
(setq auto-save-file-name-transforms
`((".*" ,user-temporary-file-directory t)))
In XEmacs
(require 'auto-save)
(require 'backup-dir)
(defvar user-temporary-file-directory
(concat (temp-directory) "/" (user-login-name)))
(make-directory user-temporary-file-directory t)
(setq backup-by-copying t)
(setq auto-save-directory user-temporary-file-directory)
(setq auto-save-list-file-prefix
(concat user-temporary-file-directory ".auto-saves-"))
(setq bkup-backup-directory-info
`((t ,user-temporary-file-directory full-path)))
You can also remove them all with a simple find command
find . -name “*~” -delete
Note that the asterisk and tilde are in double quotes to stop the shell expanding them.
By the way, these aren't strictly temporary files. They are a backup of the previous version of the file, so you can manually "undo" your last edit at any time in the future.

You can create an ignore file, like this:
core.*
*~
*.o
*.a
*.so
<more file patterns you want to skip>
and then run diff with -X option, like this:
diff -X ignore-file <other diff options you use/need> path1 path2
There used to be a .diffignore file "close" to the Linux kernel (maybe an informal file), but I couldn't find it anymore. Usually you keep using this ignore-file, just adding new patterns you want to ignore.

You can create a small sunction/script to it, like:
#!/bin/bash
olddir="/tmp/old"
newdir="/tmp/new"
pushd $newdir
for files in $(find . -name \*.c)
do
diff $olddir/$file $newdir/$file
done
popd
This is only one way to script this. The simple way. But I think you got the idea.
Other suggestion is configuring in emacs a backup dir, so your backup files go always to the same place, outside your work dir!

The poster has listed this as the 'short answer':
diff -ruN -x *~ ...
but feeding this to shell will cause the * to be globbed before diff is invoked.
This is better:
diff -r -x '*~' dir1 dir2
I omit the -u and -N flags as those are matters of taste and not relevant to the question at hand.

Related

eshell TRAMP find remote file with relative path (or at least less than the full Tramp path)?

I love eshell's TRAMP integration. With it I can do cd /ssh:foo:/etc to
ssh into a remote machine and visit its /etc/ directory. I can also do
find-file motd to open this file in my local emacs. However, what if I need to use sudo to change the file? I know I can give the
full path, like so:
find-file /sudo:foo:/etc/motd
but is there a way to open the file via TRAMPs sudo support, without having to type the full path?
I managed to came up with the following eshell alias that works for me:
alias sff 'find-file "${pwd}/$1"(:s/ssh/sudo/)'
It should be fairly obvious what it does. It prepends the working directory
path, but with the string ssh replaced by sudo. Thus it only works for
remote files accessed over ssh. I rarely edit files using sudo locally, so
that's not a problem for me. However, we can make it work for local files too, at the cost of complexity:
alias sff 'find-file "${pwd}/$1"(:s,^,/sudo::,:s,::/ssh:,:,)'
That is, prepend /sudo:: (which is how to sudo for local files) and
subsequently replace any ocurrence of ::/ssh: with :. (I would have just removed :/ssh:, but eshell's :s/// construct didn't accept an empty
replacement.)
I found an alternative answer that works very well over at EmacsWiki.
Using that you'd still open the file with find-file as usual, but then
invoke M-x sudo-edit-current-file (shown below) to re-open the file as root
using Tramp. I think this is a very elegant solution, because often I
initially just want to look at a file, then later find that I need to edit it.
Here's the function, in case it disappears from the page above:
(set-default 'tramp-default-proxies-alist (quote ((".*" "\\`root\\'" "/ssh:%h:"))))
(require 'tramp)
(defun sudo-edit-current-file ()
(interactive)
(let ((position (point)))
(find-alternate-file
(if (file-remote-p (buffer-file-name))
(let ((vec (tramp-dissect-file-name (buffer-file-name))))
(tramp-make-tramp-file-name
"sudo"
(tramp-file-name-user vec)
(tramp-file-name-host vec)
(tramp-file-name-localname vec)))
(concat "/sudo:root#localhost:" (buffer-file-name))))
(goto-char position)))

How can I use M-x rgrep with the git grep command in Emacs?

I want to be able to use the normal M-x rgrep workflow (entering a path, a pattern and displaying the linked results in a *grep* buffer) but using git grep instead of the normal find command:
find . -type f -exec grep -nH -e {} +
I tried directly setting the grep-find-command variable:
(setq grep-find-command "git grep")
and using grep-apply-setting
(grep-apply-setting 'grep-find-command "git grep")
but neither seems to work. When I run M-x rgrep it just uses the same find command as before.
In fact, I'm pretty sure now that rgrep doesn't even use the grep-find-command variable, but I can't figure out where it's command is stored.
What about M-x vc-git-grep (C-x v f). Doesn't that do what you need?
It prompts you for:
search pattern (default: token at point, or region)
filename pattern (default: current file suffix)
base search directory (default, current dir)
Works nicely for me.
Turns out the relevant variable is actually grep-find-template. This takes a command with a few additional parameters:
<D> for the base directory
<X> for the find options to restrict directory list
<F> for the find options to limit the files matched
<C> for the place to put -i if the search is case-insensitive
<R> for the regular expression to search for
The default template looks like this:
find . <X> -type f <F> -exec grep <C> -nH -e <R> {} +
To make the command work with git grep, I had to pass in a few options to make sure git doesn't use a pager and outputs things in the right format. I also ignored a few of the template options because git grep already restricts the files searched in a natural way. However, it probably makes sense to add them back in somehow.
My new value for grep-find-template is
git --no-pager grep --no-color --line-number <C> <R>
After some cursory testing, it seems to work.
Note that you should set this variable using grep-apply-setting rather than modifying it directly:
(grep-apply-setting 'grep-find-template "git --no-pager grep --no-color --line-number <C> <R>")
Since I don't use two of the inputs to rgrep, I wrote my own git-grep command which temporarily stashes the old grep-find-template and replaces it with mine. This feels a bit hacky, but also seems to work.
(defcustom git-grep-command "git --no-pager grep --no-color --line-number <C> <R>"
"The command to run with M-x git-grep.")
(defun git-grep (regexp)
"Search for the given regexp using `git grep' in the current directory."
(interactive "sRegexp: ")
(unless (boundp 'grep-find-template) (grep-compute-defaults))
(let ((old-command grep-find-template))
(grep-apply-setting 'grep-find-template git-grep-command)
(rgrep regexp "*" "")
(grep-apply-setting 'grep-find-template old-command)))
With Emacs for Windows and Git Bash make sure PATH finds git.exe or vc-git-grep won't work:
(let ((dir "C:/Program Files/Tools/Git/bin"))
(setenv "PATH" (concat (getenv "PATH") ";" dir))
(setq exec-path (append exec-path '(dir))))
exec-path is not enough... resaons are explained here: Using git with emacs
Since vc-git-grep uses the directory of the buffer from which you run the function I also found a wrapper convenient:
(global-set-key [(control f8)]
(lambda() (interactive)
(with-current-buffer ROOT (call-interactively #'vc-git-grep))))
Here ROOT is a buffer (or function that evaluates a buffer) from whose directory the search begins.

Batch export of org-mode files from the command line

Assume that I have in a certain directory several org-mode files: foo1.org, foo2.org, etc. I would like to have a script (maybe a makefile) that I could invoke something like
$ generate-pdfs
and foo1.pdf, foo2.pdf, etc. will be generated.
I thought that something like emacs --batch --eval <MAGIC> is a good start, but I don't know the magic.
A solution that is solely inside emacs could be of interest as well.
As you said, Emacs has the --batch option to perform operations with Emacs from the shell. In addition to that, you can use the -l flag to load Emacs Lisp code from a file and execute it, and the -f flag to execute a single Lisp function.
Here is a basic example, which exports a single org-mode file to HTML:
emacs myorgfile.org --batch -f org-html-export-to-html --kill
Perhaps you want something more advanced like exporting/publishing a full org-mode project. I do not have sample code for that, but it should not be too complicated.
I also have a sample Makefile I wrote some time ago to export all org-mode files in the directory to HTML (and also copy the HTML files to another directory):
OUT_DIR=/some/output/dir/html
# Using GNU Make-specific functions here
FILES=$(patsubst %.org,$(OUT_DIR)/%.html,$(wildcard *.org))
.PHONY: all clean install-doc
all: install-doc
install-doc: $(OUT_DIR) $(FILES)
$(OUT_DIR):
mkdir -v -p $(OUT_DIR)
%.html: %.org
emacs $< --batch -f org-html-export-to-html--kill
$(OUT_DIR)/%.html: %.html
install -v -m 644 -t $(OUT_DIR) $<
rm $<
clean:
rm *.html
EDIT:
With Org-mode 8 and the new export engine the function for HTML export has changed.
To make the previous examples work with Org 7 or older, replace org-html-export-to-html with org-export-as-html.
I expect to publish (by the end of this week-end) OrgMk, a suite of Makefile and standalone Bash scripts (usable as well under Cygwin) just to do that! Even more: generation of HTML, Ascii, Beamer, etc.
You'll find it on my GitHub account: https://github.com/fniessen/ (where I already have Emacs configuration files, color themes and other stuff such as an Org Babel refcard -- in progress).
Mark a few org files in dired and call this:
(defun dired-org-to-pdf ()
(interactive)
(mapc
(lambda (f)
(with-current-buffer
(find-file-noselect f)
(org-latex-export-to-pdf)))
(dired-get-marked-files)))
If you know what async is, wrap the call as it can take a while.
update:
Here's a version that combines the awesome dired approach with the lame
other one:)
(defun dired-org-to-pdf ()
(interactive)
(let ((files
(if (eq major-mode 'dired-mode)
(dired-get-marked-files)
(let ((default-directory (read-directory-name "dir: ")))
(mapcar #'expand-file-name
(file-expand-wildcards "*.org"))))))
(mapc
(lambda (f)
(with-current-buffer
(find-file-noselect f)
(org-latex-export-to-pdf)))
files)))

Can I use ediff if I have a file and a diff, rather than two versions of the same file?

With tf.exe diff , I can get a diff.
Can I use this with ediff to visualize the diff in emacs?
I'm under the impression that ediff normally takes 2 or 3 files. I just have the one file, and a diff.
An option you might get to work is to use
M-x ediff-patch-buffer
It will prompt you for the patch file (or buffer if you have it open already), and the buffer to be patched. It then will march you through the differences.
Because the diff shows changes from the repository version to the current version, the patch is wrong direction. I'd write a command that generated the proper diff and use that - if you really want to use a diff.
Personally, I'd probably try to plug some code in to get 'ediff-revision (which I have bound to C-x v -) to get it to work.
Or just write some lisp which follows this pseudo code (since I don't have tf to do actual testing):
(defun ediff-tf-file-with-previous-version (file &optional version)
"DTRT and call ediff with the previous version of this file"
(interactive)
(ediff-files (progn
(unless version
(setq version (<parse-to-get-version> (shell-command (concat "tf.exe properties " file)))))
(shell-command (concat "tf.exe view " file (<munge-itemspec-version> version) " > " file ".older")))
file))
thanks R Berg for the fix
It looks as though someone has written a rudimentary Team Foundation mode, which you can grab from the wiki page here. It doesn't look like it has plugged anything into ediff though.
Here's a script I wrote that does it (I think!):
#!/bin/bash
# quit on error
set -e
# create a temporary file for the patched output
# note that the mkfifo command is optional - it will save disc space
patched_file=/tmp/diff_$RANDOM
mkfifo $patched_file
patch -o $patched_file "$1" "$2" &
vimdiff "$1" $patched_file
rm $patched_file

Dired copy asynchronously

Is there a way to modify/tell dired to copy files asynchronously? If you mark multiple files in dired and then use 'C' to copy them, emacs locks up until every file is copied. I instead want this copy to be started, and for me to continue editing as it goes on in the background. Is there a way to get this behaviour?
EDIT: Actually, C calls 'dired-do-copy' in dired-aux, not in dired itself. Sorry for any confusion.
I think emacs is mostly limited to a single thread - so this may not be directly possible through standard dired commands such as 'C' copy.
However, there is a dired command "dired-do-shell-command" which calls out to a shell to do the work in the background. If you select the files you want to copy and then use key '!' (this runs dired-do-shell-command) then type 'cp ? [destination]' (possibly can use 'copy' if you are on windows). I haven't tested this - so see help on "dired-do-shell-command" for full details.
See also the Emacs function dired-do-async-shell-command.
For an even more generic solution see https://github.com/jwiegley/emacs-async with which you also can evaluate arbitrary Emacs Lisp code through call to a separate Emacs process (which of course incurs a bit of extra latency). More specifically regard file operations see the file dired-async.el in this repo.
Also note that there is work on threading in Emacs under the working name Concurrent Emacs but it's not there yet. See http://www.emacswiki.org/emacs/ConcurrentEmacs for details.
I found this answer quite helpful: https://emacs.stackexchange.com/a/13802/10761. Reading that answer shows that you can make it so that dired will copy with the scp method instead of the ssh method (the latter initially encodes the file with gzip and that can be quite slow). The scp method will only copy with the scp program when the file is larger than tramp-copy-size-limit (which is 10240 by default). Using this scp method in conjunction with dired-async-mode is very nice, as it will not only copy quickly with scp, but it will also do it asynchronously and out of your way.
Also, I think this is useful: https://oremacs.com/2016/02/24/dired-rsync/. It provides this snippet of code to use rsync to copy files in dired:
;;;###autoload
(defun ora-dired-rsync (dest)
(interactive
(list
(expand-file-name
(read-file-name
"Rsync to:"
(dired-dwim-target-directory)))))
;; store all selected files into "files" list
(let ((files (dired-get-marked-files
nil current-prefix-arg))
;; the rsync command
(tmtxt/rsync-command
"rsync -arvz --progress "))
;; add all selected file names as arguments
;; to the rsync command
(dolist (file files)
(setq tmtxt/rsync-command
(concat tmtxt/rsync-command
(shell-quote-argument file)
" ")))
;; append the destination
(setq tmtxt/rsync-command
(concat tmtxt/rsync-command
(shell-quote-argument dest)))
;; run the async shell command
(async-shell-command tmtxt/rsync-command "*rsync*")
;; finally, switch to that window
(other-window 1)))
(define-key dired-mode-map "Y" 'ora-dired-rsync)