Git merge driver for
package-lock.jsonv2+
This is a fork of the original (unmaintained) npm-merge-driver project.
This package provides a CLI to install (and uninstall) a merge driver which attempts to automatically resolve merge conflicts in package-lock.json files.
Do you get merge conflicts in your package-lock.json files? Like all the damn time? Then yeah.
TL;DR: This is a whole-ass package.
- Supports for npm workspaces (monorepos)
- Sacrifices speed for reliability
- Validates the result via
npm lsto check for broken dependencies (if this fails, automatic resolution fails) - Default behavior is to install merge drivers globally (you can still install locally if you want)
- Requires Node.js v20.0.0+
- Requires
npmv7.0.0+ - Removed
--no-legacyflag because what is even that - Supports Git includes when discovering and writing to Git configuration files
- Will cleanup empty
gitattributesfiles it created - Tested against an actual Git repository
- Unrecognizable compared to original; don't bother
In addition, the following items are current differences, but they might instead become non-differences in a hypothetical future:
- Use with Yarn or pnpm lockfiles is unsupported
- No support for
npm-shrinkwrap.json, but you probably don't care about that
I suppose if (big if) I do end up supporting Yarn or pnpm then I might need to rename the package. I'll think of a better name.
I needed npm-merge-driver to work. But it doesn't, and there's no way forward to fix it. So against my better judgement, here we are.
- Node.js v20.11.0+
- npm v7.0.0+
To start using it right away:
npx package-lock-merge-driver installThe next time any package-lock.json has a conflict, a merge driver will attempt to automatically fix it. Unless it fails, you don't need to do anything else. You will still need to resolve conflicts in package.json files yourself, though!
Tip
Once you've tried it a couple times and felt its powerful magic, it's recommended to install package-lock-merge-driver globally to avoid some npx-related overhead:
npm install -g package-lock-merge-driverBONUS! If you install globally and are on a POSIX OS, you should be able to run man package-lock-merge-driver to see the man page! Which is just this README.md; sorry.
After installation, you create a feature branch and make some dependency changes. Now you want to rebase onto main:
git rebase mainEek, there's a conflict! But don't panic! You should see something like thiss:
🔐 package-lock-merge-driver v2.3.6
Moved to trash: /my-repo/node_modules
package-lock-merge-driver: Successfully resolved conflicts in package-lock.json
Auto-merging package-lock.json
Did conflicts in package-lock.json remain?
git statusM package-lock.json
No. No conflicts in package-lock.json remain.
This only applies if you used the method detailed in Automatic Setup. If you didn't, then figure it out yourself.
To remove an installed merge driver, use package-lock-merge-driver uninstall:
npx package-lock-merge-driver uninstall [--global] [--name=package-lock-merge-driver]This will remove the driver from whatever Git configuration it put it in originally, and then remove it from the gitattributes file it used. If it created the gitattributes file and it is empty after removing the entry, package-lock-merge-driver will delete the file because it's a sweetheart.
The install command does the actual configuration ("installation") of the merge driver. It supports a couple of config options:
-
--command- This is the command used for the actual merge operation. You probably don't want to fiddle with this. -
--name- String to use as the internal driver name in your configuration. I don't know why this option is even here, but it is. -
--local- Install the driver in the local repository only. By default, the driver is installed globally.
For example, to install the driver locally in the current working directory using a custom name:
npx package-lock-merge-driver install --local --name=buttsRun any command with --verbose to get more output. For example:
npx package-lock-merge-driver install --verboseThis is tedious.
package-lock-merge-driver is explicitly designed to be installed globally. It bundles its own dependencies. You can install this into a local project, but I wouldn't recommend doing so.
npm install -g package-lock-merge-driverpackage-lock-merge-driver's automated installation uses the following config:
- A merge driver in the main Git configuration, including
name(description [really]),driver(the actual command)gitAttributesPath(path to thegitattributesfile we will write to; this is only necessary for clean uninstallation and you can ignore it if installing manually)
- A
gitattributes(5)configuration referencingpackage-lock.jsonand the merge driver configured in 1.
If you do not want package-lock-merge-driver to install itself for you (I guess I wouldn't blame you), here's an example of a manual global installation:
Add the driver to ~/.gitconfig:
git config --global merge.package-lock-merge-driver.name \
"Automatically merge npm lockfiles"
# this is the most important part!
git config --global merge.package-lock-merge-driver.driver \
"npx package-lock-merge-driver merge %A %O %B %P"Add the relevant attributes to ~/.gitattributes (creating if necessary):
package-lock.json merge=package-lock-merge-driverThe RHS of the merge attribute above must match <name> in merge.<name>.driver.
- Barely.
- Trash (read: move to the OS' trash/recycle bin/shitcan)
node_modulesand any othernode_modulesfolders found in workspaces, then re-runnpm install. - Validate result by running
npm ls.
Note
Workspaces (monorepo) support is best-effort, since package.json may be in conflict when we try to parse it. This will typically only affect the resulting lockfile if the actual workspaces field is in conflict.
npm install --package-lock-onlywill not avail you as of npm v7.0.0. So that's out.- Running a full
npm installevery time is slow enough without arm -rf node_modules packages/*/node_modulesfirst (though I could make this configurable, I suppose), we just move them away. Your OS will take care of it. Trust me. This has the advantage of mitigating churn inpackage-lock.jsondue to hownpmmodifiespackage-lock.jsonwhen anode_modulesis present. If you ever see random extra fields being added and removed topackage-lock.json, you know what I mean. I'm pretty sure this is just a bug innpm. npm ciis not possible, of course, because it only works if the lockfile is valid and synced with allpackage.jsonmanifests.- Just accepting "their"
package-lock.jsondoesn't help, as it will always require a manualnpm installthereafter.
If you know of some way to sort out the conflicts without a full npm install, please file an issue. Please. 🥹
- Current maintainer: Christopher Hiller
- Original author: Kat Marchán
- Copyright © 2025 Christopher Hiller
- Copyright © 2017 Microsoft Corporation (a.k.a. npm, Inc. a.k.a. GitHub)
This work is released under the terms of the ISC license. See LICENSE.md for details.