composer: RFC: Automatically resolve conflicts in composer.lock

When merging/rebasing branches it’s not that rare that you may encounter merge conflicts in composer.lock. Most of the time the conflict would be in the hash or in a timestamp or in some cases you’d need to choose both blocks on the same lines.

However, it’s quite rare you’d actually need to manually resolve something in composer.lock in a custom way.

The usual workflow:

  1. You have a conflict in composer.lock
  2. You run your git-mergetool and chose one of the hashes - doesn’t matter which one.
  3. composer update --lock
  4. git add composer.lock
  5. git rebase --continue or git commit (if you’re merging).

How about automatically fix the merge conflicts when running composer install or composer update --lock if possible?

This was already implemented in Yarn:

What do you think?

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 46
  • Comments: 27 (22 by maintainers)

Most upvoted comments

I have created a custom git merge driver that can be used to minimize merge conflicts in composer.json and composer.lock files. Handling this at the merge step (instead of grappling with the merge conflict markers after the fact) allows for more graceful handling of merges within these files; this only results in conflicts when a dependency’s version has changed in multiple branches, which is a legitimate conflict that requires a conscious resolution.

https://github.com/balbuf/composer-git-merge-driver

Please check it out!

The content-hash serves a real purpose and removing it is not a solution, it might resolve some merge conflicts but would introduce other issues.

Adding a merge functionality that checks the two lock files and sees if they are compatible and still match the current requirements though sounds like something that’s feasible and definitely should be looked.

I have created issue WI-39466. In PHPStorm tracker, I think solving this problem in editor might be more proper place.

What I’ve been recently doing to overcome composer.lock conflicts in feature branches is:

  1. I create a feature branch and update some dependencies in it. Both composer.json and composer.lock files are modified. I note the CLI composer command I used for this update.
  2. Someone pushes a deps update to the main branch.
  3. Rebasing the feature branch on top of main branch would create a composer.lock conflict.
  4. What I do first is that I change the feature branch and remove the composer.lock change. So the commit that updates dependencies in feature branch only contains composer.json changes.
  5. I can now rebase the feature branch on top of the main branch without composer.lock conflict.
  6. This now allows me to replay my noted composer command from 1) on top of the latest composer.lock file from the main branch.

If Composer would let me do this in an easier way without doing all the git-fu, that would be great!

Maybe not very clean but - separate folder like ‘.composer.lock’ having files separate per library or just remove content-hash. In bigger projects with large teams, this becomes a real pain.

Right. Conflicts on the lock file should be something that a plugin can handle.

But could this not be cached in some place that is not tracked with git? Either on system level or on project level. (the answer to this depends on the questions below)

being tracked by git is precisely what allows reproducible installs in all environments. Other environments must have the metadata too.

Composer plugin running on install or a new command. Install and setup are easy. Discoverability is not.

This one might be hard to implement, because composer loads the composer.json file quite early (as it contains some config stuff), and would fail there in case of an invalid file.

A. Git merge driver for Composer - needs improvements on installation and complex cases.

For that, I suggest opening issues on the merge driver repo for the different cases causing issues. Regarding new and removed libraries for instance, we could easily imagine that the driver would not perform a dumb deep merging of objects, but would treat the name of packages in a special way, treating the 2 objects as different.

if we target a specific version number, then newer commits should not matter, right? unless there is a force-push.

Even without a force push, git allows deleting a tag and publishing the same version on a new commit. Also, force pushes in libraries do happen. But I think this is beside the point in this conversation. This is mostly about multiple developers working on the same project having conflicts in composer.lock when merging and rebasing across branches. This is happening way more often. Any remedy should work with existing composer.lock format for BC.

I’m also aware this can be solved with a little bit of git-fu:

  1. When the rebase conflicts, do whatever you want with the composer.lock.
  2. You now have your branch on top of the branch you’re rebasing on.
  3. Rebase again (interactively) and edit the commit with the composer.lock change
  4. Reset the composer.lock file to the same state as in on top of the main branch.
  5. You can now run your composer require or composer update package command and the composer.lock will end up in the state you want without any other unwanted updates.
  6. Finish the rebase.

I wonder if there’s a way for Composer to do the same thing out of the box…

@Seldaek would you accept a PR which incorporates https://github.com/balbuf/composer-git-merge-driver into the composer codebase (solving the problem vcs independently)?

IMO solving merge conflicts of composer.json/lock is pain point for composer usage and should not be something the composer user should need additional setup for (setup the git merge-driver etc). I guess a lot of composer users dont know git merge drivers at all and therefore deal with those problems manually. additionally the git merge driver thing doesnt work for mercurial or svn etc.