Difdef
Utility to do an N-way diff and N-way merge, for N>2. Uses the patience diff algorithm.
Install / Use
/learn @Quuxplusone/DifdefREADME
This is "Difdef", a program that performs a multi-way diff among a set of source files. Difdef is released under the MIT (Expat) license; see LICENSE for details.
==Command-line use==
To build Difdef, run "make". This will produce an executable called "difdef", with the following behavior:
difdef [-D FOO ...] file1 [file2 file3 ...]
Invoked without any -D options, "difdef" produces output similar to the standard "diff" program: a merged version of the given files, with a prefix on each line indicating which files contain that line. Where "diff" uses a one-character prefix from the set [+- ], "difdef" uses an N-character prefix: "a" in the first column means the line is present in file1, "b" in the second column means the line is present in file2, and so on.
Invoked with -D options (of which there must be exactly as many as there are filenames on the command line), "difdef" produces a merged version of the given files where each difference is surrounded by #ifdefs of the form #if defined(V1) || defined(V4) || defined(V5) <differing text> #endif /* V1 || V4 || V5 */ In other words, the output of "difdef -DV1 -DV2 A B" is similar to the output of "diff -DV2 A B". However, blank lines are treated specially; they can be coalesced and/or moved outside an #ifdef range. Also, "difdef A B C D E" produces readable output similar to the above example, where iterated application of "diff -D" would produce an unintelligible stew.
Invoked with the -u option, "difdef" behaves as a drop-in replacement for "diff -u", mostly just to prove that I could do it.
==Hacking==
Internally, the code aims for reusability. To create a merge, your code should #include "difdef.h". The class Difdef manages all the resources associated with a single N-way merge; the Difdef constructor requires that you specify N.
Once you have a Difdef object, you can populate it by calling mydifdef.replace_file(i, <file>) for 0 <= i < N. Then call mydifdef.merge(), which returns a Diff object. The Diff object (which perhaps would have been better called a Merge object) is just a wrapper around a vector of Lines, where each Line knows which of the N files it comes from and what its text is.
The full "public interface" for Difdef looks like this:
class Difdef {
static const int MAX_FILES = 32;
typedef unsigned int mask_t;
class Diff {
class Line {
const std::string *text;
mask_t mask;
bool in_file(int fileid) const;
};
const int dimension;
mask_t all_files_mask() const;
bool includes_file(int fileid) const;
};
Difdef(int num_files);
void replace_file(int fileid, std::istream &);
Diff merge() const;
Diff merge(int, int) const;
Diff merge(const std::set<int> &) const;
const int NUM_FILES;
};
Related Skills
node-connect
338.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
338.7kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.6kCommit, push, and open a PR
