Peer-to-peer Git over Bluetooth. Push, pull, and clone repositories between nearby Macs without Wi-Fi, internet, or a server.
- Bluetooth L2CAP channels: uses CoreBluetooth's direct L2CAP sockets for high-throughput streaming (no BLE GATT overhead)
- Full Git protocol: reads and writes real Git packfiles via
git pack-objectsandgit index-pack; works with any existing repo - Push, pull, fetch and clone: bidirectional; fetch downloads commits into
refs/remotes/bltgit/without touching the working tree - Connection check: quickly verify Bluetooth reachability and trust setup with
bltgit ping <device> - Remote log: peek at the commit history on another Mac without downloading anything locally
- Remote status: compare local branches with a remote in seconds, with no data transferred
- Chunked, reliable transfer: 60 KB chunks with sequence numbers, ACKs, and retry logic survive transient BT glitches
- Transfer resume: if a connection drops mid-transfer, just retry the same command — it picks up from the last saved checkpoint (at most 8 chunks back)
- Mutual PIN pairing: first-time connections require both sides to confirm a 6-digit PIN; subsequent connections skip it via a local trust store
- Non-blocking async I/O: event-driven stream bridge with no polling loops; the CoreBluetooth RunLoop and async tasks never starve each other
- macOS 13.0 or later
- Swift 5.8 or later (
swift build) - Bluetooth hardware (built into every Mac)
giton both machines (used for packfile generation and application)
git clone <this-repo>
cd bltgit-v2
swift build -c release
# Binary is at .build/arm64-apple-macosx/release/bltgitTo install system-wide:
sudo cp .build/arm64-apple-macosx/debug/bltgit /usr/local/bin/bltgitFor a quick test without installing, you can also just run the debug build:
swift build
.build/arm64-apple-macosx/debug/bltgit --helpRun this in the directory you want to share:
bltgit serve
# Serving repo at /path/to/your/repo...Or point it at a repo somewhere else, without changing directory:
bltgit serve ~/code/my-project
# Serving repo at /Users/you/code/my-project...If the path isn't a git repository, serve says so and exits instead of advertising an empty directory.
The Mac will advertise itself over Bluetooth and wait for connections. It handles both incoming pull and push requests.
bltgit discover
# Found: <DEVICE_NAME> <UUID> RSSI: -52 dBmDiscovery scans for 10 seconds by default. If a device is slow to show up — a busy radio environment, or the other Mac only just started serving — scan for longer:
bltgit discover --timeout 30Use this when you want to confirm the remote is reachable and paired before running pull, push, or clone:
bltgit ping "<DEVICE_NAME>"
# Ping success: paired and connected to <DEVICE_NAME> (<UUID>)Device names are matched case-insensitively, and you can still pass the raw UUID from bltgit discover.
bltgit clone "<DEVICE_NAME>" ./my-project
# or use the UUID from discover:
bltgit clone <UUID> ./my-projectOn first connection you will be asked to confirm a PIN displayed on the other Mac. After pairing, subsequent connections are automatic.
# Inside an existing bltgit-cloned repo:
bltgit pull "<DEVICE_NAME>"Download new commits into refs/remotes/bltgit/ without touching your working tree:
bltgit fetch "<DEVICE_NAME>"
# Fetch complete.
# refs/remotes/bltgit/main
#
# To inspect: git log refs/remotes/bltgit/main
# To merge: git merge refs/remotes/bltgit/mainUseful when you want to review what changed before committing to a merge.
bltgit push "<DEVICE_NAME>"See the last 20 commits on another Mac without pulling anything:
bltgit log "<DEVICE_NAME>"
# Commit log for <DEVICE_NAME>:
# ------------------------------------------------------------
# abc1234 Jane Doe 3 hours ago Fix scanner timeout
# def5678 Bob Smith 1 day ago Add chunked transfer retry
# f1a2b3c Jane Doe 2 days ago Initial commitSee how your local branches compare to another Mac without transferring any data:
bltgit status "<DEVICE_NAME>"
# Status vs <DEVICE_NAME>:
# ------------------------------------------------------------
# develop 2 commits ahead
# feature diverged (1 ahead, 3 behind)
# main up to date
# old-exp local onlyClassifications: up to date, N commits ahead, N commits behind, diverged, remote only, local only, remote has new commits (run bltgit fetch).
See what would change if you pulled from a remote, without merging anything locally:
bltgit diff "<DEVICE_NAME>"
# Shows the diff between local HEAD and refs/remotes/bltgit/<branch>This is useful when you want to inspect incoming changes before deciding whether to fetch, merge, or pull.
bltgit devices
# Trusted devices:
# "<DEVICE_NAME>" (<UUID>) paired Jun 2, 2026- Discovery: the server publishes a BLE advertisement containing a CoreBluetooth L2CAP PSM (channel number) in a GATT characteristic.
- Connection: the client reads the PSM and opens a direct L2CAP socket, bypassing the GATT overhead for raw byte streaming.
- Pairing: both sides exchange a SHA-256 hash of a 6-digit PIN; the trust result is saved to
~/.config/bltgit/trusted_devices.json. - Transfer: Git packfiles are split into 60 KB chunks, each with a sequence number and ACK; the receiver reassembles and passes the result to
git index-pack. - Ref update: after a successful pack import, refs are updated with
git update-refand the working tree is checked out.
- Push always targets
refs/heads/main(current branch resolution not yet implemented) - Large repos (>100 MB pack) will be slower than Wi-Fi but work reliably
- macOS only; iOS does not support L2CAP server mode in CoreBluetooth
