Skip to main content

A git remote helper for Google Cloud Storage

Project description

git-remote-gcs

Use Google Cloud Storage as a Git remote. This is a GCP equivalent of awslabs/git-remote-s3.

It provides a git remote helper that lets you use a GCS bucket as a serverless Git server — no VMs, no Secure Source Manager, just a bucket.

Installation

pip install git-remote-gcs

Or install from source:

git clone <this-repo>
cd git-remote-gcs
pip install .

Prerequisites

  1. A GCP project with a GCS bucket (or create one):
gcloud storage buckets create gs://my-git-bucket --location=us-west1
  1. Authentication configured — any of:

    • gcloud auth application-default login (local dev)
    • Service account key via GOOGLE_APPLICATION_CREDENTIALS
    • Workload Identity (GKE)
    • Attached service account (Compute Engine, Cloud Shell)
  2. IAM permissions on the bucket. Minimum required:

    • storage.objects.create
    • storage.objects.get
    • storage.objects.delete
    • storage.objects.list

    The simplest way is the Storage Object Admin role (roles/storage.objectAdmin) on the bucket:

gcloud storage buckets add-iam-policy-binding gs://my-git-bucket \
  --member="user:tyler@zerosumdefense.co" \
  --role="roles/storage.objectAdmin"

For more granular per-repo access using prefixes, see Access Control.

Quick Start

Create a new repo

mkdir my-repo
cd my-repo
git init
git remote add origin gcs://my-git-bucket/my-repo

echo "Hello" > hello.txt
git add -A
git commit -m "initial commit"
git push --set-upstream origin main

Clone a repo

git clone gcs://my-git-bucket/my-repo my-repo-clone

Branches

cd my-repo
git checkout -b feature-branch
touch new_file.txt
git add -A
git commit -m "new feature"
git push origin feature-branch

Access Control

Access is controlled entirely through GCS IAM. You can scope permissions per-repo by using bucket prefixes and IAM conditions:

# Grant access to a specific repo prefix only
gcloud storage buckets add-iam-policy-binding gs://my-git-bucket \
  --member="user:dev@example.com" \
  --role="roles/storage.objectAdmin" \
  --condition="expression=resource.name.startsWith('projects/_/buckets/my-git-bucket/objects/my-repo/'),title=my-repo-access"

Multiple repos can share the same bucket with different prefixes:

gcs://my-git-bucket/repo-a
gcs://my-git-bucket/repo-b
gcs://my-git-bucket/team/project-c

Data Encryption

GCS encrypts all data at rest by default with Google-managed keys. For additional control, use Customer-Managed Encryption Keys (CMEK):

gcloud storage buckets update gs://my-git-bucket \
  --default-encryption-key=projects/PROJECT/locations/LOCATION/keyRings/RING/cryptoKeys/KEY

Concurrent Push Protection

git-remote-gcs uses GCS generation-match preconditions to implement per-reference locking, preventing concurrent pushes to the same branch.

If a lock acquisition fails:

error refs/heads/main "failed to acquire ref lock at my-repo/refs/heads/main/LOCK.lock.
Another client may be pushing. If this persists beyond 60s,
run git-gcs doctor gcs://my-git-bucket/my-repo --lock-ttl 60 to inspect and clear stale locks."

Configure the lock TTL via environment variable:

export GIT_REMOTE_GCS_LOCK_TTL=120  # seconds, default is 60

Managing the Remote

Doctor — diagnose and fix issues

git-gcs doctor gcs://my-git-bucket/my-repo
git-gcs doctor gcs://my-git-bucket/my-repo --delete-bundle  # remove conflicting bundles
git-gcs doctor gcs://my-git-bucket/my-repo --lock-ttl 30    # clear locks older than 30s

Protect/unprotect branches

git-gcs protect gcs://my-git-bucket/my-repo main
git-gcs unprotect gcs://my-git-bucket/my-repo main

Protected branches cannot be force-pushed to or deleted.

Delete a remote branch

git-gcs delete-branch gcs://my-git-bucket/my-repo -b old-feature

Under the Hood

How it works

Bundles are stored in GCS as <prefix>/<ref>/<sha>.bundle.

Push:

  1. Acquire a per-ref lock using GCS generation-match preconditions
  2. Create a git bundle: git bundle create <sha>.bundle <ref>
  3. Upload the bundle to <prefix>/<ref>/<sha>.bundle
  4. Clean up the previous bundle for that ref
  5. Release the lock

Fetch:

  1. List all objects under <prefix>/refs/ to discover refs and SHAs
  2. Download the bundle for each requested ref
  3. Unbundle locally with git bundle unbundle

List:

  1. Scan <prefix>/refs/ for .bundle objects
  2. Extract ref names and SHAs from the object keys
  3. Read <prefix>/HEAD for the default branch

Storage layout

gs://my-git-bucket/my-repo/
├── HEAD                                    # default branch ref
├── refs/
│   ├── heads/
│   │   ├── main/
│   │   │   └── abc123...def.bundle         # branch bundle
│   │   └── feature/
│   │       └── 789abc...012.bundle
│   └── tags/
│       └── v1.0/
│           └── 345def...678.bundle

Debugging

# Verbose output
GIT_REMOTE_GCS_VERBOSE=1 git push origin main

# Or use git's verbosity flag
git -c transfer.verbosity=2 push origin main

Comparison with Alternatives

Feature git-remote-gcs Secure Source Manager GitHub + Cloud Build Gitea on VM
Cost ~$0 (GCS storage) $1,000/mo Free (public) Free tier VM
Managed Yes (GCS) Yes Yes No
IAM integration Native GCP IAM Native GCP IAM Separate None
Setup time Minutes Minutes Minutes 30+ min
UI / PRs No Yes Yes Yes
Serverless Yes Yes N/A No

Inspired By

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

git_remote_gcs-0.1.0.tar.gz (13.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

git_remote_gcs-0.1.0-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file git_remote_gcs-0.1.0.tar.gz.

File metadata

  • Download URL: git_remote_gcs-0.1.0.tar.gz
  • Upload date:
  • Size: 13.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for git_remote_gcs-0.1.0.tar.gz
Algorithm Hash digest
SHA256 128d8f1990211a0dce44881bd654224656e74537c93b66fa9861e3ee50068c34
MD5 e183c83c6c430114bef67059289ad591
BLAKE2b-256 a71567b2d8c3094e4b77b40fb05f4bd66e9e7657ec30cd17769ce02fc1312fd6

See more details on using hashes here.

File details

Details for the file git_remote_gcs-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: git_remote_gcs-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for git_remote_gcs-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d1ed76936aef71844350edc69d86168ff514271849c49e5b86407344a2df98d6
MD5 16a3953c7bbf96901aa54c41e1ba279c
BLAKE2b-256 429b27f43f3f22f0b3dd882dd125f29a08ea56795670cb8f2c7bda92feaf596c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page