package.json 中的波浪号(~)和插入符号(^)有啥区别?

Posted

技术标签:

【中文标题】package.json 中的波浪号(~)和插入符号(^)有啥区别?【英文标题】:What's the difference between tilde(~) and caret(^) in package.json?package.json 中的波浪号(~)和插入符号(^)有什么区别? 【发布时间】:2021-06-17 02:01:21 【问题描述】:

在我升级到最新的稳定版nodenpm 后,我尝试了npm install moment --save。它使用插入符号 ^ 前缀将条目保存在 package.json 中。以前,它是一个波浪号 ~ 前缀。

    为什么在 npm 中进行这些更改? 波浪号~ 和插入符号^ 有什么区别? 与其他人相比有什么优势?

【问题讨论】:

仅供参考,您可以通过以下方式阻止前缀或使用自定义前缀:npm config set save-prefix=''。 (如果您愿意,请在引号中加上 ~。)我个人会这样做并为生产中的东西收缩包装。 关于波浪号和插入符号如何工作和差异的所有细节:github.com/npm/node-semver#tilde-ranges-123-12-1 这个工具是测试semver.npmjs.com的好帮手 Semantic versioning 在 npm 和节点中 npm shrinkwrap 和 package-lock.json vs npm-shrinkwrap.json #toSaveYouAGoogle(或两个)的文档 -- fncomp 提到了 above 和 tehfoo below。此外,助记符:~ 保持均匀,^ 上升一点。 【参考方案1】:

参见NPM docs 和semver docs:

~version “大约相当于版本”,将更新您到所有未来的补丁版本,而不增加次要版本。 ~1.2.3 将使用从 1.2.3 到

^version “与版本兼容”,将更新您到所有未来的次要/补丁版本,而不增加主要版本。 ^2.3.4 将使用从 2.3.4 到

请参阅下面的评论了解例外情况,尤其是for pre-one versions, such as ^0.2.3

【讨论】:

在这里发帖希望能抓住那些不太想通的人,但 ^ 和 ~ 都假设您可以信任依赖项中的次要版本和点版本。如果您正在发布图书馆并希望其他人信任您,请不要盲目接受下游依赖项。从你的依赖中释放一个坏点会导致上游的连锁反应,当事情变成梨形时,人们会敲你的门。这是在生产代码中使用 npm shrinkwrap 的另一个重要原因。 你也可以去掉所有在你的版本前加上^~的废话。如果您想严格控制您的版本,请设置此选项:npm config set save-prefix='' @prasanthv 是对的:来自docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4:插入符号范围^1.2.3 ^0.2.5 ^0.0.4。允许不修改 [major, minor, patch] 元组中最左边的非零数字的更改。换句话说,这允许对 1.0.0 及更高版本进行补丁和次要更新,对 0.X >=0.1.0 版本进行补丁更新,对 0.0.X 版本不进行更新。 @jgillich 在 semver 中使用 0.2.x2 不是 major version。这就是docs.npmjs.com 使用特定词的原因:the left-most non-zero digit。这种情况又如何:^0.0.4 表示 0.0.4 @FagnerBrack:您提供的具体示例是正确的,但通常您的思维方式是错误的。一个例子:假设你有 3 个版本的包 A0.0.10.0.20.0.30.0.1 中有一个错误,所以你希望在你的包 B 中至少有 0.0.2。如果你写0.0.x,你会得到0.0.3,这没关系。但是,如果某个其他包 C 需要 BA 并且还具有约束 "A": "<0.0.2" 您将获得 0.0.1 而不会显示任何冲突问题,这不是您想要的。使用波浪号 ~0.0.2 应该可以帮助您避免这个问题。【参考方案2】:

我还想添加官方 npmjs 文档,其中描述了版本特异性的所有方法,包括问题中提到的方法

value desc
~version "Approximately equivalent to version" See npm semver - Tilde Ranges
^version "Compatible with version" See npm semver - Caret Ranges
version Must match version exactly
>version Must be greater than version
>=version etc
<version
<=version
1.2.x 1.2.0, 1.2.1, etc., but not 1.3.0
* Matches any version
latest Obtains latest release

以上列表并不详尽。其他版本说明符包括 GitHub url 和 GitHub 用户 repo、本地路径和带有特定 npm 标签的包

官方文档

npm docs > package.json > dependencies npm docs > semver > versions semver (7)

【讨论】:

也可以指定一个精确的版本范围,比如1.2.0 || >=1.2.2 <1.3.0:完全是1.2.0,或者从1.2.2到1.3.0(含)的所有版本,但不是1.2.1,或 1.3.1 及更高版本,也不是 1.1.x 及更低版本。 上面的更具体的链接-> docs.npmjs.com/files/package.json#dependencies "Approximately equivalent to version""Compatible with version" 是描述 ~ 和 ^ 行为的令人沮丧的非特定方式。感谢@jgillich 提供实际答案! 另一个资源:nodejs.dev/learn/semantic-versioning-using-npm @Timo “从不依赖版本的部门”可能不存在。您可以拥有不当前依赖于版本的dep,但不保证未来版本的依赖项向后兼容,因此除非您拥有依赖项以及应用程序,否则可以肯定的是,最终“最新”将不起作用。对我来说,“最新”说明符的最佳用途似乎是在早期开发、概念验证或不会长期维护的短期项目中。【参考方案3】:

npm 允许安装比指定版本更新的软件包。使用波浪号 (~) 为您提供错误修复版本,插入符号 (^) 也为您提供向后兼容的新功能。

问题是旧版本通常不会收到那么多错误修复,因此 npm 使用插入符号 (^) 作为 --save 的默认值。

根据:"Semver explained - why there's a caret (^) in my package.json?".

注意,这些规则适用于 1.0.0 以上的版本,并不是每个项目都遵循语义版本控制。对于 0.x.x 版本,插入符号仅允许 patch 更新,即它的行为与波浪号相同。见"Caret Ranges"

以下是概念的直观解释:

来源:"Semantic Versioning Cheatsheet"。

【讨论】:

^0.2.5 怎么样?来自docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4:插入符号范围^1.2.3 ^0.2.5 ^0.0.4。允许不修改 [major, minor, patch] 元组中最左边的非零数字的更改。换句话说,这允许对 1.0.0 及更高版本进行补丁和次要更新,对 0.X >=0.1.0 版本进行补丁更新,对 0.0.X 版本不进行更新。 @rofrol 1.0.0 之前的任何版本都被认为是不稳定的,这些规则不适用 所以你的解释不完整 @rofrol 是的,省略可读性有时很好,对于包 json 中的依赖项,低于 1.0.0 的可能性非常低。另请参阅 20/80 原则,这是专注于重要事项的重要规则 @pspi 低于 1.0.0 的版本“不太可能”?在 60 个中,我们有大约 15 个,其中大多数并不晦涩。【参考方案4】:

服务器

<major>.<minor>.<patch>-beta.<beta> == 1.2.3-beta.2
使用npm semver calculator 进行测试。尽管对 ^(包括大于同一主要范围内的特定版本的所有内容)和 ~(包括大于同一次要范围内的特定版本的所有内容)的解释不是 100% 正确,但计算器似乎工作正常。 或者,使用SemVer Check 代替,这不需要您选择包并且还提供解释。

允许或禁止更改

引脚版本:1.2.3。 使用^(如head)。允许在左起第二个非零级别进行更新:^0.2.3 表示 0.2.3 &lt;= v &lt; 0.3。 使用~(如tail)。通常冻结最右边的级别或如果省略则设置为零: ~1 表示 1.0.0 &lt;= v &lt; 2.0.0 ~1.2 表示1.2.0 &lt;= v &lt; 1.3.0~1.2.4 表示1.2.4 &lt;= v &lt; 1.3.0。 省略最右边的级别:0.2 表示0.2 &lt;= v &lt; 1。不同于~,因为: 起始省略级别版本始终为0 您可以在不指定子级别的情况下设置起始主版本。

所有(希望的)可能性

设置起始主级别并允许向上更新

*  or "(empty string)   any version
1                         v >= 1

冻结主要级别

~0 (0)            0.0 <= v < 1
0.2               0.2 <= v < 1          // Can't do that with ^ or ~ 
~1 (1, ^1)        1 <= v < 2
^1.2              1.2 <= v < 2
^1.2.3            1.2.3 <= v < 2
^1.2.3-beta.4     1.2.3-beta.4 <= v < 2

冻结次要级别

^0.0 (0.0)        0 <= v < 0.1
~0.2              0.2 <= v < 0.3
~1.2              1.2 <= v < 1.3
~0.2.3 (^0.2.3)   0.2.3 <= v < 0.3
~1.2.3            1.2.3 <= v < 1.3

冻结补丁级别

~1.2.3-beta.4     1.2.3-beta.4 <= v < 1.2.4 (only beta or pr allowed)
^0.0.3-beta       0.0.3-beta.0 <= v < 0.0.4 or 0.0.3-pr.0 <= v < 0.0.4 (only beta or pr allowed)
^0.0.3-beta.4     0.0.3-beta.4 <= v < 0.0.4 or 0.0.3-pr.4 <= v < 0.0.4 (only beta or pr allowed)

禁止更新

1.2.3             1.2.3
^0.0.3 (0.0.3)    0.0.3

注意:缺少major、minor、patch或指定beta不带编号,与缺少级别的any相同。

注意:当您安装以0 为主要级别的软件包时,更新只会安装新的 beta/pr 级别版本!那是因为npmpackage.json 中将^ 设置为默认值,并且当安装的版本类似于0.1.3 时,它会冻结所有主要/次要/补丁级别。

https://docs.npmjs.com/misc/semver https://docs.npmjs.com/files/package.json#dependencies

【讨论】:

告诉人们避免从 0 开始项目,因为库和消费开发人员不了解系统是一个糟糕的解决方案。我认为@asdfasdfads 有更好的信息。 @ProLoser 我只是觉得应该简化系统,我们不应该使用0.x版本。 早期生命周期开发和 v0 的用例非常有意义。了解 v0 如何正常运行实际上让我对其他早期生命周期项目充满期待。这意味着您可以拥有一个具有大量向后不兼容的快速变化的 API,而不必在实际上不是时将您的项目声明为 1.x(又名:稳定)。 我理解,但我只是不喜欢它如何与 semver 和限定符一起使用 感觉更像是一种意见,不应被视为普遍接受的方法。而且 ^0.1.x 可以完美地获得补丁。【参考方案5】:

只要第一个数字(“主要”)至少为 1:

~ 锁定主要和次要号码。当您准备好只接受错误修复(第三个数字的增量),但不想要任何其他更改,甚至不想要添加功能的小升级时,使用它。

^ 只锁定主号码。当您愿意接收错误修复(第三个数字的增量)和添加功能但不应破坏现有代码的小升级(第二个数字的增量)时,使用它。但是,您不希望更改会破坏现有代码(第一个数字的增量)。

除此之外,^ 在旧 npm 版本中是 not supported,应谨慎使用。

所以,^ 是一个很好的默认值,但它并不完美。我建议仔细挑选和配置对您最有用的 semver 运算符。

(为了避免使用“fixes”冲突,避免说“fixes”和“bug-fixes”,这是令人困惑的)

【讨论】:

不正确:插入符号范围 ^1.2.3 ^0.2.5 ^0.0.4。允许不修改 [major, minor, patch] 元组中最左边的非零数字的更改。换言之,这允许对 1.0.0 及更高版本进行补丁和次要更新,对 0.X >=0.1.0 版本进行补丁更新,对 0.0.X 版本不进行更新。 docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4 这个答案是完全错误的(就像这里的许多其他人一样)。这些都没有修复主要数字!正如@rofrol 所说, ^ 只是保持最左边的非零数字不变。 ~ 另一方面,如果指定了次要版本(例如 ~1.2.3 或 ~1.2),则只允许补丁更新,如果未指定次要版本(例如 ~1),则允许次要更新。 @TheBaj 他们的意思是“修复”为“定义”(“固定”)而不是“调整”,所以你们都同意如何处理主要数字。 是的,这个答案似乎完全倒退了,直到我意识到回答者的意思是“修复”,如“使固定、静止或不变”。【参考方案6】:

~:合理地接近

   ~1.1.5: 1.1.0 <= accepted < 1.2.0

^兼容

   ^1.1.5: 1.1.5 <= accepted < 2.0.0

   ^0.1.3: 0.1.3 <= accepted < 0.2.0

   ^0.0.4: 0.0.4 <= accepted < 0.1.0

【讨论】:

@kytwb - 没有。在第零个版本号的特殊情况下,克拉等于波浪号。因此^0.1.3 只接受版本0.1.x 而不会接受0.2.0,即使这是一个小的增量。此行为等效于~0.1.3。这种行为背后的原因是零版本的包仍然被认为是不稳定的。用semver.org 的话来说,#4,“任何事情都可能随时改变”(包括向后不兼容的改变)。【参考方案7】:

^ 是 1.[any].[any](最新次要版本)~ 是 1.2.[any](最新补丁)

关于 semver 如何应用于 npm 以及他们正在做什么以使其匹配the semver standardhttp://blog.npmjs.org/post/98131109725/npm-2-0-0

【讨论】:

不正确:插入符号范围 ^1.2.3 ^0.2.5 ^0.0.4。允许不修改 [major, minor, patch] 元组中最左边的非零数字的更改。换句话说,这允许版本 1.0.0 及更高版本的补丁和次要更新,版本 0.X >=0.1.0 的补丁更新,以及版本 0.0.X 的不更新。 docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4【参考方案8】:

~波浪号:

~ 冻结主要和次要号码。 当您准备好接受依赖项中的错误修复时使用它, 但不希望有任何可能不兼容的更改。 波浪号与最新的次要版本(中间数字)匹配。 ~1.2.3 将匹配所有 1.2.x 版本,但会错过 1.3.0。 波浪号 (~) 为您提供错误修复版本

^ 插入符号:

^ 仅冻结主号码。 当您密切关注您的依赖关系并准备好在次要版本不兼容时快速更改您的代码时使用它。 它会将您更新到最新的主要版本(第一个数字)。 ^1.2.3 将匹配包括 1.3.0 在内的任何 1.x.x 版本,但在 2.0.0 上会延迟。 插入符号 (^) 还为您提供向后兼容的新功能。

【讨论】:

波浪号匹配最新的补丁版本(最后一个数字)。插入符号匹配最新的次要版本(中间数字)。 “冻结”是最好的解释。 插入符号既冻结了主编号,又会将您更新到最新的主版本(第一个编号)?主要数字是第一个数字,所以这没有意义。【参考方案9】:

帽子匹配可能被视为“损坏”,因为它不会将^0.1.2 更新为0.2.0。当软件出现时,使用0.x.y 版本,帽子匹配将只匹配最后一个变化的数字(y)。这是故意的。原因是在软件不断发展的同时,API 也在迅速变化:前一天你拥有这些方法,而前一天你拥有这些方法,而旧的方法已经消失了。如果您不想破坏已经在使用您的库的人的代码,您可以增加主要版本:例如1.0.0 -> 2.0.0 -> 3.0.0。所以,当你的软件最终 100% 完成并功能齐全时,它会像版本 11.0.0 一样,看起来没有多大意义,实际上看起来很混乱。另一方面,如果您使用的是 0.1.x -> 0.2.x -> 0.3.x 版本,那么当软件最终 100% 完成并功能齐全时,它会作为版本 1.0.0 发布,这意味着“这个版本是一个长期服务版本,你可以在你的生产代码中继续使用这个版本的库,作者明天或下个月不会改变一切,他也不会放弃这个包”。

规则是:在您的软件尚未成熟时使用 0.x.y 版本控制,并在您的公共 API 更改时以增加中间数字的方式发布它(因此拥有 ^0.1.0 的人将不会获得 0.2.0 更新和它不会破坏他们的代码)。然后,当软件成熟时,在1.0.0 下发布它,并在每次公共 API 更改时增加最左边的数字(因此拥有^1.0.0 的人不会得到2.0.0 更新,也不会破坏他们的代码)。

Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.

【讨论】:

这条评论非常有用,而且似乎没有很好地记录下来。您是否有指向有关此行为的文档的链接?这个关于 v0 项目的答案对我帮助很大。 我没有链接:我也通过谷歌搜索和玩 npm 语义版本计算器semver.npmjs.com找到了这个信息 需要以更正式的方式添加到他们的文档中。我在索尼给我的工程团队做了一次演讲,因为它似乎很容易被忽视。 slides.com/proloser/semver-v0【参考方案10】:

单线解释

标准版本控制系统是major.minor.build(例如2.4.1)

npm 根据这​​些字符检查并修复特定包的版本

~ : 主要版本固定,次要版本固定,匹配任何内部版本号

例如: ~2.4.1 意味着它将检查 2.4.x 其中 x 是什么

^ : 主要版本是固定的,匹配任何次要版本,匹配任何内部版本号

例如: ^2.4.1 表示它将检查 2.x.x 其中 x 是什么

【讨论】:

我在这个答案中看到 7 行【参考方案11】:

Tilde ~ 匹配次要版本,如果您安装了具有 1.4.2 的软件包,并且在安装后,如果您的 package.json 中有 1.4.3 和 1.4.4 版本也可用用作 ~1.4.2 然后 npm install 在您的项目中升级后将在您的项目中安装 1.4.4。但是该软件包有 1.5.0 可用,那么它不会被 ~ 安装。它被称为次要版本。

Caret ^ 匹配主要版本,如果您的项目中安装了 1.4.2 包,并且在您的安装后 1.5.0 发布,那么 ^ 将安装主要版本。如果您有 ^1.4.2,它将不允许安装 2.1.0。

固定版本如果您不想在每次安装时更改软件包的版本,请使用不带任何特殊字符的固定版本,例如 "1.4.2"

最新版本 * 如果你想安装最新版本,那么只在包名前使用 *。

【讨论】:

这个答案具有误导性。 SemVer 明确指出,正常版本号必须采用 X.Y.Z 的形式 [其中] X 是主要版本,Y 是次要版本,Z 是补丁版本。【参考方案12】:

您可能已经在 package.json 中看到了波浪号 (~) 和插入符号 (^)。它们有什么区别?

当您执行 npm install moment --save 时,它​​会使用插入符号 (^) 前缀保存 package.json 中的条目。

波浪号 (~)

用最简单的术语来说,波浪号 (~) 匹配最新的次要版本(中间的数字)。 ~1.2.3 将匹配所有 1.2.x 版本,但会错过 1.3.0。

插入符号 (^)

另一方面,插入符号 (^) 更轻松。它会将您更新到最新的主要版本(第一个数字)。 ^1.2.3 将匹配任何 1.x.x 版本,包括 1.3.0,但会推迟到 2.0.0。

参考:https://medium.com/@Hardy2151/caret-and-tilde-in-package-json-57f1cbbe347b

【讨论】:

同样,这个答案具有误导性。 SemVer 明确指出,正常版本号必须采用 X.Y.Z 的形式 [其中] X 是主要版本,Y 是次要版本,Z 是补丁版本。【参考方案13】:

semver 分为 3 个主要部分,由点分隔。

major.minor.patch
1.0.0

这些不同的主要、次要和补丁用于标识不同的版本。 潮汐 (~) 和插入符号 (^) 用于标识要在包版本控制中使用的次要版本和补丁版本。

~1.0.1
 Install 1.0.1 or **latest patch versions** such as 1.0.2 ,1.0.5
^1.0.1
 Install 1.0.1 or **latest patch and minor versions** such as 1.0.2 ,1.1.0 ,1.1.1

【讨论】:

【参考方案14】:

caret ^ 包括比同一主要范围内的特定版本更大的所有内容。

波浪号 ~ 包含比特定版本更高的所有内容。

例如,要指定最高 1.0.4 的可接受版本范围,请使用以下语法:

补丁版本:1.0 或 1.0.x 或 ~1.0.4 次要版本:1 或 1.x 或 ^1.0.4 主要版本:* 或 x

有关语义版本控制语法的更多信息,请参阅npm semver calculator。

更多来自 npm 文档About semantic versioning

【讨论】:

【参考方案15】:

波浪号 (~)

主要版本是固定的,次要版本是固定的,匹配任何构建 号码

"express": "~4.13.3" 

~4.13.3 表示它将检查 4.13.x 其中 x 是任何东西和 4.14.0

插入符号 (^)

主要版本是固定的,匹配任何次要版本,匹配任何构建 号码

"supertest": "^3.0.0"

^3.0.0 表示它将检查 3.x.x 其中 x 是什么

【讨论】:

您能否详细说明此答案与the same answer posted 4 years ago 有何不同?【参考方案16】:

版本号在语法中指定具有不同含义的每个部分。语法分为三个部分,用点分隔。

major.minor.patch 1.0.2

主要、次要和补丁代表一个包的不同版本。

npm 使用波浪号 (~) 和插入符号 (^) 分别指定要使用的补丁和次要版本。

因此,如果您看到 ~1.0.2,则表示安装版本 1.0.2 或最新的补丁版本,例如 1.0.4。如果您看到 ^1.0.2,则表示安装版本 1.0.2 或最新的次要版本或补丁版本,例如 1.1.0。

【讨论】:

您能否详细说明此答案与the same answer posted 4 years ago 有何不同?【参考方案17】:

与这个问题相关的你可以查看Composer documentation on versions,但这里简而言之:

波浪号版本范围 (~) - ~1.2.3 相当于 >=1.2.3 1.3.0 插入符号版本范围 (^) - ~1.2.3 相当于 >=1.2.3 2.0.0

因此,使用 Tilde 您将获得补丁的自动更新,但不会更新次要和主要版本。但是,如果您使用 Caret,您将获得补丁和次要版本,但不会获得主要(重大更改)版本。

波浪号版本被认为是“更安全”的方法,但如果您使用可靠的依赖项(维护良好的库),则插入符号版本应该没有任何问题(因为微小的更改不应该是破坏性更改。

您可能应该查看this *** post about differences between composer install and composer update。

【讨论】:

【参考方案18】:

本身并不是一个答案,而是一个似乎被忽视的观察结果。

插入符号范围的说明:

见:https://github.com/npm/node-semver#caret-ranges-123-025-004

允许不修改最左边非零数字的更改 [主要、次要、补丁] 元组。

表示^10.2.3 匹配10.2.3 &lt;= v &lt; 20.0.0

我不认为这就是他们的意思。引入 11.x.x 到 19.x.x 版本会破坏您的代码。

我认为他们的意思是left most non-zero number field。 SemVer 中没有任何内容要求数字字段为一位数。

【讨论】:

请注意,在此期间,措辞是固定的:Allows changes that do not modify the left-most non-zero element【参考方案19】:

波浪号~ 指定次要版本

Caret ^ 指定主要版本发布

例如,如果包版本是4.5.2,则更新时:

~4.5.2 将安装最新的4.5.x version (MINOR VERSION)

^4.5.2 将安装最新的4.x.x version (MAJOR VERSION)

【讨论】:

您能否详细说明此答案与the same answer posted 4 years ago 有何不同?

以上是关于package.json 中的波浪号(~)和插入符号(^)有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

package.json 中的波浪号(~)和插入符号(^)有啥区别?

package.json 中的波浪号(~)和插入符号(^)有啥区别?

npm生成的package.json文件中依赖项版本号前的波浪号(~)和插入符号(^)是啥意思?

package.json 安装插件时版本号前缀解析

package.json中的 ^与~

package.json 版本解释