Package Manager vs. Git Submodule/Subtree

The git solutions seem to be a lot more hassle than a simple package manager.

This is not about hassle.

This is about two different ways to build a project:

  1. through binary dependencies, with a package manager (Nexus, or Conan for C++: you declare your dependencies, and the package manager fetches them and uses them during the compilation.
    That is what a pom.xml or a npm-package.json: just one more file within your unique codebase, which will instruct the compiler to download the relevant dependencies
  2. through source dependencies, with Git submodules or subtrees, where you store references to other source code, import them, and recompile everything.
    For instance, if your system is composed of a front-end GUI sources and a backend sources, you could reference both repositories within one parent project repositories, combining their sources into one code base.

The first is good when building a system, where each part has its own release lifecycle, and you want to depend to pre-built dependencies.

The second is used when the dependencies are more tightly linked to the main program.

Or when there are no binary dependencies (which is the case, for instance, with Go and its modules).


"If the technological context allows for packaging and formal dependency management, you should absolutely go this route."

The above is from Mastering Git submodules, which is such a well written and thought out article it deserves to be the top answer for this and many similar Stackoverflow questions.

Let me quote the part that is relevant to this question:

Are they the right tool for the job?

There are a number of situations where the physical presence of module code inside container code is mandated, usually because of the technology or framework being used. For instance, themes and plugins for Wordpress, Magento, etc. are often de facto installed by their mere presence at conventional locations inside the project tree, and this is the only way to “install” them.

In such a situation, going with submodules (or subtrees) probably is the right solution, provided you do need to version that code and collaborate around it with third parties (or deploy it on another machine); for strictly local, unversioned situations, symbolic links are probably enough, but this is not what this post is about.

On the other hand, if the technological context allows for packaging and formal dependency management, you should absolutely go this route instead: it lets you better split your codebase, avoid a number of side effects and pitfalls that litter the submodule space, and let you benefit from versioning schemes such as semantic versioning (semver) for your dependencies.