Skip to main content

Upstreams

An upstream is much like a Git remote: a named repository a splice fetches from and pushes to. Its name and URL live inside the splice folder, in .splice, so they move and branch with it (why):

[upstream "origin"]
url = https://git.example.com/s.git

Unlike a Git remote, it is fetched into private refs without creating an entry under git remote (why).

A fork and the original​

A common use for several upstreams is working with a company fork while still fetching the original:

[splice]
default-upstream = fork
[upstream "origin"]
url = https://git.example.com/lib.git
[upstream "fork"]
url = https://git.example.com/company/lib.git

When .splice names several upstreams, default-upstream says which one commands use when --upstream is omitted. Without it, commands that need one upstream refuse to guess. In the example above, commands use fork unless --upstream origin selects the original; fetch fetches both (example).

URLs, keys and refs​

Each named upstream in .splice has a URL. The monorepo uses that URL as the upstream's identity.

A key is a short, ref-friendly nickname for one unique upstream URL. The mapping is one-to-one within the monorepo: one URL has one key, and one key names one URL. For example, https://github.com/acme/shared-lib.git gets the key shared-lib, so its main branch is fetched to refs/splices/shared-lib/heads/main.

The first fetch records the mapping and fetches the upstream's branches to refs/splices/<key>/heads/. These are ordinary Git refs, so commands such as git log can read them and git worktree add can check them out (example).

Choosing a key​

The generated key comes from the URL, but it can be renamed. Choose a name you already associate with the upstream, or one that makes its refs easier to recognize and type.

upstreams-setup.bash builds an example whose generated key is s. Rename it to shared-lib through any splice that uses the URL:

$ git splice key app-a/s shared-lib
ok app-a/s: renamed key 's' to 'shared-lib'

The refs move with the key:

$ git for-each-ref --format='%(objectname:short) %(refname)' refs/splices
bde4164 refs/splices/shared-lib/heads/main

Because a key belongs to its URL, the rename applies to every splice that names that URL.

Tracking another upstream branch locally​

A splice normally syncs with the upstream branch that corresponds to the current monorepo branch. When their names deliberately differ, track the upstream branch to use instead, much like setting a Git branch's upstream:

$ git splice fetch --branch development --track app-a/s
ok app-a/s fetched
ok app-a/s: 'main' tracks 'development' from now on

The override is local to this clone and the current monorepo branch. It is stored by upstream key, so it applies to every splice using that upstream. Plain sync and status commands use it from then on. Stop using it with --no-track:

$ git splice fetch --no-track app-a/s
ok app-a/s fetched
ok app-a/s: 'main' no longer tracks 'development'

See the fetch command reference for the other ways to set a tracked branch and its exact fallback behavior.

The same library at different versions​

In the same example, app-a/ and app-b/ each contain their own splice of the library s. Both .splice files name the same upstream URL:

$ git config --file app-a/s/.splice upstream.origin.url
https://git.example.com/s.git
$ git config --file app-b/s/.splice upstream.origin.url
https://git.example.com/s.git

Both therefore report the key chosen above:

$ git splice key app-a/s
shared-lib
$ git splice key app-b/s
shared-lib

They still choose versions independently. Pulling a new upstream commit into app-a/s leaves app-b/s behind:

$ seed_bare_repo "$UPSTREAM" "upstream change" &&
> git splice pull app-a/s >/dev/null &&
> git splice status
On branch main

behind 1 app-b/s

up to date app-a/s

The two folders are independent splices because they have different ids.