{"id":51548416,"url":"https://github.com/khwstolle/git-third-party","last_synced_at":"2026-07-09T21:00:58.227Z","repository":{"id":365268176,"uuid":"1232981052","full_name":"khwstolle/git-third-party","owner":"khwstolle","description":"Vendor third-party Git repositories into your own, with path filtering and local patches.","archived":false,"fork":false,"pushed_at":"2026-06-16T15:09:14.000Z","size":195,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-16T17:06:21.288Z","etag":null,"topics":["dependencies","git","gitops","package-manager","vendoring"],"latest_commit_sha":null,"homepage":"http://gh.khws.io/git-third-party/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/khwstolle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-08T13:16:39.000Z","updated_at":"2026-06-16T15:07:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/khwstolle/git-third-party","commit_stats":null,"previous_names":["khwstolle/git-third-party"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/khwstolle/git-third-party","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khwstolle%2Fgit-third-party","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khwstolle%2Fgit-third-party/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khwstolle%2Fgit-third-party/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khwstolle%2Fgit-third-party/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/khwstolle","download_url":"https://codeload.github.com/khwstolle/git-third-party/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khwstolle%2Fgit-third-party/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35312540,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependencies","git","gitops","package-manager","vendoring"],"created_at":"2026-07-09T21:00:51.928Z","updated_at":"2026-07-09T21:00:58.206Z","avatar_url":"https://github.com/khwstolle.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003cimg alt=\"git-third-party\" src=\"docs/assets/logo.svg\" width=\"320\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n# git-third-party\n\nVendor third-party git content into your repo as ordinary files — no submodules.\n\nThree surfaces, one Go core: a `git-third-party` CLI, Python bindings (`import git_third_party`), and Node bindings (`import { add, list, ... } from 'git-third-party'`). All three speak the same `third-party.toml` / `third-party.lock` config and share the same cgo bridge for in-process calls.\n\n`third-party.toml` records each entry's source URL, the ref it tracks, and any filters applied. `third-party.lock` pins the resolved commits. `git-third-party update` re-fetches upstream and stages the changes.\n\n## Why\n\nSubmodules need a second clone, complicate CI, and hide third-party code from grep, build, and IDE tooling. Subtree merges lose provenance. `git-third-party` keeps content in-tree and visible to every tool, with enough metadata to update in one command.\n\n## Requirements\n\n- `git`\n- Go 1.21+ (build only)\n\n## Install\n\n### CLI\n\nPrebuilt binaries cover `linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64`, and `win32-x64`. Pick whichever package manager you already have:\n\n```sh\n# PyPI (wheel ships the binary as a pip script):\nuv tool install git-third-party\npip install --user git-third-party\n\n# npm (main package shells out to the platform-specific binary):\nnpm install -g git-third-party\npnpm add -g git-third-party\n```\n\nBuild from source:\n\n```sh\ngo build -o ~/.local/bin/git-third-party .\n```\n\nThe binary's `git-` prefix lets you invoke it as either `git-third-party` or `git third-party`.\n\n### Python bindings\n\n```sh\nuv tool install git-third-party    # or pip install\n```\n\n```py\nfrom git_third_party import init, add, list_, version\n\nprint(version())\ninit()\nadd(dir=\"vendor/foo\", url=\"https://github.com/x/y\", follow=\"main\")\nfor e in list_():\n    print(e.dir, e.commit)\n```\n\nMutating calls take `dry_run=` and `commit_msg=`. All calls take `repo_path=` (default `.`). Errors map to `GitThirdPartyError` and its subclasses (`ConfigError`, `NetworkError`, `ConflictError`, `CheckDirtyError`).\n\n### Node bindings\n\n```sh\nnpm install git-third-party     # or pnpm/yarn add\n```\n\n```ts\nimport { init, add, list, version } from \"git-third-party\";\n\nconsole.log(version());\ninit();\nadd({ dir: \"vendor/foo\", url: \"https://github.com/x/y\", follow: \"main\" });\nfor (const e of list()) {\n  console.log(e.dir, e.commit);\n}\n```\n\nECMAScript Modules (ESM) only, ships TypeScript types, requires Node ≥ 18. Same options shape as the Python API; same error hierarchy. The bridge serializes calls process-wide — for parallel work, use `worker_threads`.\n\n## Quick start\n\nVendor a directory tracking a remote branch:\n\n```sh\ngit-third-party add third_party/zlib https://github.com/madler/zlib --follow master\ngit commit -m \"Vendor zlib\"\n```\n\nPull updates:\n\n```sh\ngit-third-party update                    # all entries\ngit-third-party update third_party/zlib   # one entry\ngit-third-party status                    # dry-run\ngit commit -m \"Update vendored zlib\"\n```\n\nList, rename, remove:\n\n```sh\ngit-third-party list\ngit-third-party rename third_party/zlib vendor/zlib\ngit-third-party remove third_party/zlib\n```\n\n## Tracking a ref\n\nEach entry tracks exactly one of:\n\n- `--follow \u003cbranch\u003e` — track the branch tip, re-resolving on every `update`. Default when neither flag is set (resolved from the remote's `HEAD`).\n- `--pin \u003ctag-or-sha\u003e` — pin to a tag (resolved once, then cached) or a commit SHA (used as-is). 40-hex-char strings count as SHAs.\n\nSwitch with `git-third-party set \u003cdir\u003e --pin v1.3.1` (or `--follow master`).\n\n## Filtering content\n\nVendor part of an upstream repo:\n\n```sh\ngit-third-party add vendor/foo https://example.com/foo.git \\\n    --subdir src \\\n    --include '*.c' --include '*.h' \\\n    --exclude 'tests/'\n```\n\n- `--subdir` — start from a subdirectory of the upstream repo.\n- `--include` — keep only matching paths (repeatable; default keeps everything).\n- `--exclude` — drop matching paths (repeatable; always wins over `--include`).\n\nPatterns follow `gitignore` rules with documented deviations; see `git-third-party add --help` for the spec. Upstream submodules inline recursively unless excluded.\n\n## Configuration files\n\nTwo files live at the repo root, both committed:\n\n- `third-party.toml` — hand-editable intent. Each `[[third_party]]` table is one vendored directory. Each `add`/`set`/`rename`/`remove` rewrites the file, dropping any user comments.\n- `third-party.lock` — generated. Records the resolved commit and any saved `tree-patch` per entry. Sorted by `dir` for stable diffs. Do not edit by hand.\n\nExample `third-party.toml`:\n\n```toml\n# git-third-party — vendored content config.\n\n[[third_party]]\ndir = \"third_party/zlib\"\nurl = \"https://github.com/madler/zlib\"\nfollow = \"master\"\n\n[[third_party]]\ndir = \"vendor/foo\"\nurl = \"https://example.com/foo.git\"\npin = \"v1.3.1\"\nsubdir = \"src\"\ninclude = [\"*.c\", \"*.h\"]\nexclude = [\"tests/\"]\n```\n\nCorresponding `third-party.lock`:\n\n```toml\n# git-third-party lockfile — generated; do not edit by hand.\nversion = 1\n\n[[third_party]]\ndir = \"third_party/zlib\"\ncommit = \"abc123...\"\n\n[[third_party]]\ndir = \"vendor/foo\"\ncommit = \"def456...\"\n```\n\n## Commands\n\n| Command              | Aliases | Purpose                                                                       |\n| -------------------- | ------- | ----------------------------------------------------------------------------- |\n| `init`               |         | Create an empty `third-party.toml` (most users skip this — `add` creates it). |\n| `add DIR URL`        |         | Register a new entry and download it.                                         |\n| `set DIR …`          | `edit`  | Change URL, ref, or filters for an existing entry.                            |\n| `unset DIR FIELD…`   |         | Clear `subdir`, `include`, or `exclude`.                                      |\n| `update [DIR]`       | `up`    | Re-fetch and stage updates.                                                   |\n| `status [DIR]`       | `st`    | `update --dry-run`.                                                           |\n| `list [DIR]`         | `ls`    | Show entries and their tracking mode.                                         |\n| `info DIR`           | `show`  | Print full details for one entry.                                             |\n| `rename DIR NEW_DIR` | `mv`    | Move a vendored directory and update the config.                              |\n| `remove DIR`         | `rm`    | Unregister a directory and `git rm -r` its content.                           |\n| `patch save DIR`     |         | (experimental) Record local edits as a tree-patch.                            |\n| `patch diff DIR`     |         | (experimental) Show the saved tree-patch via `git diff`.                      |\n| `completion SHELL`   |         | Print a `bash`/`zsh`/`fish`/`powershell` completion script.                   |\n\n### Common flags\n\n- `-v`, `-vv`, `-q` — debug, trace, or warn-only logging.\n- `--log-level=trace|debug|info|warn|error` — explicit level.\n- `--log-format=text|json` — switch the stderr handler to JSON.\n- `--color=auto|always|never` — honors `NO_COLOR`.\n- `--dry-run` — plan without staging.\n- `-f`, `--allow-dir-exists` — let `add`/`rename` write into a non-empty target.\n- `--profile \u003cpath\u003e` — write a CPU profile.\n- `--json` — emit a structured `entryResult` (or array) on stdout instead of human text. Schema lives in `output.go`.\n- `--commit MSG` — run `git commit -m MSG` after the command stages changes.\n- `--check` (on `update`/`status`) — exit non-zero if any entry would change. Useful in CI and pre-commit hooks.\n\n### Exit codes\n\n| Code | Meaning                                                                  |\n| ---- | ------------------------------------------------------------------------ |\n| 0    | success                                                                  |\n| 1    | generic failure                                                          |\n| 2    | configuration invalid (TOML parse, validation, lockfile schema mismatch) |\n| 3    | network, fetch, or ref-resolution failure                                |\n| 4    | unresolvable merge conflict during `update`                              |\n| 5    | `--check` detected a pending change                                      |\n\n## Settings\n\nSettings resolve through five layers, each overriding the previous:\n\n1. Built-in defaults.\n2. Per-user: `git config --global third-party.\u003ckey\u003e`.\n3. Per-repo: a `[settings]` table in `third-party.toml`.\n4. Environment variables.\n5. CLI flags.\n\nEnvironment variables:\n\n- `GIT_THIRD_PARTY_LOG_LEVEL` (`trace`/`debug`/`info`/`warn`/`error`) — same as `--log-level`.\n- `GIT_THIRD_PARTY_LOG_FORMAT` (`text`/`json`) — same as `--log-format`.\n- `GIT_THIRD_PARTY_COLOR` (`auto`/`always`/`never`) — same as `--color`.\n- `GIT_THIRD_PARTY_EXPERIMENTAL` — comma-separated feature names; same as `--experimental`.\n- `NO_COLOR` — standard cross-tool convention; disables ANSI color even when `--color=auto`.\n\nExperimental commands (currently the `patch` subtree) need explicit opt-in: `--experimental=patch` (`-Z patch`), `experimental = [\"patch\"]` under `[settings]`, or `git config --global third-party.experimental patch`.\n\n## Shell completions\n\n```sh\n# bash\nsource \u003c(git-third-party completion bash)\n\n# zsh\ngit-third-party completion zsh \u003e \"${fpath[1]}/_git-third-party\"\n\n# fish\ngit-third-party completion fish \u003e ~/.config/fish/completions/git-third-party.fish\n```\n\n## Editing vendored content (experimental)\n\nEnable with `--experimental=patch` (or set the equivalent in `[settings]` or git-config — see [Settings](#settings)):\n\n- `git-third-party --experimental=patch patch save \u003cdir\u003e` — record local modifications as a tree-level patch in `third-party.lock`. The patch reapplies on every `update` via a 3-way merge.\n- `git-third-party --experimental=patch patch diff \u003cdir\u003e` — show the saved patch.\n\nIf `update` produces conflicts, `git-third-party` stores the patch with a `-conflicts` suffix; resolve with `git add` followed by another `patch save`. Review the resulting commits carefully — the feature is experimental for a reason.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkhwstolle%2Fgit-third-party","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkhwstolle%2Fgit-third-party","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkhwstolle%2Fgit-third-party/lists"}