1
Fork 0
jakstys.lt/content/log/git-subtrac.md

5.3 KiB

title date draft
git-subtrac and Zig 2022-04-23T05:37:51+03:00 true

TLDR: I wish plain git clone <repository> would check out submodules if they are in the same repository.

I use git-subtrac for some of my projects, and am not very enthusiastic about Zig getting it's own package manager (can we all use git-subtrac and be done with it?). A few weeks ago in a park in Milan my conversation with Andrew Kelley was something like:

  • me: "git-subtrac yadda yadda yadda submodules but better yadda yadda yadda".
  • Andrew: "if I clone a repository that uses git-subtrac with no extra parameters, will it work as expected?"
  • me: "no, you have to pass --recursive, so git will checkout submodules... even if they are already fetched."
  • Andrew: "then it's a piece-of-shit-approach."

Uh, I agree. People have not grown muscle memory to clone repositories with --recursive flag and never will, so it's impossible to adopt git-subtrac beyond well-controlled silos. Which is why we will have a yet-another-programming-language-specific-package-manager, this time for zig. Or at least my argument for using git-subtrac stops right there.

Why git-subtrac?

git-subtrac is like "classic" git submodules, but all refs of the dependencies stay in the same repository. Wait, stop here. Repeat after me: it is git submodules, but all refs stay in the same repository. I also call it "good vendoring". Since all the deps are in our repo, no external force can make our dependency unavailable.

It is, howerver, harder to add a dependency with submodules than with, say, go get <dependency>. Let's talk about adding dependencies.

Adding dependencies

All of the programming languages I've used professionally whose name does not start with "c"1 have package managers2, which make "dependency management" easy. These package managers will download and build the dependency tree, sometimes conveniently generate a "lock file", so your project has an illusion of being "reproducible".

C/C++ projects I've been involved usually had 1-5 non-system dependencies, whereas all others -- tens or hundreds. This uncovers an obvious correlation: if it's easy to add dependencies, they will be added. En masse. Not adding dependencies in Go/Python/whatever requires discipline. Slip once, add some crap -- it will be very hard to remove, as changing dependencies often require large rewrites. Not adding dependencies in C/C++, however, is the path of least resistance. However, in the long term, my C/C++ projects tended to survive longest (or required least amount of changes to build and run after the world moved on) just because of this.

Making it easy to depend on external code is is convenient during development, but frees (or denies, depending how one looks at it) developers from their basic right (or obligation?) to understand them. And adds real long-term maintenance costs.

To sum up, the "modern" languages optimize for initial development experience, not maintenance. And as Corbet says. "We can't understand why Kids These Days just don't want to live that way". Kids want to build, John, not maintain.

This is why I am always hesitant to pull in code to my project, and have a my dependency checklist:

  • Obvious: does it work at all?
  • How easy is it to build, run and run it's tests?
  • Is it well written? API surface, documentation, tests, error handling, error signaling, logging, metrics (if applicable), etc.
  • It's system dependencies.
  • It's transitive dependencies.

Zooming into the last part: C projects tend to do it well. For Go and Python projects a small number of dependencies is often a sign of care and quality on other areas, too. mattn/go-sqlite3, google/brotli, apenwarr/redo, cmph are good examples.

If a dependency is well written, but has more transitive dependencies than I need and there is no good alternative, I will fork it and remove unnecessary code and dependencies. My recent example is sql-migrate.

If I may combine Corbet's views with mine: if we understand and audit our dependencies (and transitive ones), we will have less dependencies and a more maintainable system. Win-win.

Which brings us to...

Transitive dependencies and git-subtrac

git-subtrac does not deal with transitive dependencies. At least not directly. Or I am not aware of it. Ok, I haven't tried.

If we audit and thus understand our dependencies, we will be able to add transitive ones to our project even without support of git-subtrac. So perhaps git-subtrac shouldn't care?

Conclusion

Can git checkout local submodules when they are in the same repository, so our conversation of reconsidering (or not having) a zig package manager doesn't stop after 5 seconds?


  1. Alphabetically: Erlang, Go, Javascript, PHP, Perl, Python. ↩︎

  2. Usually written in the same language. Zoo of package managers (sometimes a couple of popular ones for the same programming language) is a can of worms in an on itself worth another blog post. ↩︎