2

I want to compare and merge some org files. How can I make a diff tool assume that some tasks or notes are identical, even if they are on different levels, i.e. strings only differ in the number of asterisks (*) at the beginning? I would then collapse those strings and consider merging only the rest that really differ.

Evgeny Mikhaylov
  • 179
  • 1
  • 14

3 Answers3

2

If you are content to use diff on the bash command line and are not looking for a pure emacs solution, you can use process substitution to pass into diff slightly modified files:

diff <(sed -E 's/^\*+/*/' file1.org) <(sed -E 's/^\*+/*/' file2.org)

Each sed command outputs its input file unchanged, except that a string of one or more asterisks at the beginning of a line is changed to a single asterisk. Bash process substitution makes a file out of that output. Conceptually, the above is equivalent to

sed -E 's/^\*+/*/' file1.org > /tmp/file1.modified.org
sed -E 's/^\*+/*/' file2.org > /tmp/file2.modified.org
diff /tmp/file1.modified.org /tmp/file2.modified.org
rm /tmp/file1.modified.org /tmp/file2.modified.org

You can also write a bash script to simplify the invocation:

#!/bin/bash

diff <(sed -E 's/^\*+/*/' $1) <(sed -E 's/^\*+/*/' $2)

Save it as stardiff in $HOME/bin (which I assume is in your $PATH), make it executable: chmod +x $HOME/bin/stardiff and invoke it like this:

stardiff file1.org file2.org

Process substitution is a general mechanism and is very useful in situations like this one, where we basically want to pipe the output of a command (the sed command output) into the input of another command (the diff command), except that we have two or more inputs: an ordinary pipe cannot deal with that, but process subsitution can.

Of course, this has nothing to do with emacs, but I hope the emacs SE moderators will not be too upset :-)

NickD
  • 27,023
  • 3
  • 23
  • 42
2

You can do an ediff-buffers-wordwise and type #h \*+ to ignore words consisting of stars.

If you advance to the next diff by pressing SPC ediff will skip words only differing in the number of stars.

Tobias
  • 32,569
  • 1
  • 34
  • 75
2

One can configure ediff-filtered-filters such that it replaces multiple leading stars with one leading star and call ediff-buffers.

The following Elisp function my-org-ediff does that for you. Just copy the Elisp code to your init file, restart Emacs, and use my-org-ediff for diffing org files in the way you want it.

(defvar ediff-filtered-filters)
(defun my-org-ediff ()
  "Ediff like `ediff-buffers' but convert all heading leaders \\*+\\([[:space:]]\\) to \\*\\1."
  (interactive)
  (let ((ediff-filtered-filters '(("^\\*+\\([[:space:]]\\)" . "*\\1"))))
    (call-interactively #'ediff-buffers)))
Tobias
  • 32,569
  • 1
  • 34
  • 75