13

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 Answers 3

18

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).

8
  • that works great for ediff-files. Thanks! I still can't ediff-directories to work. Any ideas? Commented Nov 17, 2014 at 1: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
    Commented Nov 17, 2014 at 1:08
  • When I use that call as you have written, emacs tells me, "This session group has no members" Commented Nov 17, 2014 at 2: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
    Commented Nov 17, 2014 at 7: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. Commented Nov 18, 2014 at 5:39
6

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...

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.