A short example of using subtree for stuff.
Brennen Bearnes 9f01e78448 update.gif 3 years ago
imgs update.gif 3 years ago
libs Merge commit '78958bacb8' as 'libs/Adafruit-PiTFT-Helper' 3 years ago
README.md update.gif 3 years ago
update_subtrees.sh initial commit with script 3 years ago

README.md

HOWTO use Git subtrees, I kinda think

structure of this repo

This was created with:

mkdir libs
git subtree add -P libs/Big_Easy_Driver --squash git@github.com:sparkfun/Big_Easy_Driver.git master
git subtree add -P libs/Adafruit-PiTFT-Helper --squash git@github.com:adafruit/Adafruit-PiTFT-Helper.git master

You could also do the same thing by creating a named remote first:

git remote add Adafruit-Pi-PiTFT-Helper git@github.com:adafruit/Adafruit-Pi-PiTFT-Helper.git
git subtree add -P libs/Adafruit-PiTFT-Helper --squash Adafruit-Pi-PiTFT-Helper master

master here could be a branch or a specific commit.

(Notice how in the subtree add, I used the named remote instead of git@github.com:adafruit/Adafruit-PiTFT-Helper.git. This can be convenient, but it will only exist on a local copy of the repo, so it’s one extra layer of confusion when explaining to people.)

There’s an update_subtrees.sh. It looks like this:

#!/usr/bin/env bash
git subtree pull -P libs/Big_Easy_Driver --squash git@github.com:sparkfun/Big_Easy_Driver.git master
git subtree pull -P libs/Adafruit-PiTFT-Helper --squash git@github.com:adafruit/Adafruit-PiTFT-Helper.git master

The reason this is in a script is that every git subtree command pretty much requires a prefix, a remote, and a ref. This is too much to expect anybody to remember without googling. Trust me, you’ll forget it an hour after you set up the subtree the first time. If you don’t put it in a script, at least document all the commands you use in your README.

update_subtrees.sh

I have tested this on Debian. It would probably run on Windows in a git shell (assuming Bash), but I haven’t tried that yet.

what?

Ok, so first, why subtree?

Lots of people I know (especially in the hardware community) seem to be dealing with dependencies between repositories lately.

git is actually quite bad at handling this problem, to date. In fact, I’m not sure if there exists an otherwise usable VCS that’s any good at it. It just doesn’t seem to be very much part of the model for anything. (Somebody tell me if I’m wrong about this.)

There are two out of the box solutions that I’m aware of:

  • submodules
  • subtrees

Of these, submodules are probably better documented and have more first-class UI. They also seem to break things a lot and confuse users pretty badly. Here’s the relevant google search. I have had a real bad time with submodules, but this isn’t meant as a polemic. There may be use-cases for submodules, and they may be improving as git is developed.

Anyhow, subtrees: Subtrees are a fundamentally pretty different abstraction. Rather than pointing at some remote, they copy the contents (and optionally history) of a remote repository. Advantages:

  • users don’t have to initialize anything or clone with --recursive to get dependencies - code’s just there.
  • if you use --squash, you just wind up with one commit pointed at the target ref.
  • I’m guessing it’s less likely to blow up in your face with a branching workflow, but who knows.

Here are some writeups:

Good luck.