Skip to main content

git-orchard

pre-commit status Deploy Status Go Reference Arch User Repsoitory PyPI Go Report Card

A command-line utility for managing git-subtrees.

Install

AUR:

git-orchard is available from the Arch User Repository.

yay -S git-orchard

pip:

git-orchard is available as a pypi package.

pip install git-orchard

go:

go install github.com/jmelahman/git-orchard@latest

Usage

Subtrees are listed in a committed manifest at the repository root, .gitsubtrees or .config/git-orchard/subtrees (but not both), in the same syntax as .gitmodules:

[subtree "tools/foo"]
	remote = git@github.com:owner/foo.git
	branch = master

The same keys in git's own configuration (e.g. .git/config) override it for one clone. Pulls and adds are squashed unless the manifest sets orchard.squash = false.

git orchard init                        # list the subtrees already in git history
git orchard add git@github.com:owner/foo.git tools/foo
git orchard add git@github.com:owner/foo.git # prefix defaults to the repo name, foo
git orchard status                      # commits ahead/behind each upstream
git orchard pull [prefix...]            # merge upstream changes
git orchard push [prefix...]            # publish, fast-forward only
git orchard push --changed-since REV    # only subtrees changed since REV
git orchard push --tag tools/foo/v1.2.3 # publish as v1.2.3 upstream
git orchard release tools/foo          # tag the next version, e.g. tools/foo/v1.2.4, and push it to origin
git orchard release tools/foo v2.0.0   # or a version of your choosing
git orchard sync [prefix...]            # copy shared files into subtrees
git orchard detach [worktree]           # turn a linked worktree into a standalone clone

Without a version, release picks one after the latest release, much as tag does: the patch version incremented (--minor and --major increment those instead), or a pre-release's stable release; --suffix rc picks the next release candidate, e.g. v1.2.4-rc, then v1.2.4-rc.1. Releases are the <prefix>/v* tags in the monorepo and on its remote, and the v* tags upstream, so releases from before the subtree count; --dry-run prints the pick. release requires the upstream branch to contain the release already, so the upstream tag lands on its history; --upstream pushes the branch and tag there directly instead of leaving it to the action. push, pull and release take --no-verify to skip git hooks. push --force overwrites upstream branches and tags, leased on their value when the push starts so a concurrent update still fails it; the action never forces. release --force moves an existing tag, unless the upstream already published it at another commit: the Go module proxy and release artifacts won't follow a moved release.

push splits each subtree out of the monorepo with git subtree split, which is deterministic, so the same history always gives the same commits and every push is a fast-forward. An upstream with commits the monorepo doesn't have rejects the push until they're pulled in.

detach gives a worktree made with git worktree add its own .git directory, with the repository's refs, config, hooks and excludes, and the worktree's HEAD and index, so uncommitted changes carry over; objects are hardlinked where possible, as for a local clone. It then drops the worktree from the original repository, and refuses one that is locked, has submodules, or is mid-merge, rebase, cherry-pick, revert or bisect.

git-orchard only runs git, so credentials, SSH config and url.<base>.insteadOf rewrites apply as usual.

Shared files

Subtrees that are published on their own each need their own copy of config like .pre-commit-config.yaml or .github/dependabot.yml. git orchard sync keeps those copies in step with one source. A subtree lists the profiles it shares, and each profile is a directory under orchard.sharedDir (.config/git-orchard/shared by default):

[subtree "tools/foo"]
	remote = git@github.com:owner/foo.git
	shared = base
	shared = go
.config/git-orchard/shared/
  base/.github/dependabot.yml   # → tools/foo/.github/dependabot.yml
  base/.pre-commit-config.yaml
  go/.pre-commit-config.yaml

A file in a profile lands at the same path in the subtree, replacing it whole. When the subtree's file marks a block for the profile, only the lines between the markers are replaced, and the rest of the file stays the subtree's own:

repos:
  # BEGIN orchard:base
  # END orchard:base
  # BEGIN orchard:go
  # END orchard:go
  - repo: local # not shared
    hooks: [...]

Markers work in any comment syntax, since git-orchard only looks for BEGIN orchard:<profile> and END orchard:<profile> in the line. Two profiles can share a file only through blocks.

sync exits 1 when it changes a file, like a formatter, and --check prints the differences without writing them. To run it on every commit, add the hook to the monorepo's root pre-commit config (not to the subtrees', since their mirrors have no manifest):

repos:
  - repo: https://github.com/jmelahman/git-orchard
    rev: v1.2.3
    hooks:
      - id: git-orchard-sync

GitHub Action

This repository is also an action that mirrors a monorepo's subtrees on every push: changed subtrees are pushed to their upstreams, and a <prefix>/<name> tag is published to that prefix's upstream as <name>.

on:
  push:
    branches: [master]
    tags: ["**/v*"] # `*` doesn't match `/`

jobs:
  mirror:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0 # splits need the full history
          persist-credentials: false
      - uses: jmelahman/git-orchard@v1
        with:
          app-client-id: ${{ vars.ORCHARD_APP_CLIENT_ID }}
          app-private-key: ${{ secrets.ORCHARD_APP_PRIVATE_KEY }}

The action pushes as a GitHub App, which git orchard github-app creates:

git orchard github-app  # add --org ORG for an organization's repositories

It opens a browser to create a private App under your account from a manifest (contents and workflows write, no webhook), then to install it: pick the upstream repositories there. With the GitHub CLI installed, it stores the App's client ID and private key on the monorepo (origin, or --repo) as the ORCHARD_APP_CLIENT_ID variable and ORCHARD_APP_PRIVATE_KEY secret; otherwise it writes the key to a file and prints the gh commands to store it. The App and its key are yours; git-orchard runs no service.

The action mints a short-lived token from the App's installation for owner (default: the monorepo's owner). Alternatively, pass token, e.g. a fine-grained token with "Contents" and "Workflows" read and write on the upstreams; GitHub refuses pushes that change .github/workflows without the latter. Either way, GitHub remotes in the manifest are rewritten to use the token. changed-since defaults to the start of the pushed range; set it empty to push every subtree. The action builds git-orchard from its own source, so the CLI is always the version the action is pinned to.

Metadata

Release files for git-orchard 1.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for git-orchard 1.2.1
File
git_orchard-1.2.1-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
git_orchard-1.2.1-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
git_orchard-1.2.1-py3-none-manylinux_2_17_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
git_orchard-1.2.1-py3-none-manylinux_2_17_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
git_orchard-1.2.1-py3-none-macosx_11_0_x86_64.whl Python 3 none macOS 11.0+ x86-64 Details
git_orchard-1.2.1-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
git_orchard-1.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 29.4 MB

Release files / git_orchard-1.2.1-py3-none-win_arm64.whl

Download URL git_orchard-1.2.1-py3-none-win_arm64.whl
Size 4.0 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
d2aa980b815d1b9e5d7d72a76ad3c5aa60ada69d6d9f8d0c4110c8025434e561
BLAKE2b-256 checksum
How to use checksums
56f40dfba99a1f806e58aea547a5a7452bde33525914569c27bb5d4e7285929b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / git_orchard-1.2.1-py3-none-win_amd64.whl

Download URL git_orchard-1.2.1-py3-none-win_amd64.whl
Size 4.5 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
2e842080fff639ac40062c76c15d6b551e24434efba53875a749d1bc1857a187
BLAKE2b-256 checksum
How to use checksums
f015fc107429efe4991d81ab6468d18ae5d00abe13c0e0b983f14eeabfcbdd44
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / git_orchard-1.2.1-py3-none-manylinux_2_17_x86_64.whl

Download URL git_orchard-1.2.1-py3-none-manylinux_2_17_x86_64.whl
Size 4.4 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
54d7a565f8730b5313defff40e7b75e4e29f324c6707293ff2b71d3e06d971d3
BLAKE2b-256 checksum
How to use checksums
43dfc97dc09c206ca9d394e87e3ec053b19b16d910d113a7b794d07f5faeac8a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / git_orchard-1.2.1-py3-none-manylinux_2_17_aarch64.whl

Download URL git_orchard-1.2.1-py3-none-manylinux_2_17_aarch64.whl
Size 3.9 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
0f8cc3d86702996b03da5ea69d77badeb637a0573aad1dd49537bfb8dad7c6e8
BLAKE2b-256 checksum
How to use checksums
51fc6911da7eb15223cf97dc3ca9489fba4d83c5407830b5ae883a75a0d21903
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / git_orchard-1.2.1-py3-none-macosx_11_0_x86_64.whl

Download URL git_orchard-1.2.1-py3-none-macosx_11_0_x86_64.whl
Size 4.4 MB
Tags Python 3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
2c953c503aaa7e1702ca9febcafd4161370a2b167c4d2ce8107b8cea50691415
BLAKE2b-256 checksum
How to use checksums
27c6caf7f14fd49c2988162216cd54bde3348dcecfc320f21c25b9e4f39e6131
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / git_orchard-1.2.1-py3-none-macosx_11_0_arm64.whl

Download URL git_orchard-1.2.1-py3-none-macosx_11_0_arm64.whl
Size 4.0 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d77928356d10801485f4946395ededf1de8c24146af43e1cf3394efa8ec29d7f
BLAKE2b-256 checksum
How to use checksums
d978555589256641e3da24c06c38cfd6dcb9f6c9b7d62d24cbf622bf66e47699
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / git_orchard-1.2.1-py3-none-any.whl

Download URL git_orchard-1.2.1-py3-none-any.whl
Size 4.4 MB
Tags Python 3
SHA-256 checksum
How to use checksums
8bb310aeac39b4161017b5a77ae219bcaf31f94e62526bf9a92cc93012fbb12b
BLAKE2b-256 checksum
How to use checksums
51de450cd1bd36f3541169deb7b299b21ff3c7849e984b788fcfaa493961b1e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

1.2.1 This release

7 release files

1.2.0

7 release files

1.1.2

7 release files

1.1.1

7 release files

1.1.0

2 release files

1.0.4

7 release files

1.0.3

4 release files

1.0.2

3 release files

1

2 release files

0.0.1

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page