Merge Debian Changelogs Safely with dpkg-mergechangelogs
You will combine two edited copies of a Debian debian/changelog into one ordered file, with an optional three-way merge for the same version entry. The workflow keeps the source files intact until you have inspected the result. Allow about fifteen minutes for a small changelog, longer if the branches contain several conflicting edits.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need the dpkg-dev package and three changelog files: a common ancestor, and the two branch versions. The examples use the command installed here from dpkg-dev version 1.22.6ubuntu6.6, reporting dpkg-mergechangelogs version 1.22.6. Version-specific options are called out below.
1. Check the installed command
First confirm the binary and package version. These are ordinary read-only commands and do not need sudo:
$ command -v dpkg-mergechangelogs
/usr/bin/dpkg-mergechangelogs
$ dpkg-query -W -f='${Package} ${Version}\n' dpkg-dev
dpkg-dev 1.22.6ubuntu6.6
$ dpkg-mergechangelogs --version
Debian dpkg-mergechangelogs version 1.22.6.
The command takes old, new-a and new-b, followed by an optional output path. It writes the merged changelog to that path, or to standard output when the path is omitted.
2. Put the three inputs in a disposable test area
Do not experiment on your working copy's real debian/changelog first. Make read-only copies of the ancestor and branch files in a temporary directory, or use paths inside a disposable checkout:
$ mkdir -p /tmp/changelog-merge-test
$ cp --reflink=auto debian/changelog /tmp/changelog-merge-test/old
$ cp --reflink=auto /path/to/branch-a/debian/changelog /tmp/changelog-merge-test/new-a
$ cp --reflink=auto /path/to/branch-b/debian/changelog /tmp/changelog-merge-test/new-b
$ ls -l /tmp/changelog-merge-test/old /tmp/changelog-merge-test/new-a /tmp/changelog-merge-test/new-b
Replace the paths with your actual common ancestor and branch files. The names are positional, not descriptive: old is the base, while new-a and new-b are the two descendants. Check that all three files are the changelog you intended before proceeding.
Checkpoint
The input files exist and remain separate. The command reads them; it does not update them.
3. Produce a merged file without overwriting either branch
Pass a new destination as the fourth argument. This example writes to merged, leaving all three inputs unchanged:
$ dpkg-mergechangelogs \
/tmp/changelog-merge-test/old \
/tmp/changelog-merge-test/new-a \
/tmp/changelog-merge-test/new-b \
/tmp/changelog-merge-test/merged
$ test -s /tmp/changelog-merge-test/merged && echo 'merged file is non-empty'
merged file is non-empty
Entries are identified by version and ordered from the highest version downwards. Entries that occur in only one branch are included. If the same version appears in both branches, the program attempts a line-based three-way merge of that entry when the Perl module Algorithm::Merge is available. That module is supplied by the libalgorithm-merge-perl package. Without it, the same entry can become a global conflict instead.
Inspect the result before copying it into a checkout:
$ sed -n '1,100p' /tmp/changelog-merge-test/merged
$ dpkg-parsechangelog -l /tmp/changelog-merge-test/merged -S Version
The first command is a review, not a proof that the merge is suitable for upload. The second asks the installed Debian tooling to parse the resulting file and prints its top version. If parsing fails, stop and fix the changelog rather than replacing a branch file.
4. Handle repeated experimental versions deliberately
Normal comparison treats different versions as different entries. That matters for development versions such as 2.3-1~exp1 and 2.3-1~exp5, even when both branches are editing what you regard as one evolving entry. Add --merge-prereleases, or its short form -m, when the part after the last tilde should be ignored for identity:
$ dpkg-mergechangelogs --merge-prereleases \
/tmp/changelog-merge-test/old \
/tmp/changelog-merge-test/new-a \
/tmp/changelog-merge-test/new-b \
/tmp/changelog-merge-test/merged-prereleases
This option changes which entries are considered the same. It does not turn an arbitrary set of versions into one release, and it does not remove the tilde from the version printed in the output. Use it only when the suffix represents repeated revisions of the same pre-release entry.
5. Coalesce unreleased development
Use --merge-unreleased when both branches contain entries marked UNRELEASED and their version numbers represent successive development rather than separate released history:
$ dpkg-mergechangelogs --merge-unreleased \
/tmp/changelog-merge-test/old \
/tmp/changelog-merge-test/new-a \
/tmp/changelog-merge-test/new-b \
/tmp/changelog-merge-test/merged-unreleased
With this option, the version number is ignored when comparing entries marked UNRELEASED. The resulting coalesced entry takes the version from the changelog data, so inspect its distribution, version and ordering before using it. This option was introduced in dpkg 1.21.0 and is available in the installed 1.22.6 command.
Do not combine this option with an assumption that every development entry is safe to merge. Review maintainer notes and issue references: a merged changelog records history, but it cannot resolve a packaging decision that the branches made differently.
6. Install the Git merge driver after testing
If this merge is for a Git repository, configure the driver only after the standalone command has produced a result you understand. The following changes Git configuration and repository attributes, so review the lines before running them. They do not require root:
$ git config merge.dpkg-mergechangelogs.name 'debian/changelog merge driver'
$ git config merge.dpkg-mergechangelogs.driver 'dpkg-mergechangelogs -m %O %A %B %A'
$ printf '%s\n' 'debian/changelog merge=dpkg-mergechangelogs' >> .gitattributes
$ git diff -- .gitattributes
$ git config --get-regexp '^merge\.dpkg-mergechangelogs\.'
The driver uses -m, the common ancestor placeholder %O, the current side %A and the other side %B. It writes back to %A, which is the file Git is asking the driver to merge. The .gitattributes line applies the driver to debian/changelog.
Recovery
Before committing, undo the repository attribute with git restore .gitattributes only if that file contains no unrelated work. Otherwise edit the line out manually. To remove the local driver settings, run git config --unset-all merge.dpkg-mergechangelogs.driver and git config --unset-all merge.dpkg-mergechangelogs.name. Do not run either cleanup command blindly in a repository with pre-existing configuration you did not inspect.
7. Know the lossy boundary
The program parses changelog entries through Dpkg::Changelog. Material that the parser does not recognise, including stray comments, can be lost during the merge. Keep the original files under version control and review the complete diff:
$ diff -u /tmp/changelog-merge-test/new-a /tmp/changelog-merge-test/merged
$ git diff --check
A clean git diff --check catches whitespace errors in a working tree, not missing history or an incorrect version. If the merged output is wrong, discard only the uncommitted generated file and rerun with corrected inputs. Do not overwrite a trusted changelog until the review and parser checks pass.
Done means
dpkg-mergechangelogsis installed and its version is known.- The common ancestor and both branch changelogs were identified in the correct positional order.
- The merged output was written to a new path, parsed with
dpkg-parsechangelog, and reviewed. -mor--merge-unreleasedwas used only when the version semantics justified it.- Any Git driver configuration was reviewed, tested, and kept separate from an unreviewed release commit.