跳转到内容

解决合并冲突

在同一个Composer项目上进行团队协作时,你最终会遇到这样一种情况:多个人在多个分支中对composer.jsoncomposer.lock文件进行了添加、更新或删除操作。当这些分支最终合并在一起时,就会产生合并冲突。解决这些合并冲突并不像处理其他文件那样简单,尤其是对于composer.lock文件而言。

注意: 基于文本的合并为何无法用于锁定文件,这一点可能并非一目了然,因此我们来设想以下场景:我们要合并两个分支。

  • 分支1已添加了需要包B的包A。包B被锁定在版本1.0.0
  • 分支2添加了包C,该包与包B所有低于1.2.0的版本存在冲突。

基于文本的合并将导致包A的版本为1.0.0、包B的版本为1.0.0以及包C的版本为1.0.0。这是一个无效的结果,因为没有考虑到包C的冲突,且这需要对包B进行升级。

合并Composer文件最安全的方法是接受一个分支的版本,然后应用另一个分支的更改。

我们有两个分支的示例:

  1. 已添加包“A”
  2. 已移除包“B”,并添加了包“C”。

要解决合并这两个分支时出现的冲突:

  • 我们选择变更最多的分支,并接受该分支中的composer.jsoncomposer.lock文件。在这种情况下,我们选择分支2中的Composer文件。
  • 我们重新应用来自另一个分支(分支1)的更改。在这种情况下,我们必须再次运行composer require package/A

提交前,请确保生成的composer.jsoncomposer.lock文件有效。为此,请运行以下命令:

php composer.phar validate
php composer.phar install [--dry-run]

通过使用自定义的git合并驱动程序,可以对git的冲突解决进行一些改进。

这方面的一个例子可以在balbuf的composer git合并驱动程序中找到。

在少数情况下,只有content-hash会显示为冲突状态,因为版本控制系统可能能够干净地合并文件中剩余的文本。这种情况通常发生在合并的两侧添加或更新了两个不同的包,且没有重叠或冲突的依赖项时。发生这种情况时,运行composer update --lock可能足以移除冲突标记并更新锁定文件的哈希值。你也可以运行composer update的任何其他变体来移除冲突标记,并可能更新包。

请记住,每当锁定文件出现合并冲突时,其中一个分支上新包被锁定的确切版本信息就会丢失。当分支1中的包A被限制为^1.2.0并锁定为1.2.0时,如果以分支2为基准并执行新的composer require package/A:^1.2.0,该包可能会被更新,因为这会在可能的情况下使用约束所允许的最新版本。此时该包可能已有1.3.0版本可用,现在就会改用这个版本。

选择正确的版本约束</b0,并确保在使用下一个重要发布运算符时,包遵循语义化版本控制</b1,这样可以确保合并分支时不会因意外更新依赖项而导致任何问题。

如果未遵循上述步骤,并且无论如何都进行了基于文本的合并,那么你的Composer项目可能会处于一种出现意外行为的状态,因为composer.lock文件与composer.json文件(未完全)同步。

这里可能会发生两种情况:

  1. 在composer.json文件的require或require-dev部分存在一些包,这些包不在锁定文件中,因此从未被安装。

**注意:**从Composer 2.5版本开始,如果存在所需但未在composer.lock中出现的包,运行install时会导致错误。

  1. composer.lock 文件中有一些包,它们并非任何所需包的直接或间接依赖项。因此,即使运行 composer why vendor/package 显示某个包是不需要的,该包仍然会被安装。

有几种方法可以解决这些问题;

最简单但影响最大的选择是运行composer update,从头开始将其修复到正确状态。

这样做的一个缺点是,以前锁定的包版本现在会被更新,因为有关先前包版本的信息已经丢失。如果您的所有依赖项都遵循语义化版本控制</b0,并且您的版本约束</b1使用了下一个重要版本运算符</b2,那么这应该不是问题,否则您可能会无意中破坏您的应用程序。

一种在很多情况下可能不太可行但值得一提的选择;

通过回溯git历史,找到最新的有效composer.lock文件,并从该文件重新引入新的依赖项,或许可以重建正确的包状态。

有一种方法可以解决composer.jsoncomposer.lock文件之间的差异,而无需深入研究git历史记录或从头开始。为此,我们需要分别解决问题1和问题2。

要检测任何被要求但未安装的包,您只需运行:

php composer.phar validate

如果存在需要但未安装的包,你应该会得到类似如下的输出:

./composer.json is valid but your composer.lock has some errors
# Lock file errors
- Required package "vendor/package-name" is not present in the lock file.
This usually happens when composer files are incorrectly merged or the composer.json file is manually edited.
Read more about correctly resolving merge conflicts resolving-merge-conflicts.html
and prefer using the "require" command over editing the composer.json file directly cli.html#require

要解决此问题,只需为这里列出的每个包运行composer update vendor/package-name。为这里列出的每个包执行此操作后,再次运行composer validate应该不会出现锁文件错误:

./composer.json is valid

要检测并修复那些被锁定但并非直接/间接依赖项的包,您可以运行以下命令:

php composer.phar remove --unused

如果没有锁定非依赖项的包,该命令将有以下输出:

No unused packages to remove

如果有需要清理的包,输出将如下所示:

vendor/package-name is not required in your composer.json and has not been removed
./composer.json has been updated
Running composer update vendor/package-name
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 0 updates, 1 removal
- Removing vendor/package-name (1.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove