Skip to content

Instantly share code, notes, and snippets.

@szemate
Last active March 28, 2024 13:37
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save szemate/6fb69c8e3d8cce3efa9a6c922b337d98 to your computer and use it in GitHub Desktop.
Save szemate/6fb69c8e3d8cce3efa9a6c922b337d98 to your computer and use it in GitHub Desktop.
How to resolve package-lock.json conflicts

How to resolve package-lock.json conflicts

It is not possible to resolve conflicts of package-lock.json in GitHub's merge tool and you need to do a manual merge.

  1. Update the master branch with the latest changes:
    git checkout master
    git pull
    
  2. Merge your feature branch into master:
    git merge mybranch
    
    You will see something like the following message:
    Auto-merging package-lock.json
    CONFLICT (content): Merge conflict in package-lock.json
    Auto-merging package.json
    CONFLICT (content): Merge conflict in package.json
    Automatic merge failed; fix conflicts and then commit the result.
    
  3. Open your editor (e.g. VSCode) and:
    • Carefully resolve conflicts in package.json (if there is any)
    • Ignore the conflicts in package-lock.json
  4. Install packages, which will re-generate package-lock.json:
    npm install
    
  5. "Test drive" your application to make sure the conflicts in package.json have been resolved correctly.
  6. If the application is able to start up (i.e. there are no missing dependencies), add all changes and finish the merge:
    git add --update
    git commit
    
    ⚠️ Make sure not to commit the *.orig files!
  7. If everything looks fine, push to GitHub:
    git push
    
@AbhiKansana
Copy link

Thank you so much. I was thinking about how even I can resolve conflicts in package-lock.json

@mcthuggets
Copy link

Thanks for this!

Our package-lock.json is scary big. It's nice to know that I don't have to handle any of that by hand.

@AmirDiafi
Copy link

Thanks @szemate

@DaveVodrazka
Copy link

But if your package.json looks something like this:

{
  "dependencies": { "some-package": "^1.2.0" }
}

and you are using some-package version 1.2.0, using this method, it may get bumped to any 1.x.x version, something like 1.5.8.

Now, version 1.5.8 may introduce some problematic changes, which you don't want to add if you are not directly bumping some-package.

So the question is how to resolve package-lock.json conflicts, without changing version of any package that was not directly changed with the changes that let to the conflict?

@szemate
Copy link
Author

szemate commented Sep 23, 2022

@DaveVodrazka this method doesn't change the contents of package.json, it only changes package-lock.json that is basically a list of the dependencies of your dependencies. If two of those require different versions of some package, both versions will be installed, and each of your dependencies will use the version that they require. The version numbers that you specify in package.json won't be altered.

@cjones26
Copy link

@szemate I agree with @DaveVodrazka, if we regenerate the package-lock.json this way, don't we simply lose all benefit of it?

Say for example, I have a dependency which as, in turn, an unlocked transient dependency which uses semver to pull the latest minor version. When my package-lock.json is first generated, the transient dependency could be, for instance, 5.0.8...when regenerating the package-lock.json, if the latest version is 5.10.0, then our package-lock.json file will now have 5.10.0 listed as the dependency of the dependency.

Hope that makes sense.

@DaveVodrazka
Copy link

Here is a step by step example, that should make it extra clear:

Problem

My library has three dependencies, package a, b and c. My package.json looks like this:

{
  "a": "^1.0.0",
  "b": "^1.0.0",
  "c": "^1.0.0"
}

and my package-lock.json looks like this (notice missing ^):

{
  "a": "1.0.0",
  "b": "1.0.0",
  "c": "1.0.0"
}

This means, that all three dependencies are "locked" at version 1.0.0.

Now, some time has gone by and maintainers of my dependencies have published newer versions. In the npm repository the latest versions are now a: 1.2.1, b: 1.3.4 and c: 1.0.7.

I need to bump package c to version 1.0.7 to fix some bug. I run npm install c and merge changes. package.json now looks like this:

{
  "a": "^1.0.0",
  "b": "^1.0.0",
  "c": "^1.0.7"
}

and pakcage-lock.json like this:

{
  "a": "1.0.0",
  "b": "1.0.0",
  "c": "1.0.7"
}

Someone else decides to bump package b to fix a different bug. They checkout their own branch and run npm install b, which bumps pakcage b to 1.3.4. Their package.json looks like this:

{
  "a": "^1.0.0",
  "b": "^1.3.4",
  "c": "^1.0.0"
}

and pakcage-lock.json like this:

{
  "a": "1.0.0",
  "b": "1.3.4",
  "c": "1.0.0"
}

They try to merge, but run into a conflict. They easily resolve conflict in package.json like this:

{
  "a": "^1.0.0",
  "b": "^1.3.4",
  "c": "^1.0.7"
}

So that both package b and c are at the appropriate version. All that is left to do is to resolve conflict in the package-lock.json.

And this is where we run into the problem, because the package-lock.json that we should have locks versions like this:

{
  "a": "1.0.0",
  "b": "1.3.4",
  "c": "1.0.7"
}

But if you were to run npm install now, the pakcage-lock.json you'd end up with would lock these versions:

{
  "a": "1.2.1",
  "b": "1.3.4",
  "c": "1.0.7"
}

Notice that, while nobody bumped package a, we ended up with a new version "a": "1.2.1".

Explanation

Now why is that? Since the version in our package.json is set to "a": "^1.0.0", the ^ symbols tells npm to keep both minor and patch version up to date, ie. if there is newer minor or patch version, it will be downloaded and updated in package-lock.json.

Theoretically, this should not be a problem, because patch should never break anything and minor version update should always be backwards compatible, but since versioning is done by people and people are prone to making mistakes - this does not always hold true.

This is why running npm install to resolve package-lock.json conflits is not a bulletproof strategy.

I don't have a better solution and I do use this way of fixing the conflicts, but you should be aware of potential problems this may introduce.

@cjones26
Copy link

cjones26 commented Sep 28, 2022

@DaveVodrazka 👏 bravo--excellent explanation.

In regards to this entire conversation, I posed a similar question regarding the maintenance of package-lock.json files to a contributor of npm ~2 weeks ago here: npm/cli#4844 (comment).

Since npm v6 there is no longer any mention about how to resolve lockfile conflicts within the npm documentation, though it appears the appropriate solution is to utilize something like parse-conflict-json. I haven't looked into it much but it may be the solution we are all looking for, it would just be helpful is the npm team would actually codify some of this in their documentation.

@cjones26
Copy link

@DaveVodrazka I've also opened a feedback suggestion with the npm team which you may be interested in: npm/feedback#777.

@wtfiwtz
Copy link

wtfiwtz commented Aug 31, 2023

You can do "accept all current" or "accept all inbound changes" in vscode
https://stackoverflow.com/questions/52288120/how-can-i-accept-all-current-changes-in-vscode-at-once

@waqartargaryen
Copy link

This is such a life saviour. Thank you. 🙏🏽

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment