{"slug": "preventing-port-conflicts-in-git-worktrees-using-directory-hashing", "title": "Preventing port conflicts in Git worktrees using directory hashing", "summary": "A developer published a technique for preventing port conflicts across git worktrees by hashing each worktree's absolute directory path with SHA-256 and mapping the digest into 400 five-port buckets spanning ports 8000 to 9999. The approach, implemented in a Makefile, computes PORT once via `:=` and exports it, reserving PORT+1 through PORT+4 for secondary services such as the Firestore emulator, so parallel coding agents on the same repository no longer collide on port 8080.", "body_md": "# Preventing port conflicts in git worktrees using directory hashing\n\n            Coding agents are making `git worktree` popular because worktrees let\n            multiple agents work on the same repository at the same time without interfering with\n            each other. Each branch is checked out in its own directory: if your\n            *main* branch lives in `main/`, a `feature-1` branch can\n            sit right next to it in `feature-1/`.\n          \n\n            However, directory isolation doesn't isolate network ports. When a server in one\n            worktree runs on port `8080`, starting the server in another worktree fails\n            because the address is already in use.\n          \n\n            At first, I passed ports manually per worktree (like `PORT=8001 make run`),\n            which got tedious. Next, I decided to calculate a deterministic port number for each\n            worktree, using its absolute directory path. Because each worktree lives in a different\n            directory, every environment gets its own port automatically.\n          \n\n## Hashing the directory path in your Makefile\n\n            To turn a directory path into a port number, take the SHA-256 hash of the current\n            working directory, convert the hex digest to an integer, and map it into 400 buckets of\n            5 ports across the `8000` to `9999` range:\n          \n\n```\nfull_path = os.getcwd().encode(\"utf-8\")\npath_hash = int(hashlib.sha256(full_path).hexdigest(), 16)\nport = 8000 + ((path_hash % 400) * 5)\n```\n\n            Spacing base ports 5 numbers apart (`8000`, `8005`,\n            `8010`, and so on) gives you 400 buckets, making collisions across a handful\n            of local worktrees unlikely while reserving four adjacent ports (`PORT + 1`\n            through `PORT + 4`) for secondary services.\n          \n\n            To avoid changing your application code, you can compute `PORT` directly in\n            your `Makefile` and export it as an environment variable:\n          \n\n```\n# Allocate a 5-port bucket (8000, 8005, ..., 9995) from the worktree's path\nifeq ($(PORT),)\nexport PORT := $(shell python3 -c \"import hashlib, os; h = hashlib.sha256(os.getcwd().encode('utf-8')).hexdigest(); print(8000 + ((int(h, 16) % 400) * 5))\")\nelse\nexport PORT\nendif\n\n.PHONY: run\nrun:\n\t@echo \"Starting server on http://localhost:$(PORT)\"\n\t@uvicorn main:app --host 0.0.0.0 --port $(PORT)\n```\n\n            If `PORT` isn't already set, Make runs the Python command once\n            (`:=`) to calculate the port and exports it to child processes. If you pass a\n            port manually (like `PORT=9000 make run`), the `else` branch keeps\n            your value and exports it instead. Using `ifeq` with `:=` rather\n            than `PORT ?=` avoids re-running the Python subshell every time\n            `$(PORT)` is referenced.\n          \n\n## Offsetting ports for secondary services\n\n            Because each worktree gets a 5-port bucket, you can assign up to four secondary services\n            to `PORT + 1` through `PORT + 4` without colliding with another\n            worktree's base port. Here's an example with the Firestore emulator:\n          \n\n```\nFIRESTORE_PORT ?= $(shell expr $(PORT) + 1)\nexport FIRESTORE_EMULATOR_HOST ?= 127.0.0.1:$(FIRESTORE_PORT)\n\n.PHONY: emulator\nemulator:\n\t@gcloud emulators firestore start --host-port=$(FIRESTORE_EMULATOR_HOST)\n```\n\n`expr $(PORT) + 1` adds `1` to the base port, and exporting\n            `FIRESTORE_EMULATOR_HOST` tells the Google Cloud client libraries in your app\n            and test runner which emulator port to connect to automatically. Passing\n            `--host-port=$(FIRESTORE_EMULATOR_HOST)` binds the Firestore emulator to that\n            same address on startup.", "url": "https://wpnews.pro/news/preventing-port-conflicts-in-git-worktrees-using-directory-hashing", "canonical_source": "https://wietsevenema.eu/blog/2026/avoiding-port-conflicts-when-using-git-worktree/", "published_at": "2026-10-16 15:41:02+00:00", "updated_at": "2026-10-16 15:47:14.298413+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents"], "entities": ["git worktree", "Makefile", "SHA-256", "Firestore emulator", "uvicorn", "Google Cloud"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/preventing-port-conflicts-in-git-worktrees-using-directory-hashing", "markdown": "https://wpnews.pro/news/preventing-port-conflicts-in-git-worktrees-using-directory-hashing.md", "text": "https://wpnews.pro/news/preventing-port-conflicts-in-git-worktrees-using-directory-hashing.txt", "jsonld": "https://wpnews.pro/news/preventing-port-conflicts-in-git-worktrees-using-directory-hashing.jsonld"}}