serve-git
v0.3.0
Published
Serve the current Git repository through a temporary read-only HTTPS tunnel.
Maintainers
Readme
serve-git
Temporarily serve your current Git repository as a read-only HTTPS remote with one command.
npx serve-gitserve-git creates a disposable bare snapshot of your current branch, exposes it through a Cloudflare Quick Tunnel, keeps that snapshot updated when new commits land on the branch, and removes its temporary resources when you stop it.
It is useful when you need to move local commits from a remote machine without installing your personal SSH key or storing GitHub credentials on that machine.
Quick start
Run inside any Git worktree:
npx serve-gitExample output:
Creating temporary read-only Git tunnel...
Repository: my-project
Branch: main
Commit: abc1234
Ready:
https://random-name.trycloudflare.com/my-project.git
Clone:
git clone https://random-name.trycloudflare.com/my-project.git
Warning: the URL is publicly readable while this process is running.
Press Ctrl-C to close and clean up.On another machine:
git clone https://random-name.trycloudflare.com/my-project.gitOr add it as a temporary remote:
git remote add temp https://random-name.trycloudflare.com/my-project.git
git fetch tempWhen the transfer is complete, press Ctrl-C on the machine running serve-git.
While serve-git is running, new commits on the selected branch are detected automatically. The public URL stays the same, so clients only need to run git fetch again to receive the new commit. The watcher checks for branch changes every two seconds.
Common commands
Serve the current branch:
npx serve-gitServe a specific branch:
npx serve-git --branch mainRemove stale sessions without starting a new tunnel:
npx serve-git --cleanupShow help:
npx serve-git --helpHow it works
serve-git keeps the implementation intentionally small:
- Detects the Git worktree containing the current directory.
- Resolves the current branch, or the branch passed with
--branch. - Creates a disposable single-branch bare snapshot in the system temp directory.
- Expands the snapshot's packed objects into loose Git objects for broad dumb-HTTP client compatibility, including Apple Git.
- Runs
git update-server-infoso the snapshot can be fetched over static HTTP. - Starts a Node.js HTTP server bound only to
127.0.0.1on a random free port. - Reuses
cloudflaredfromPATH, or downloads a temporary binary when necessary. - Opens a Cloudflare Quick Tunnel and prints the public Git URL.
- Cleans up the tunnel, local server, bare snapshot, and invocation-owned files when the process stops.
There are no third-party npm runtime dependencies.
Read-only by design
The local HTTP server only serves static Git files. It does not run:
git-http-backendgit-receive-pack- an SSH server
- any writable Git transport
Clients can clone and fetch, but they cannot push through the generated URL.
This makes serve-git suitable for temporary one-way transfer of Git history.
Crash recovery
Normal shutdown is not the only cleanup mechanism.
Each invocation creates a temporary session directory and writes a small session.json manifest containing the owner process ID, the cloudflared process ID, the exact executable path, the local tunnel target, and the creation time.
If the CLI is terminated with SIGKILL, the terminal disappears, the machine loses power, or ordinary cleanup cannot run, a later invocation automatically scans previous serve-git-* sessions before opening a new tunnel.
A stale session is removed only after its owner process is confirmed dead. If an orphaned cloudflared process is still running, serve-git terminates it only when the live command line matches both the executable and local URL recorded in the manifest. PID equality by itself is never considered sufficient, which protects unrelated processes from PID reuse.
The owner PID is also encoded in the temporary directory name, so a directory can still be recovered if the process dies before its manifest is fully created. Manifest writes use an atomic rename to avoid leaving a partially written final manifest.
You can run the same scavenger manually:
npx serve-git --cleanupActive sessions are left untouched.
Security
The generated trycloudflare.com URL is temporary, but it is not authenticated. Anyone who obtains the URL while the tunnel is active can read the exposed branch history.
The snapshot is created with --single-branch and --no-local, so unrelated refs are not intentionally published through the temporary repository. However, the selected branch's complete reachable Git history is available to clients.
Use serve-git only when that history is safe to expose through a temporary public URL, and stop the process as soon as the transfer is complete.
Requirements
- Node.js 20 or newer
- Git
- Internet access to Cloudflare
- Internet access to GitHub Releases when
cloudflaredis not already installed
Automatic cloudflared download currently supports:
- Linux x64
- Linux arm64
- macOS x64
- macOS arm64
Using an existing cloudflared
If cloudflared is already available on PATH, serve-git reuses it and never deletes it.
You can also select an executable explicitly:
SERVE_GIT_CLOUDFLARED=/path/to/cloudflared npx serve-gitThis is also useful for deterministic testing.
Development
Clone the repository and run:
npm test
npm pack --dry-runThe test suite covers localhost Git cloning, signal cleanup, startup interruption, stale-session cleanup, PID safety checks, and recovery after the parent process is forcibly killed.
License
MIT
Automated releases
Releases are managed by release-please.
On every pull request and push to main, GitHub Actions runs the test suite and verifies the npm package on Node.js 20, 22, and 24.
On main, release-please reads Conventional Commit messages and maintains a release pull request automatically. When that release pull request is merged, it updates package.json, updates CHANGELOG.md, creates the matching GitHub tag and release, and publishes the package to npm.
Typical commit prefixes are:
fix: handle an edge case -> patch release
feat: add a new option -> minor release
feat!: change CLI behavior -> major releaseA BREAKING CHANGE: footer also triggers a major version bump.
npm Trusted Publishing setup
The publish job uses npm Trusted Publishing with GitHub Actions OIDC, so no long-lived npm write token is required in GitHub Secrets.
Trusted Publishing can only be configured after the npm package already exists. For the initial bootstrap:
Create the GitHub repository and push this project.
Add a
repositoryfield topackage.jsonwhose URL exactly matches that GitHub repository.Publish the initial version once with your normal npm account credentials:
npm publishIn npm package settings for
serve-git, add a GitHub Actions trusted publisher for the GitHub repository and set the workflow filename toci-release.yml.Allow the trusted publisher to perform
npm publish.
After that bootstrap, releases are automatic. Merge normal Conventional Commit changes into main, then merge the release-please PR when you are ready to publish the proposed version.
The release job uses Node.js 24 and npm's OIDC authentication. npm automatically attaches provenance for eligible public packages published through Trusted Publishing.
