Git merge driver for
package-lock.json
v2+
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 ls
to 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
npm
v7.0.0+ - Removed
--no-legacy
flag because what is even that - Supports Git includes when discovering and writing to Git configuration files
- Will cleanup empty
gitattributes
files 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 install
The 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-driver
BONUS! 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 main
Eek, 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 status
M 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=butts
Run any command with --verbose
to get more output. For example:
npx package-lock-merge-driver install --verbose
This 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-driver
package-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 thegitattributes
file 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.json
and 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-driver
The 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_modules
and any othernode_modules
folders 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-only
will not avail you as of npm v7.0.0. So that's out.- Running a full
npm install
every time is slow enough without arm -rf node_modules packages/*/node_modules
first (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.json
due to hownpm
modifiespackage-lock.json
when anode_modules
is 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 ci
is not possible, of course, because it only works if the lockfile is valid and synced with allpackage.json
manifests.- Just accepting "their"
package-lock.json
doesn't help, as it will always require a manualnpm install
thereafter.
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.