Keep the Changelog, Avoid the Conflicts
More code is flowing through projects, with people and agents working on changes in parallel. That means more pull requests updating the same changelog, often at the same time.
Two pull requests add unrelated features. Both add a line at the top of
CHANGELOG.md. The code merges cleanly, but the changelog conflicts:
## [Unreleased]
### Added
<<<<<<< HEAD- Added S3 support.=======- Added SSH support.>>>>>>> ssh-support- Initial feature.Both entries belong in the changelog. The conflict is straightforward to resolve, but it keeps coming back as more changes land.
A shared changelog puts everyone’s changes in one file, often under the same heading. Git sees competing edits to the same lines, even when the entries describe independent work.
We built changelog-merge to handle this for files that follow Keep a Changelog. It understands releases, categories, and entries. In this example, it keeps both additions:
## [Unreleased]
### Added
- Added S3 support.- Added SSH support.- Initial feature.Use it with devenv
Section titled “Use it with devenv”Enable the integration in your project’s devenv.nix:
{ changelog-merge.enable = true;}Enter the environment and merge as usual:
devenv shellgit merge ssh-supportdevenv configures Git to use the changelog-merge binary to resolve conflicts in
CHANGELOG.md.
For a changelog with a different name, add its path:
{ changelog-merge.enable = true; git.attributes = [ "docs/CHANGES.md merge=changelog-merge" ];}Commit your devenv configuration so other contributors get the same setup when they enter the environment. See the integration documentation for more options.
Use it with plain Git
Section titled “Use it with plain Git”You can use changelog-merge without devenv or Nix. With Rust 1.88 or newer installed, run:
cargo install changelog-merge --version 0.1.0 --lockedMake sure changelog-merge is on your PATH, then check your existing changelog:
changelog-merge check CHANGELOG.mdAdd this line to your repository’s .gitattributes:
CHANGELOG.md merge=changelog-mergeRegister the merge driver from inside the repository:
git config --local merge.changelog-merge.name 'Keep a Changelog semantic merger'git config --local merge.changelog-merge.driver 'changelog-merge merge %O %A %B --marker-size %L --path %P'git config --local merge.changelog-merge.recursive binaryCommit .gitattributes. Each contributor needs to install the executable and
run the three configuration commands in their clone. The attribute travels with
the repository; local Git configuration does not.
Now git merge, git rebase, and git cherry-pick can use changelog-merge
automatically. You can check the setup with:
git check-attr merge -- CHANGELOG.mdgit config --get merge.changelog-merge.driverThe first command should report CHANGELOG.md: merge: changelog-merge, and the
second should print the driver command you configured.
When a conflict still needs you
Section titled “When a conflict still needs you”If both branches rewrite the same entry incompatibly, changelog-merge leaves conflict markers for you to resolve. It also preserves conflicts when it cannot confidently match changes. Independent additions can merge automatically; competing changes still need a decision.
Try it on your next pair of changelog updates. The source and documentation cover merge behavior and limitations, and we’d like to hear how it works on your project’s changelog.

