2016-02-29

composer.lock: Why you need it and why it should be kept in version control

Composer is a dependency manager for PHP, used by many projects, most notably the Symfony PHP framework. It allows developers to specify which dependencies a project has by creating a composer.json file. When composer is run with "composer install", it uses the composer.json file to find out which versions of the dependencies to get. I do not want to get into too much detail regarding how version constraints can be specified in the composer.json file. If you are interested, there is a detailed manual on versions for Composer. Suffice to say that you usually do not want to specify a fixed version, but instead want to specify a minimum version so that your software can be updated to use newer versions of your dependencies.

The problem with this approach should already be apparent: When you create the project or checkout the project from source control and run "composer install", you will get the newest compatible versions of the dependencies which are available at the time you run the command. However, when another developer checks out the code, the same will happen to him, only that by then there could be a newer version than what you have. It is possible, that this newer version is incompatible with your project, which you did not anticipate when defining the version constraints in the composer.json file. So now the other developer can not get your project working because the dependency fails and, being new on the project, has no idea how to fix it. You, on the other hand, are happily coding on your checked out copy of the code which uses the old version of the dependencies and will never be aware of the problem.

The gist of this example is that it is bad practice to use different versions of dependencies among developers. You want all developers to use the same version of the dependencies to get reproducible results for all checked out copies of your code. The Composer folks were aware of this problem and created composer.lock to ensure this.

When you run "composer install" for the first time, Composer will find the newest compatible version of your dependencies and install them. It will then generate the composer.lock file which contains information about the exact version which was installed so that it is possible to restore this state on your machine and on other machines. So unlike the composer.json file, the composer.lock file contains specific versions numbers for all your dependencies. The next time you or someone else runs "composer install", Composer will try to find the composer.lock file and install the version of the dependencies specified in there.

Now it should also be obvious why you should add the composer.lock file to version control: By sharing this file, you let all other developers know which versions of the dependencies you have installed and tested your code with. They will now no longer need to fix possible bugs which might happen with newer versions of your dependencies.

So why should you not specify exact version constraints directly in your composer.json file? Well, this file is used to specify which versions your software should be compatible with, so which versions it should be safe to upgrade to. If you specify version constraints correctly and all your dependencies obey semantic versioning rules, you can run "composer update" to get the newest compatible version for each dependency as specified in the composer.json file. Note that this does not read the composer.lock file, but instead updates it with the new exact version numbers you are now using. After you have tested and verified everything still works, you can commit your updated composer.lock file to the repository. All other developers can then run "composer install" again to use the same versions as you.

No comments:

Post a Comment