{"id":51470662,"url":"https://github.com/dekobon/git-remote-object-store","last_synced_at":"2026-07-06T17:01:22.540Z","repository":{"id":357980807,"uuid":"1220943074","full_name":"dekobon/git-remote-object-store","owner":"dekobon","description":"Use an object store as a git remote and LFS server","archived":false,"fork":false,"pushed_at":"2026-06-16T01:16:40.000Z","size":2718,"stargazers_count":4,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-16T02:23:06.147Z","etag":null,"topics":["azure-blob","azure-blob-storage","git","git-lfs","git-remote-helper","object-storage","rust","s3","vcs"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dekobon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-25T14:46:00.000Z","updated_at":"2026-06-16T01:16:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dekobon/git-remote-object-store","commit_stats":null,"previous_names":["dekobon/git-remote-object-store"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/dekobon/git-remote-object-store","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dekobon%2Fgit-remote-object-store","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dekobon%2Fgit-remote-object-store/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dekobon%2Fgit-remote-object-store/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dekobon%2Fgit-remote-object-store/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dekobon","download_url":"https://codeload.github.com/dekobon/git-remote-object-store/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dekobon%2Fgit-remote-object-store/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35199360,"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-06T02:00:07.184Z","response_time":106,"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":["azure-blob","azure-blob-storage","git","git-lfs","git-remote-helper","object-storage","rust","s3","vcs"],"created_at":"2026-07-06T17:01:21.757Z","updated_at":"2026-07-06T17:01:22.527Z","avatar_url":"https://github.com/dekobon.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# git-remote-object-store\n\n[![CI](https://github.com/dekobon/git-remote-object-store/actions/workflows/ci.yml/badge.svg?branch=main\u0026event=push)](https://github.com/dekobon/git-remote-object-store/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush)\n[![CodeQL](https://github.com/dekobon/git-remote-object-store/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/dekobon/git-remote-object-store/actions/workflows/codeql.yml?query=branch%3Amain)\n[![crates.io](https://img.shields.io/crates/v/git-remote-object-store.svg)](https://crates.io/crates/git-remote-object-store)\n\n**Push, fetch, and clone Git repositories straight against a S3 compatible store or\nAzure Blob Storage. No intermediary servers. One static binary, one object store.**\n\n```bash\ngit remote add origin 's3+https://my-bucket.s3.us-west-2.amazonaws.com/my-repo'\ngit push -u origin main\n```\n\nOr, with Azure:\n\n```bash\ngit remote add origin 'az+https://myaccount.blob.core.windows.net/my-container/my-repo?credential=PROD'\ngit push -u origin main\n```\n\nThat's it. Your bucket is your remote.\n\n## Why?\n\nYou want a private Git remote that is:\n\n- **Owned by you, not a vendor.** No SaaS subscription, no per-seat\n  cost, no \"the host got breached\" risk for your private code. Just\n  a bucket or container in an account you already control.\n- **Backed by storage you already trust.** Encryption at rest,\n  IAM/RBAC at the prefix or container, lifecycle policies, regional\n  replication, audit logs — every control your cloud storage gives\n  you, with no application server in between.\n- **One small binary.** No Python runtime, no Docker image, no\n  webhook endpoint to babysit.\n\nUse cases that fit naturally:\n\n- Private repos you do not want on GitHub or GitLab.\n- Internal libraries hosted on your team's existing S3 / Azure tenant.\n- Repos consumed by AWS CodePipeline (use `?zip=1` to mirror each push\n  as `repo.zip` next to the bundle).\n- Air-gapped or sovereign-cloud environments where SaaS Git hosts are\n  not an option.\n\n## What you get\n\n- **Two backends behind one trait.** AWS S3 and Azure Blob Storage,\n  plus any S3-compatible endpoint (MinIO, Cloudflare R2, Wasabi,\n  Backblaze B2, RustFS, on-prem appliances).\n- **Two storage engines.** A `bundle` engine (one git bundle per\n  push, simple and self-contained) and a `packchain` engine (newest-\n  first pack manifest with GC and compaction, smaller fetches on\n  active repos). Pick per-remote with `?engine=`; default is\n  `bundle`. See [docs/storage-engines.md](docs/storage-engines.md)\n  for the comparison and when to choose which.\n- **Streaming uploads end-to-end.** No in-memory buffering of bundles,\n  no 5 GiB single-PUT ceiling — multipart upload is wired into both\n  backends.\n- **Locking parity across backends.** `If-None-Match: *` on S3,\n  mirrored on Azure; same TTL semantics; tested across both.\n\n## Quick install\n\nSee [docs/getting-started.md](docs/getting-started.md) for the full\nwalkthrough — install, credentials for both clouds, your first push,\nLFS, submodules, local development against MinIO and Azurite.\n\nThe short version:\n\n```bash\ncargo xtask install\n```\n\nThat runs `cargo install --path cli` and creates the four `+`-form\nhelper symlinks (`git-remote-s3+https`, `git-remote-s3+http`,\n`git-remote-az+https`, `git-remote-az+http`) alongside the cargo\nbinaries, which is what git looks up by URL scheme. Re-runs are\nidempotent. Pass `--bin-dir \u003cPATH\u003e` to install into a custom\ndirectory, `--no-install` to refresh the symlinks only, or\n`--dry-run` to preview.\n\n## Using as a library\n\n`git-remote-object-store` is also a Rust library crate. `Remote` is\nthe entry point for reading and writing objects in the on-bucket\nformat; the `ObjectStore` trait and the S3 / Azure backends are also\npublicly exported for building custom storage integrations. See\n[docs/library-usage.md](docs/library-usage.md) for a worked example\nand [docs.rs](https://docs.rs/git-remote-object-store) for the full\nAPI.\n\n## Documentation\n\n- [Getting started](docs/getting-started.md) — install, credentials,\n  first push, LFS, submodules, local dev with MinIO / Azurite,\n  troubleshooting.\n- [Storage engines](docs/storage-engines.md) — `bundle` vs\n  `packchain`, trade-offs, on-bucket layout, when to choose which.\n- [Environment variables](docs/environment-variables.md) — every\n  variable the helpers, CLI, and test suites read.\n- [Library usage](docs/library-usage.md) — using the crate as a Rust\n  library.\n- [Verifying releases](docs/verifying-releases.md) — signature,\n  attestation, and SBOM verification.\n- [Changelog](CHANGELOG.md).\n- [Lessons learned](docs/development/lessons_learned.md).\n\n## Testing\n\n`make shellspec` runs the fast CLI unit suite. The end-to-end shellspec\nsuites drive `git push` / `git fetch` / `git clone` through the helper\nbinaries against real backend containers; they require Docker, the\nmatching cloud CLI on the host, and `git-lfs` for the LFS scenarios.\n\n```bash\nmake shellspec-integration-s3       # requires docker + aws-cli + git-lfs\nmake shellspec-integration-azure    # requires docker + azure-cli + git-lfs\nmake shellspec-integration          # both\n```\n\n## Status\n\nThe shipping surface covers both storage engines (`bundle` and\n`packchain`), both backends (S3 and Azure Blob), the helper-protocol\nREPL, parallel `fetch`, locked `push`, the management CLI (`doctor`,\n`delete-branch`, `protect`, `unprotect`, `gc`, `compact`), the LFS\ncustom-transfer agent, and the signed release pipeline. See\n[`CHANGELOG.md`](CHANGELOG.md) for the current release.\n\nGit operations are gitoxide-backed end to end — bundle read/write is\nnative via `gix-pack`, and the crate spawns no `git` subprocess in\nproduction code. The `gix` surface in use covers rev-parse,\nis-ancestor, ref-name validation, remote-URL inspection, archive,\nlast-commit-message, ref discovery, and object resolution.\n\n## Known limitations\n\nA push of a multi-GB monorepo will work today on either backend —\nmultipart upload is wired into both — but a few sharp edges are worth\nknowing about before you start:\n\n- **No resume after a failed upload.** If the helper process dies\n  mid-push (network blip, signal, reboot), the next `git push`\n  re-uploads the bundle from the beginning. S3 cleans up abandoned\n  multipart sessions per the bucket's lifecycle policy; Azure\n  uncommitted blocks expire after seven days. Neither backend\n  surfaces a \"resume from byte N\" handle today.\n- **Object-size ceilings are the cloud's, not ours.** S3 caps a\n  single object at 5 TiB and a multipart upload at 10 000 parts; the\n  single-`PutObject` ceiling is still 5 GiB but the helper auto-\n  promotes large bodies to multipart well below that. Azure caps a\n  block blob at 50 000 committed blocks (~4.75 TiB at the SDK's\n  default block size). Repositories whose individual bundles\n  approach those limits are outside what either backend can store.\n\n## Verifying releases\n\nEvery `v*` tag publishes signed, attested artefacts (minisign over\n`SHA256SUMS`, SLSA build provenance, CycloneDX SBOMs) to\n[GitHub Releases](https://github.com/dekobon/git-remote-object-store/releases).\nSee [docs/verifying-releases.md](docs/verifying-releases.md) for the\nverification recipe and [`SECURITY.md`](SECURITY.md) for vulnerability\nreporting.\n\n## License\n\nApache-2.0. See [LICENSE](LICENSE).\n\n## Credits\n\nInspired by [`awslabs/git-remote-s3`](https://github.com/awslabs/git-remote-s3),\nwhich itself draws on\n[`bgahagan/git-remote-s3`](https://github.com/bgahagan/git-remote-s3)\nand the LFS work in\n[`nicolas-graves/lfs-s3`](https://github.com/nicolas-graves/lfs-s3).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdekobon%2Fgit-remote-object-store","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdekobon%2Fgit-remote-object-store","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdekobon%2Fgit-remote-object-store/lists"}