Solving Package-lock.json Conflicts

TLDR at the end! The full post contains an example to illustrate the point.

Create Example

Create a new folder and run these commands inside it:

npm init -y
npm i react@15
git init
git add package.json package-lock.json
git commit -m "Install React 15"

We created a new package.json, installed React 15 on it, and commit both package.json and package-lock.json.

Feature Branch One

Create another branch and update React to 16:

git checkout -b react-16
npm i react@16
git add -u
git commit -m "Install React 16"

Feature Branch Two

Go back to the original branch and create another branch from it where we install React 17:

git checkout -
git checkout -b react-17
npm i react@17
git add -u
git commit -m "Install React 17"

Merge Feature Branch One To Master

One of the developers finishes his work and it gets merged to master or equivalent:

git checkout master
git merge react-16

Dealing With Conflicts

The other developer finishes the work on Feature Branch Two and we want to rebase his work with master:

git checkout react-17
git rebase master

It fails due to a conflict on both package.json and package-lock.json:

Auto-merging package.json
CONFLICT (content): Merge conflict in package.json
Auto-merging package-lock.json
CONFLICT (content): Merge conflict in package-lock.json
error: could not apply f7b25bc... Install React 17
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

The package.json doesn't seem hard, we just have to use version 17:

{
"name": "example-package-lock-conflict",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
<<<<<<< HEAD
"react": "^16.14.0"
=======
"react": "^17.0.2"
>>>>>>> f7b25bc (Install React 17)
}
}

The package-lock.json conflict is bigger:

{
"name": "example-package-lock-conflict",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
<<<<<<< HEAD
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
},
"react": {
"version": "16.14.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2"
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
=======
"react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
>>>>>>> f7b25bc (Install React 17)
}
}
}

You may feel tempted to resolve this manually, but there are better ways. Older versions of the npm documentation had a section on this problem: Resolving lockfiles conflicts. I don't know where this section went on the newest documentation, but the knowledge on the old docs is still valid, and that's what we're going to do here.

Abort the rebase and install npm-merge-driver, which will automatically run npm install --package-lock-only whenever we do a rebase:

git rebase --abort
npx npm-merge-driver install --global

Then we can attempt to do the rebase again:

git rebase master

You'll see a message that npm-merge-driver failed due to a conflict in package.json. It even says that we should fix package.json manually and run npm install --package-lock-only to solve the package-lock.json conflict. Let's do exactly that, starting by fixing package.json:

{
"name": "example-package-lock-conflict",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"react": "^17.0.2"
}
}

and run:

npm i --package-lock-only
git add -u
git commit -m "Install React 17"

These commands solved the npm conflicts without having to manually mess with package-lock.json! You can check the branch has the correct commit history (git log -3 --pretty=oneline):

5537d91dff4d6f5f7f7d6b60c9b0a3ed027823a5 (HEAD) Install React 17
02a45a0e9043f97e133766a0679614f56fbce977 (react-16, master) Install React 16
b6e388577b3dfda16a74dcb474a708c604d5d3a9 Install React 15

TLDR

Resolve the conflict of package.json manually and run npm i --package-lock-only. You can also install npm-merge-driver which runs npm i --package-lock-only automatically on rebases.