12

I would like to launch emacs to ediff either files or directories. For example, I'd like something like:

emacs -f ediff-files file1 file2

But when I do this, it doesn't take file1 and file2 as the two files to diff. Rather, emacs prompts me for the files to difference.

Does anyone know how to do this in one command line?

3 Answers3

13

I'm pretty sure there are other solutions, but you can do this using --eval instead of -f (--funcall):

emacs --eval '(ediff-files "file1" "file2")'

In fact, the Emacs manual on "Command Line Arguments for Emacs Invocation" says that -f function and --funcall function

Call Lisp function function. If it is an interactive function (a command), it reads the arguments interactively just as if you had called the same function with a key sequence. Otherwise, it calls the function with no arguments.

This explains why you can not get the behavior you want with -f/--funcall.


ediff-directories takes three arguments, so the command shown above changes to

emacs --eval '(ediff-directories "dir1" "dir2" "regexp")'

e.g. to compare everything in both directories (i.e. unfiltered) use .* as a regexp:

emacs --eval '(ediff-directories "dir1" "dir2" ".*")'

As explained here, ediff-directories causes Emacs to enter ediff-meta-mode, so you'll be dropped into the "Ediff Session Group Panel" first. From the Ediff manual on Session Groups:

Several major entries of Ediff perform comparison and merging on directories. On entering ediff-directories, ediff-directories3, [...] the user is presented with a Dired-like buffer that lists files common to the directories involved along with their sizes. [...] We call this buffer Session Group Panel because all Ediff sessions associated with the listed files will have this buffer as a common focal point. [...]

In directory comparison or merging, a session group panel displays only the files common to all directories involved. The differences are kept in a separate directory difference buffer and are conveniently displayed by typing D to the corresponding session group panel. [...]

So to display the actual diff, just hit D (ediff-show-dir-diffs).

wilfcoles
  • 3
  • 1
itsjeyd
  • 14,586
  • 3
  • 58
  • 87
  • that works great for ediff-files. Thanks! I still can't ediff-directories to work. Any ideas? – Madeleine P. Vincent Nov 17 '14 at 01:01
  • @MadeleineP.Vincent Could you be a bit more specific about what isn't working? For me, `emacs --eval '(ediff-directories "dir1" "dir2" "regexp")'` works fine. – itsjeyd Nov 17 '14 at 01:08
  • When I use that call as you have written, emacs tells me, "This session group has no members" – Madeleine P. Vincent Nov 17 '14 at 02:00
  • @MadeleineP.Vincent Yes, but this is not an error message; it's displayed in what seems to be some sort of overview buffer. To get the actual diff, all you need to do is hit `D` (`ediff-show-dir-diffs`). – itsjeyd Nov 17 '14 at 07:53
  • I'm close, but not quite there. When I hit D, it shows dir1 and dir2, and `*** No differences ***`, even though if I invoke ediff from within emacs with M-x, everything works as expected (i.e., the differences are shown). Maybe I have something set differently in my .emacs. – Madeleine P. Vincent Nov 18 '14 at 05:39
  • @MadeleineP.Vincent If you suspect that something in your `.emacs` might be interfering, try invoking Emacs via `emacs -Q --eval ...`. This will prevent any customizations from being loaded. If this results in the desired behavior, you can recursively bisect your `.emacs` to identify the code that is causing the problem: Comment out half of the code and restart Emacs (without the `-Q` flag). If the problem persists, the offending code is in the portion of your `.emacs` that is currently *not* commented out. Similarly, if the problem is gone, ... – itsjeyd Nov 18 '14 at 07:42
  • @MadeleineP.Vincent ... this means that the offending code is in the portion of your `.emacs` that *is* commented out. Proceed by commenting out half of the code that you now know contains the offending code, and restart Emacs. Repeat this process until you've narrowed the problem down to a few lines of code. You can easily (un)comment multiple lines of code by setting up a region and hitting `M-;` (`comment-dwim`). If you still need help after narrowing down the problem to a few lines of code, **consider asking a new question**. – itsjeyd Nov 18 '14 at 07:46
  • @MadeleineP.Vincent As far as I can tell, the original problem of "how do I keep `ediff-files`/`ediff-directories` from prompting me for files/directories at startup" has been solved. – itsjeyd Nov 18 '14 at 07:48
5

I use the following script: it checks in advance if there are differences, and in case there are, it opens Emacs with the appropriate function evaluated. With the -d option, it assumes the items provided are directories, and ediff-directories instead of ediff-files is used; otherwise it checks if they are directories or files, and sets the function to use accordingly.

#!/bin/sh

EMACS=$(which emacs)

if [ $# -lt 2 ] ; then
    echo "Usage:: " `basename $0` " [ -d ]  item1  item2"
    exit 1
fi

dir="no"
if [ "$1" = "-d" ]; then
    dir="yes"
    item1="$2"
    item2="$3"
else
    if [ -d "$1" -a -d "$2" ]; then
        dir="yes"
    fi
    item1="$1"
    item2="$2"
fi

if [ "$dir" = "no" ]; then

    # Check that files do exist
    if [ ! -f "$item1" ] ; then
        printf "File %s not found.\n" "$item1"
        exit 2
    fi
    if [ ! -f "$item2" ] ; then
        printf "File %s not found.\n" "$item2"
        exit 2
    fi

    # Check whether files are identical or not
    diffdata=`diff "$item1" "$item2"`
    if [ "_" = "_$diffdata" ] ; then
        printf "%s and %s are identical.\n" "$item1" "$item2"
        exit 3
    fi

fi

diff_fn="ediff-files"
if [ "$dir" = "yes" ]; then
    diff_fn="ediff-directories"
    opt="\"\""
fi

# Run Emacs with ediff-files function
printf "Comparing files %s and %s . . .  " "$item1" "$item2"
$EMACS -q -nw -eval "($diff_fn \"$item1\" \"$item2\" $opt)" && echo done.

exit 0

Since it checks if there are differences in advance, I find it very handy when comparing lots of files in different folders, from the command line, instead of running one single diff session in the parent folders. For example for comparing folders A and B, and copying non-existing files from the first to the other...

J C Gonzalez
  • 365
  • 4
  • 9
0

If you are using emacs with package manager(ie.use-package) then add this snipped to the init.el file

(use-package ediff
  :config
  (setq ediff-split-window-function 'split-window-horizontally)
  (setq ediff-window-setup-function 'ediff-setup-windows-plain)
  (defun my/command-line-diff (switch)
    (setq initial-buffer-choice nil)
    (let ((file1 (pop command-line-args-left))
      (file2 (pop command-line-args-left)))
      (ediff file1 file2)))
  ;; show the ediff command buffer in the same frame
  (add-to-list 'command-switch-alist '("-diff" . my/command-line-diff)))

From the command line $ emacs -diff /path/to/file1 /path/to/file2 will launch files with diff in ediff mode

Talespin_Kit
  • 435
  • 2
  • 11