# Composer: Missing Distributions For Explict References


By Ben Ramsey

Published on June 17, 2015

Updated on June 19, 2015

> [!SUCCESS] NOTITLE
> [Wim Vandersmissen](https://twitter.com/wim_vds) was kind enough to correct this behavior with a [pull request](https://github.com/composer/composer/pull/4167) to the Composer project, which [Jordi](http://seld.be/) merged in. If you run `composer self-update`, it will update Composer with these changes, and `--prefer-dist` will behave properly to retrieve distribution zip archives for explicit references from Bitbucket.

This came as a bit of a surprise to me today, so I wanted to post it here to help others, in case you run into similar problems.

For applications I control that are not distributed to the public, I like to hard-lock my [Composer](https://getcomposer.org/) dependencies to a specific version. I don't use tilde, asterisk, caret, ranges, etc. to specify dependencies. I use the specific version number I want (i.e., `3.7.1`). This gives me piece of mind that application code I have already tested is not going to change behavior simply because underlying libraries I'm using have changed. It also gives me the flexibility to upgrade dependencies on my own terms.

> [!CAUTION] Use Flexible Dependencies for Public Libraries
> I do not advocate this approach if you are developing a library for public distribution. Public libraries need to have flexible dependencies so that Composer can choose to the best possible version for other libraries requiring different versions of the same dependency.

Sometimes a library has updates that haven't yet been released, and I need to use these right away. Composer allows me to specify the specific commit I want to use for a library. In this way, I can hard-lock a dependency to a specific state, even when there is not yet a release for the changes I need.

```json
{
    "require": {
        "acme/foo": "dev-master#b96ab0ce4a"
    }
}
```

This has worked well until today, when I tried to do a fresh `composer install`. After installing, one library contained files and methods that I did not expect. It turns out Composer was grabbing the HEAD of dev-master instead of the specific commit I referenced.

When I looked in `vendor/composer/installed.json`, it became clear what was happening. The relevant entry looked a little something like this:

```json
{
    "name": "acme/foo",
    "version": "dev-master",
    "version_normalized": "9999999-dev",
    "source": {
        "type": "git",
        "url": "https://bitbucket.org/acme/foo.git",
        "reference": "b96ab0ce4a"
    },
    "dist": {
        "type": "zip",
        "url": "https://bitbucket.org/acme/foo/get/03ae0dba64d1a902fb4d76004ef12c8391ededc8.zip",
        "reference": "b96ab0ce4a",
        "shasum": ""
    },
    "require": {
        "php": ">=5.2.0"
    },
    "time": "2015-03-23 22:00:25",
    "type": "library",
    "installation-source": "dist",
    "autoload": {
        "psr-0": {
            "Acme": "src/"
        }
    },
    "description": "An example library"
}
```

Notice in line 21 that my installation-source is "dist," and in the dist section it shows a zip file URL referring to a different commit hash than the reference (line 12 vs. line 13). This is because [Bitbucket](https://bitbucket.org/) provides a distribution zip file for the current HEAD of the branch, but not the specific commit I need.

Since `composer install` uses `--prefer-dist` by default, I was getting the distribution zip file provided by Bitbucket for the HEAD of the master branch, rather than for the specific commit I needed.

> [!NOTE] GitHub Provides a Zip Archive for Each Commit
> It appears that this problem does not exist on GitHub. GitHub provides the ability to download a zip archive of every single commit, and Composer grabs the correct distribution for the explicit reference.

When providing the `--prefer-source` option to `composer install`, I was able to retrieve the exact commit I wanted. Problem solved!

Unfortunately, using `--prefer-source` is slower and downloads VCS files (i.e., `.git/`), as well as files that are marked as `export-ignore` in `.gitattributes` (since Composer isn't getting the exported distribution archive but is cloning the repository itself).


