Checking in Package Dependencies into Source Control
This post looks into why we should include packages in the source control and not resolve it via configuration files at build time.
Over the past few years, Package Managers have gained an important role in the way software gets developed. There is an increasing number of package managers catering to different programming languages and areas of development, making the distribution of reusable libraries and plugins easy. The convention that’s usually followed with these package dependencies is to exclude them from source control, and use a configuration file (package.json, packages.config) to retrieve all the packages at build time. Even the GitHub’s collection of .gitignore file templates ignores the packages folders of various package managers.
# NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* ... # Dependency directories node_modules jspm_packages
Since checking in packages is not a common practice, let’s first see some of the arguments for not doing this and how it compares to having them checked in.
Packages are something that can be resolved at runtime and keeping them excluded saves that extra space on the source control system.
Yes, this might have been a good reason few years back, but these days this is not a good reason as storage has become really cheap. Moreover popular source control systems charge by the number of repositories and not by the space it occupies (although it has limits on it).
The clone is faster when you do not have packages in the source control repository as opposed to having them.
But for the project to build we need the packages restored first. So the time is either spent in the clone or in the restore. But if the packages are included in the git clone then you can immediately start working on the project after a clone and do not need any internet connectivity to make the project build. This is also of advantage if you want to run a ’git clean’ - which cleans the working tree by recursively removing files that are not under version control. With packages not under the source control, you have to restore them every time you run it - This is not a problem if you have internet connectivity, but will block your work if you do it when you don’t.
Without checking in dependent packages, you can’t git clone and get on a flight nor can you git clean while on a flight
Moreover cloning a repository is a one-time activity, while a clean can be done any time a developer wants to. So it actually saves more time to keep the packages checked in.
Now that we have seen most of the common arguments are not valid, let’s see more reasons on why including the packages into the source control is actually better.
It’s always better to be explicit about your code dependencies and not have them resolved by a package manager.
Packages are nothing but code and can alter the behaviour of the application.
There are possibilities of specific package versions getting removed from the package manager, which your application is still dependent on and leads to build breakage! If your package configuration is set up in such a way to resolve the latest available package of the specific dependency, there are possibilities that the package owner pushes an update that is not backward compatible, causing the build to break! Given that these possibilities exist there is no reason to exclude package dependencies from checked in.
Though the publicly available package sources like NuGet, npm are available almost all the time, it is likely that they too can go down. The last thing you would want is to get blocked by the downtime of these services - be it failure to build locally or on a server or even block a critical deployment. With the packages available in your source control, you have one less moving part in your whole deployment pipeline and it is better to have lesser dependencies.
Many times I have had to update my Package sources in Visual Studio and break my head on the specific order of these entries to get the project building. This is very common when using custom packages sources like ProGet or MyGet. Such dependencies make project setup harder and is easily avoided if all the dependent assemblies are available within the repository. You can still have them as custom NuGet sources but have the dependencies included into the repository and update the references whenever source changes. This makes project ramp up easier and faster, with one less configuration step.
Do you still see any reason for not checking in package dependencies into the source control? If not let’s go and change that package folder exclude and have them included in the source. (I just updated CLAL to include dependencies.)