Skip to content

Repository files navigation

comport

Deterministic port allocator for git worktrees. Assigns a stable, collision-resistant set of port numbers based on the worktree path so that multiple worktrees of the same project can run their services simultaneously without port conflicts.

How it works

comport hashes the git worktree path (FNV-1a 64-bit) and maps it to a slot in a configurable port range (default 10000--59999). Each service gets a consecutive port starting from the slot's base port. Because the hash is deterministic, the same worktree always gets the same ports.

Service names are resolved in the following priority:

  1. --names flag (comma-separated)
  2. Auto-detection from compose.yaml / docker-compose.yaml
  3. Fallback to --num-services (numeric indices)

Installation

Download a prebuilt binary from the Releases page. Binaries are available for:

  • x86_64-linux
  • aarch64-linux
  • x86_64-macos
  • aarch64-macos
# Example: download and install on Linux x86_64
curl -sL https://api.github.com/repos/windymelt/comport/releases/latest \
  | grep -o 'https://[^"]*comport-[^"]*x86_64-linux' \
  | xargs curl -Lo comport
chmod +x comport
sudo mv comport /usr/local/bin/

Verifying a download

Every release ships a checksums.txt, and each binary carries a build provenance attestation tying it to the workflow run that produced it.

# Check the SHA-256 digest. Do this before renaming the file, since
# checksums.txt records the original comport-<version>-<target> names.
curl -sLO https://github.com/windymelt/comport/releases/latest/download/checksums.txt
sha256sum --check --ignore-missing checksums.txt

# Confirm the binary came from this repository's release workflow
gh attestation verify comport-0.1.0-x86_64-linux --repo windymelt/comport

Build from source

Requires sbt (2.x), JDK 17+, and Clang/LLVM for Scala Native linking.

# Run directly
sbt run

# Build native binary (produces ./comport)
./build.sh

Usage

Run comport inside a git repository. It outputs shell export statements that you can eval:

eval "$(comport)"

Options

  --num-services <int>   Number of services (used when --names is not specified
                         and no compose file is found). Default: 1
  --names <string>       Service names (comma-separated). Overrides compose file
                         auto-detection when specified
  --prefix <string>      Environment variable prefix. Default: PORT
  --base <int>           Start of the port range. Default: 10000
  --range <int>          Width of the port range. Default: 50000
  --show                 Show allocation info on stderr
  --dotenv               Output in .env format without export
  --version              Print the version and exit

--version reports the release tag the binary was built from:

$ comport --version
comport 0.1.0

Binaries built locally with ./build.sh report 0.0.0-SNAPSHOT unless COMPORT_VERSION is set in the environment.

Examples

Auto-detect from compose file

If your worktree has a compose.yaml with services web and db:

$ comport --show
export PORT_BASE=34210
export PORT_DB=34210
export PORT_WEB=34211

Explicit service names

$ comport --names api,worker,redis --prefix SVC
export SVC_BASE=28430
export SVC_API=28430
export SVC_WORKER=28431
export SVC_REDIS=28432

.env file output

comport --dotenv > .env

Use in docker compose

You can reference the allocated ports in compose.yaml:

services:
  web:
    ports:
      - "${PORT_WEB}:8080"
  db:
    ports:
      - "${PORT_DB}:5432"
eval "$(comport)" && docker compose up

Use with direnv

Add the following to your .envrc:

eval "$(comport)"

Whenever you cd into the worktree, direnv will automatically export the allocated ports.

License

BSD 3-Clause License. See LICENSE.

About

Docker Compose worktree port assigner: randomize port to avoid collision between worktree

Resources

Stars

30 stars

Watchers

1 watching

Forks

Releases

Contributors

Languages