--- /dev/null
+
+/* README:
+ The default merge driver of 'git' *always* produces conflicts when
+ pulling public modifications into a privately modified ChangeLog file.
+ This is because ChangeLog files are always modified at the top; the
+ default merge driver has no clue how to deal with this. Furthermore
+ the conflicts are presented with more <<<< ==== >>>> markers than
+ necessary; this is because the default merge driver makes pointless
+ efforts to look at the individual line changes inside a ChangeLog entry.
+
+ This program serves as a 'git' merge driver that avoids these problems.
+ 1. It produces no conflict when ChangeLog entries have been inserted
+ at the top both in the public and in the private modification. It
+ puts the privately added entries above the publicly added entries.
+ 2. It respects the structure of ChangeLog files: entries are not split
+ into lines but kept together.
+ 3. It also handles the case of small modifications of past ChangeLog
+ entries, or of removed ChangeLog entries: they are merged as one
+ would expect it.
+ 4. Conflicts are presented at the top of the file, rather than where
+ they occurred, so that the user will see them immediately. (Unlike
+ for source code written in some programming language, conflict markers
+ that are located several hundreds lines from the top will not cause
+ any syntax error and therefore would be likely to remain unnoticed.)
+ */
+
+/* Installation:
+
+ $ gnulib-tool --create-testdir --dir=/tmp/testdir123 git-merge-changelog
+ $ cd /tmp/testdir123
+ $ ./configure
+ $ make
+ $ make install
+
+ Additionally, for git users:
+ - Add to .git/config of the checkout (or to your $HOME/.gitconfig) the
+ lines
+
+ [merge "merge-changelog"]
+ name = GNU-style ChangeLog merge driver
+ driver = /usr/local/bin/git-merge-changelog %O %A %B
+
+ - In every directory that contains a ChangeLog file, add a file
+ '.gitattributes' with this line:
+
+ ChangeLog merge=merge-changelog
+
+ (See "man 5 gitattributes" for more info.)
+
+ Additionally, for bzr users:
+ - Install the 'extmerge' bzr plug-in listed at
+ <http://doc.bazaar.canonical.com/plugins/en/index.html>
+ <http://wiki.bazaar.canonical.com/BzrPlugins>
+ - Add to your $HOME/.bazaar/bazaar.conf the line
+
+ external_merge = git-merge-changelog %b %T %o
+
+ - Then, to merge a conflict in a ChangeLog file, use
+
+ $ bzr extmerge ChangeLog
+
+ Additionally, for hg users:
+ - Add to your $HOME/.hgrc the lines
+
+ [merge-patterns]
+ ChangeLog = git-merge-changelog
+
+ [merge-tools]
+ git-merge-changelog.executable = /usr/local/bin/git-merge-changelog
+ git-merge-changelog.args = $base $local $other
+
+ See <http://www.selenic.com/mercurial/hgrc.5.html> section merge-tools
+ for reference.
+ */
+
+/* Use as an alternative to 'diff3':
+ git-merge-changelog performs the same role as "diff3 -m", just with
+ reordered arguments:
+ $ git-merge-changelog %O %A %B
+ is comparable to
+ $ diff3 -m %A %O %B
+ */
+
+/* Calling convention:
+ A merge driver is called with three filename arguments:
+ 1. %O = The common ancestor of %A and %B.
+ 2. %A = The file's contents from the "current branch".
+ 3. %B = The file's contents from the "other branch"; this is the contents
+ being merged in.
+
+ In case of a "git stash apply" or of an upstream pull (e.g. from a subsystem
+ maintainer to a central maintainer) or of a downstream pull with --rebase:
+ 2. %A = The file's newest pulled contents; modified by other committers.
+ 3. %B = The user's newest copy of the file; modified by the user.
+ In case of a downstream pull (e.g. from a central repository to the user)
+ or of an upstream pull with --rebase:
+ 2. %A = The user's newest copy of the file; modified by the user.
+ 3. %B = The file's newest pulled contents; modified by other committers.
+
+ It should write its merged output into file %A. It can also echo some
+ remarks to stdout. It should exit with return code 0 if the merge could
+ be resolved cleanly, or with non-zero return code if there were conflicts.
+ */
+
+/* How it works:
+ The structure of a ChangeLog file: It consists of ChangeLog entries. A
+ ChangeLog entry starts at a line following a blank line and that starts with
+ a non-whitespace character, or at the beginning of a file.
+ The merge driver works as follows: It reads the three files into memory and
+ dissects them into ChangeLog entries. It then finds the differences between
+ %O and %B. They are classified as:
+ - removals (some consecutive entries removed),
+ - changes (some consecutive entries removed, some consecutive entries
+ added),
+ - additions (some consecutive entries added).
+ The driver then attempts to apply the changes to %A.
+ To this effect, it first computes a correspondence between the entries in %O
+ and the entries in %A, using fuzzy string matching to still identify changed
+ entries.
+ - Removals are applied one by one. If the entry is present in %A, at any
+ position, it is removed. If not, the removal is marked as a conflict.
+ - Additions at the top of %B are applied at the top of %A.
+ - Additions between entry x and entry y (y may be the file end) in %B are
+ applied between entry x and entry y in %A (if they still exist and are
+ still consecutive in %A), otherwise the additions are marked as a
+ conflict.
+ - Changes are categorized into "simple changes":
+ entry1 ... entryn
+ are mapped to
+ added_entry ... added_entry modified_entry1 ... modified_entryn,
+ where the correspondence between entry_i and modified_entry_i is still
+ clear; and "big changes": these are all the rest. Simple changes at the
+ top of %B are applied by putting the added entries at the top of %A. The
+ changes in simple changes are applied one by one; possibly leading to
+ single-entry conflicts. Big changes are applied en bloc, possibly
+ leading to conflicts spanning multiple entries.
+ - Conflicts are output at the top of the file and cause an exit status of
+ 1.
+ */