解决合并冲突
在同一个Composer项目上进行团队协作时,你最终会遇到这样一种情况:多个人在多个分支中对composer.json和composer.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进行升级。
1. 重新应用更改
Section titled “1. 重新应用更改”合并Composer文件最安全的方法是接受一个分支的版本,然后应用另一个分支的更改。
我们有两个分支的示例:
- 已添加包“A”
- 已移除包“B”,并添加了包“C”。
要解决合并这两个分支时出现的冲突:
- 我们选择变更最多的分支,并接受该分支中的
composer.json和composer.lock文件。在这种情况下,我们选择分支2中的Composer文件。 - 我们重新应用来自另一个分支(分支1)的更改。在这种情况下,我们必须再次运行
composer require package/A。
2. 验证合并后的文件
Section titled “2. 验证合并后的文件”提交前,请确保生成的composer.json和composer.lock文件有效。为此,请运行以下命令:
php composer.phar validatephp composer.phar install [--dry-run]使用git自动解决合并冲突
Section titled “使用git自动解决合并冲突”通过使用自定义的git合并驱动程序,可以对git的冲突解决进行一些改进。
这方面的一个例子可以在balbuf的composer git合并驱动程序中找到。
处理简单情况
Section titled “处理简单情况”在少数情况下,只有content-hash会显示为冲突状态,因为版本控制系统可能能够干净地合并文件中剩余的文本。这种情况通常发生在合并的两侧添加或更新了两个不同的包,且没有重叠或冲突的依赖项时。发生这种情况时,运行composer update --lock可能足以移除冲突标记并更新锁定文件的哈希值。你也可以运行composer update的任何其他变体来移除冲突标记,并可能更新包。
重要注意事项
Section titled “重要注意事项”请记住,每当锁定文件出现合并冲突时,其中一个分支上新包被锁定的确切版本信息就会丢失。当分支1中的包A被限制为^1.2.0并锁定为1.2.0时,如果以分支2为基准并执行新的composer require package/A:^1.2.0,该包可能会被更新,因为这会在可能的情况下使用约束所允许的最新版本。此时该包可能已有1.3.0版本可用,现在就会改用这个版本。
选择正确的版本约束</b0,并确保在使用下一个重要发布运算符时,包遵循语义化版本控制</b1,这样可以确保合并分支时不会因意外更新依赖项而导致任何问题。
从错误解决的合并冲突中恢复
Section titled “从错误解决的合并冲突中恢复”如果未遵循上述步骤,并且无论如何都进行了基于文本的合并,那么你的Composer项目可能会处于一种出现意外行为的状态,因为composer.lock文件与composer.json文件(未完全)同步。
这里可能会发生两种情况:
- 在composer.json文件的require或require-dev部分存在一些包,这些包不在锁定文件中,因此从未被安装。
**注意:**从Composer 2.5版本开始,如果存在所需但未在
composer.lock中出现的包,运行install时会导致错误。
- composer.lock 文件中有一些包,它们并非任何所需包的直接或间接依赖项。因此,即使运行 composer why vendor/package 显示某个包是不需要的,该包仍然会被安装。
有几种方法可以解决这些问题;
A. 从头开始
Section titled “A. 从头开始”最简单但影响最大的选择是运行composer update,从头开始将其修复到正确状态。
这样做的一个缺点是,以前锁定的包版本现在会被更新,因为有关先前包版本的信息已经丢失。如果您的所有依赖项都遵循语义化版本控制</b0,并且您的版本约束</b1使用了下一个重要版本运算符</b2,那么这应该不是问题,否则您可能会无意中破坏您的应用程序。
B. 从git历史记录中重建
Section titled “B. 从git历史记录中重建”一种在很多情况下可能不太可行但值得一提的选择;
通过回溯git历史,找到最新的有效composer.lock文件,并从该文件重新引入新的依赖项,或许可以重建正确的包状态。
C. 手动解决问题
Section titled “C. 手动解决问题”有一种方法可以解决composer.json和composer.lock文件之间的差异,而无需深入研究git历史记录或从头开始。为此,我们需要分别解决问题1和问题2。
1. 检测并修复缺失的必需包
Section titled “1. 检测并修复缺失的必需包”要检测任何被要求但未安装的包,您只需运行:
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.htmland 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 valid2. 检测并修复多余的包
Section titled “2. 检测并修复多余的包”要检测并修复那些被锁定但并非直接/间接依赖项的包,您可以运行以下命令:
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 updatedRunning composer update vendor/package-nameLoading composer repositories with package informationUpdating dependenciesLock file operations: 0 installs, 0 updates, 1 removal - Removing vendor/package-name (1.0)Writing lock fileInstalling dependencies from lock file (including require-dev)Nothing to install, update or remove