ChatGPT解决这个技术问题 Extra ChatGPT

Should composer.lock be committed to version control?

I'm a little confused with composer.lock used in an application with a repository.

I saw many people saying that we should not .gitignore composer.lock from the repository.

If I update my libraries in my dev environment, I will have a new composer.lock but I will not be able to update them into production, will I ?

Won't it generate conflicts on this file ?

That link is now dead @markus
Short answer: Yes, commit composer.lock. There are reasons to not commit it, but if you're reading this question, they probably don't apply to you.
If your composer.lock is not in .gitignore, first : add it to .gitignore file, second : delete this file from repository, end : pull from repository. In this case, composer.lock committed to repository before. When there is file in repository, you can not ignore it, and so must be commit its changes.

m
meza

If you update your libs, you want to commit the lockfile too. It basically states that your project is locked to those specific versions of the libs you are using.

If you commit your changes, and someone pulls your code and updates the dependencies, the lockfile should be unmodified. If it is modified, it means that you have a new version of something.

Having it in the repository assures you that each developer is using the same versions.


Ok but imagine if I update the libraries from the production environment, composer.lock will be overwritten so a next pull from the production will ask me to merge this file...
If the composer.lock gets modified, you need to push the modifications back to the repository. If you want to tie the software to given versions of the libraries, then do so explicitly in the configuration. That way the lock will never change. Think of the lock file as an indicator of a dependency management issue which needs to be resolved one way or the other.
In production you should not update your dependencies, you should run composer install which will read from the lock file and not change anything.
"In production you should not update your dependencies" should be written in all caps
@JoaquínL.Robles IN PRODUCTION YOU SHOULD NOT UPDATE YOUR DEPENDENCIES! :)
F
Francesco Casula

For applications/projects: Definitely yes.

The composer documentation states on this (with emphasis):

Commit your application's composer.lock (along with composer.json) into version control.

Like @meza said: You should commit the lock file so you and your collaborators are working on the same set of versions and prevent you from sayings like "But it worked on my computer". ;-)

For libraries: Probably not.

The composer documentation notes on this matter:

Note: For libraries it is not necessarily recommended to commit the lock file (...)

And states here:

For your library you may commit the composer.lock file if you want to. This can help your team to always test against the same dependency versions. However, this lock file will not have any effect on other projects that depend on it. It only has an effect on the main project.

For libraries I agree with @Josh Johnson's answer.


Why treat projects at work differently from "libraries"?
Perhaps the use of the word "coworkers" was confusing here, I changed it to collaborators. The main difference is "main project" vs library, in which a main project consists of one or more libraries and code to integrate those. When running composer from the main project it doesn't use a library's composer.lock file, so it installs its dependencies at the latest version. I think this should be similar when testing your library.
Committing the lock-file with a library is probably a good thing - the lock-file documents which versions of dependencies were installed when the test-suite was run. That's particularly important in a team, and especially in continuous integration environments.
@tonix, I can answer this with some authority! The reason I don't commit composer.lock for my libraries is that my CI builds master every night no matter what. It guarantees that if any of the library's dependencies have upgrade problems a user of the library would have, that the CI fails. Works good!
@TheodoreR.Smith then you should commit and push your composer.lock from you CI system so that the version you ran CI with is the version that your dependencies are locked to. composer.lock is about repeatability and if your CI worked then you'll want that documented. Of course, if you are always packaging up your vendor folder from CI and deploying it with your code, then you don't need composer.lock at all.
J
Josh Johnson

After doing it both ways for a few projects my stance is that composer.lock should not be committed as part of the project.

composer.lock is build metadata which is not part of the project. The state of dependencies should be controlled through how you're versioning them (either manually or as part of your automated build process) and not arbitrarily by the last developer to update them and commit the lock file.

If you are concerned about your dependencies changing between composer updates then you have a lack of confidence in your versioning scheme. Versions (1.0, 1.1, 1.2, etc) should be immutable and you should avoid "dev-" and "X.*" wildcards outside of initial feature development.

Committing the lock file is a regression for your dependency management system as the dependency version has now gone back to being implicitly defined.

Also, your project should never have to be rebuilt or have its dependencies reacquired in each environment, especially prod. Your deliverable (tar, zip, phar, a directory, etc) should be immutable and promoted through environments without changing.


Agreed. I feel it makes more sense to specify dependency versions in composer.json where the required versions are more explicitly stated. But if you don't set specific versions, better to commit the composer.lock. It's confusing if the versions specified in composer.json are different than those installed as per a composer.lock. Also it depends on the app (in-house or general release) and its dev cycle. Of course, the composer docs do say, in bold, "Commit your application's composer.lock (along with composer.json) into version control". Choose wisely =)
After much soul searching I've decided, on this point, the composer docs are wrong :) I have a rule that I don't add generated material to the VCS; I allow the build process to handle that.
Isn't the code created using your biomechanical key-pressers "generated material"? I'm not sure that is a solid criteria to base a policy on. =)
@borfast I know I'm a little late to conversation so you may have seen this by this point but, you can specify a hash in the composer.json. In the require section, you can put: "repo": "dev-master#2633721877cae79ad461f3ca06f3f77fb4fce02e". This will 1) go to the branch, 2) checkout that hash, 3) if the hash is not found on the branch, however, it will checkout the head of the specified branch (master in this case).
@CEPA - That's odd. I would have expected it to fail if the hash couldn't be found. Seems dangerous.
u
user222758

You shouldn't update your dependencies directly on Production. You should version control your composer.lock file. You shouldn't version control your actual dependencies.

1. You shouldn't update your dependencies directly on Production, because you don't know how this will affect the stability of your code. There could be bugs introduced with the new dependencies, it might change the way the code behaves affecting your own, it could be incompatible with other dependencies, etc. You should do this in a dev environment, following by proper QA and regression testing, etc.

2. You should version control your composer.lock file, because this stores information about your dependencies and about the dependencies of your dependencies that will allow you to replicate the current state of the code. This is important, because, all your testing and development has been done against specific code. Not caring about the actual version of the code that you have is similar to uploading code changes to your application and not testing them. If you are upgrading your dependencies versions, this should be a willingly act, and you should take the necessary care to make sure everything still works. Losing one or two hours of up time reverting to a previous release version might cost you a lot of money.

One of the arguments that you will see about not needing the composer.lock is that you can set the exact version that you need in your composer.json file, and that in this way, every time someone runs composer install, it will install them the same code. This is not true, because, your dependencies have their own dependencies, and their configuration might be specified in a format that it allows updates to subversions, or maybe even entire versions.

This means that even when you specify that you want Laravel 4.1.31 in your composer.json, Laravel in its composer.json file might have its own dependencies required as Symfony event-dispatcher: 2.*. With this kind of config, you could end up with Laravel 4.1.31 with Symfony event-dispatcher 2.4.1, and someone else on your team could have Laravel 4.1.31 with event-dispatcher 2.6.5, it would all depend on when was the last time you ran the composer install.

So, having your composer.lock file in the version system will store the exact version of this sub-dependencies, so, when you and your teammate does a composer install (this is the way that you will install your dependencies based on a composer.lock) you both will get the same versions.

What if you wanna update? Then in your dev environment run: composer update, this will generate a new composer.lock file (if there is something new) and after you test it, and QA test and regression test it and stuff. You can push it for everyone else to download the new composer.lock, since its safe to upgrade.

3. You shouldn't version control your actual dependencies, because it makes no sense. With the composer.lock you can install the exact version of the dependencies and you wouldn't need to commit them. Why would you add to your repo 10000 files of dependencies, when you are not supposed to be updating them. If you require to change one of this, you should fork it and make your changes there. And if you are worried about having to fetch the actual dependencies each time of a build or release, composer has different ways to alleviate this issue, cache, zip files, etc.


Thanks, I think this answer explains why you should version composer.lock, and if not, what the consequences are and if you can live with them.
That only works in case prod and dev are EXACTLY the same environment. If you have PHP 7.4 in prod and 8.0 in dev, it may result in different dependencies sets. If you include your .lock file, then you should also include your vendor directory.
C
Community

You then commit the composer.json to your project and everyone else on your team can run composer install to install your project dependencies. The point of the lock file is to record the exact versions that are installed so they can be re-installed. This means that if you have a version spec of 1.* and your co-worker runs composer update which installs 1.2.4, and then commits the composer.lock file, when you composer install, you will also get 1.2.4, even if 1.3.0 has been released. This ensures everybody working on the project has the same exact version. This means that if anything has been committed since the last time a composer install was done, then, without a lock file, you will get new third-party code being pulled down. Again, this is a problem if you’re concerned about your code breaking. And it’s one of the reasons why it’s important to think about Composer as being centered around the composer.lock file.

Source: Composer: It’s All About the Lock File.

Commit your application's composer.lock (along with composer.json) into version control. This is important because the install command checks if a lock file is present, and if it is, it downloads the versions specified there (regardless of what composer.json says). This means that anyone who sets up the project will download the exact same version of the dependencies. Your CI server, production machines, other developers in your team, everything and everyone runs on the same dependencies, which mitigates the potential for bugs affecting only some parts of the deployments. Even if you develop alone, in six months when reinstalling the project you can feel confident the dependencies installed are still working even if your dependencies released many new versions since then.

Source: Composer - Basic Usage.


k
kenorb

If you’re concerned about your code breaking, you should commit the composer.lock to your version control system to ensure all your project collaborators are using the same version of the code. Without a lock file, you will get new third-party code being pulled down each time.

The exception is when you use a meta apps, libraries where the dependencies should be updated on install (like the Zend Framework 2 Skeleton App). So the aim is to grab the latest dependencies each time when you want to start developing.

Source: Composer: It’s All About the Lock File

See also: What are the differences between composer update and composer install?


What about having different versions of PHP (as example) in different environments? What about different OS? There are packages that depends on certain binaries like DOMPdf.
M
Martijn Pieters

Yes obviously.

That’s because a locally installed composer will give first preference to composer.lock file over composer.json.

If lock file is not available in vcs the composer will point to composer.json file to install latest dependencies or versions.

The file composer.lock maintains dependency in more depth i.e it points to the actual commit of the version of the package we include in our software, hence this is one of the most important files which handles the dependency more finely.


j
jgmjgm

There's no exact answer to this.

Generally speaking, composer shouldn't be doing what the build system is meant to be doing and you shouldn't be putting composer.lock in VCS. Composer might strangely have it backwards. End users rather than produces shouldn't be using lock files. Usually your build system keeps snapshots, reusable dirs, etc rather than an empty dir each time. People checkout out a lib from composer might want that lib to use a lock so that the dependencies that lib loads have been tested against.

On the other hand that significantly increases the burden of version management, where you'd almost certainly want multiple versions of every library as dependencies will be strictly locked. If every library is likely to have a slightly different version then you need some multiple library version support and you can also quickly see the size of dependencies needed flair out, hence the advise to keep it on the leaf.

Taking that on board, I really don't find lock files to be useful either libraries or your own workdirs. It's only use for me is in my build/testing platform which persists any externally acquired assets only updating them when requested, providing repeatable builds for testing, build and deploy. While that can be kept in VCS it's not always kept with the source tree, the build trees will either be elsewhere in the VCS structure or managed by another system somewhere else. If it's stored in a VCS it's debatable whether or not to keep it in the same repo as source trees because otherwise every pull can bring in a mass of build assets. I quite like having things all in a well arranged repo with the exception of production/sensitive credentials and bloat.

SVN can do it better than git as it doesn't force you to acquire the entire repo (though I suspect that's not actually strictly needed for git either but support for that is limited and it's not commonly used). Simple build repos are usually just an overlay branch you merge/export the build tree into. Some people combine exernal resources in their source tree or separate further, external, build and source trees. It usually serves two purposes, build caching and repeatable builds but sometimes keeping it separate on at least some level also permits fresh/blank builds and multiple builds easily.

There are a number of strategies for this and none of them particularly work well with persisting the sources list unless you're keeping external source in your source tree.

They also have things like hashes in of the file, how do that merge when two people update packages? That alone should make you think maybe this is misconstrued.

The arguments people are putting forward for lock files are cases where they've taken a very specific and restrictive view of the problem. Want repeatable builds and consistent builds? Include the vendor folder in VCS. Then you also speed up fetching assets as well as not having to depend on potentially broken external resources during build. None of the build and deploy pipelines I create require external access unless absolutely necessary. If you do have to update an external resource it's once and only once. What composer is trying to achieve makes sense for a distributed system except as mentioned before it makes no sense because it would end up with library dependency hell for library updates with common clashes and updates being as slow as the slowest to update package.

Additionally I update ferociously. Every time I develop I update and test everything. There's a very very tiny window for significant version drift to sneak in. Realistically as well, when semantic versioning is upheld, which is tends to be for composer, you're not suppose to have that many compatibility issues or breakages.

In composer.json you put the packages you require and their versions. You can lock the versions there. However those packages also have dependencies with dynamic versions that wont be locked by composer.json (though I don't see why your couldn't also put them there yourself if you do want them to be version locked) so someone else running composer install gets something different without the lock. You might not care a great deal about that or you might care, it depends. Should you care? Probably at least a little, enough to ensure you're aware of it in any situation and potential impact, but it might not be a problem either if you always have the time to just DRY run first and fix anything that got updated.

The hassle composer is trying to avoid sometimes just isn't there and the hassle having composer lock files can make is significant. They have absolutely no right to tell users what they should or shouldn't do regarding build versus source assets (whether to join of separate in VCS) as that's none of their business, they're not the boss of you or me. "Composer says" isn't an authority, they're not your superior officer nor do they give anyone any superiority on this subject. Only you know your real situation and what's best for that. However, they might advise a default course of action for users that don't understand how things work in which case you might want to follow that but personally I don't think that's a real substitute for knowing how things work and being able to properly workout your requirements. Ultimately, their answer to that question is a best guess. The people who make composer do not know where you should keep your composer.lock nor should they. Their only responsibility is to tell you what it is and what it does. Outside of that you need to decide what's best for you.

Keeping the lock file in is problematic for usability because composer is very secretive about whether it uses lock or JSON and doesn't always to well to use both together. If you run install it only uses the lock file it would appear so if you add something to composer.json then it wont be installed because it's not in your lock. It's not intuitive at all what operations really do and what they're doing in regards to the json/lock file and sometimes don't appear to even make sense (help says install takes a package name but on trying to use it it says no).

To update the lock or basically apply changes from the json you have to use update and you might not want to update everything. The lock takes precedence for choosing what should be installed. If there's a lock file, it's what's used. You can restrict update somewhat but the system is still just a mess.

Updating takes an age, gigs of RAM. I suspect as well if you pick up a project that's not been touched for a while that it looked from the versions it has up, which there will be more of over time and it probably doesn't do that efficiently which just strangles it.

They're very very sneaky when it comes to having secret composite commands you couldn't expect to be composite. By default the composer remove command appears to maps to composer update and composer remove for example.

The question you really need to be asking is not if you should keep the lock in your source tree or alternatively whether you should persist it somewhere in some fashion or not but rather you should be asking what it actually does, then you can decide for yourself when you need to persist it and where.

I will point out that having the ability to have the lock is a great convenience when you have a robust external dependency persistence strategy as it keeps track of you the information useful for tracking that (the origins) and updating it but if you don't then it's neither here not there. It's not useful when it's forced down your throat as a mandatory option to have it polluting your source trees. It's a very common thing to find in legacy codebases where people have made lots of changes to composer.json which haven't really been applied and are broken when people try to use composer. No composer.lock, no desync problem.


F
Fabien Snauwaert

For anyone on Heroku, the answer is clear "yes, it should be committed":

If composer.json specifies dependencies of any kind in its require section, the corresponding composer.lock that gets generated by running composer update must also be committed to the repository, or the push will be rejected.

Source: Heroku PHP Support: Activation.