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.
3 Answers
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)))
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 :-)
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.
-
-
Same question for me. I guess that this is a custom function defined in emacs.stackexchange.com/a/46195/226– SekiCommented Dec 5, 2022 at 17:22