Preventing port conflicts in Git worktrees using directory hashing 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. Preventing port conflicts in git worktrees using directory hashing Coding agents are making git worktree popular because worktrees let multiple agents work on the same repository at the same time without interfering with each other. Each branch is checked out in its own directory: if your main branch lives in main/ , a feature-1 branch can sit right next to it in feature-1/ . However, directory isolation doesn't isolate network ports. When a server in one worktree runs on port 8080 , starting the server in another worktree fails because the address is already in use. At first, I passed ports manually per worktree like PORT=8001 make run , which got tedious. Next, I decided to calculate a deterministic port number for each worktree, using its absolute directory path. Because each worktree lives in a different directory, every environment gets its own port automatically. Hashing the directory path in your Makefile To turn a directory path into a port number, take the SHA-256 hash of the current working directory, convert the hex digest to an integer, and map it into 400 buckets of 5 ports across the 8000 to 9999 range: full path = os.getcwd .encode "utf-8" path hash = int hashlib.sha256 full path .hexdigest , 16 port = 8000 + path hash % 400 5 Spacing base ports 5 numbers apart 8000 , 8005 , 8010 , and so on gives you 400 buckets, making collisions across a handful of local worktrees unlikely while reserving four adjacent ports PORT + 1 through PORT + 4 for secondary services. To avoid changing your application code, you can compute PORT directly in your Makefile and export it as an environment variable: Allocate a 5-port bucket 8000, 8005, ..., 9995 from the worktree's path ifeq $ PORT , export PORT := $ shell python3 -c "import hashlib, os; h = hashlib.sha256 os.getcwd .encode 'utf-8' .hexdigest ; print 8000 + int h, 16 % 400 5 " else export PORT endif .PHONY: run run: @echo "Starting server on http://localhost:$ PORT " @uvicorn main:app --host 0.0.0.0 --port $ PORT If PORT isn't already set, Make runs the Python command once := to calculate the port and exports it to child processes. If you pass a port manually like PORT=9000 make run , the else branch keeps your value and exports it instead. Using ifeq with := rather than PORT ?= avoids re-running the Python subshell every time $ PORT is referenced. Offsetting ports for secondary services Because each worktree gets a 5-port bucket, you can assign up to four secondary services to PORT + 1 through PORT + 4 without colliding with another worktree's base port. Here's an example with the Firestore emulator: FIRESTORE PORT ?= $ shell expr $ PORT + 1 export FIRESTORE EMULATOR HOST ?= 127.0.0.1:$ FIRESTORE PORT .PHONY: emulator emulator: @gcloud emulators firestore start --host-port=$ FIRESTORE EMULATOR HOST expr $ PORT + 1 adds 1 to the base port, and exporting FIRESTORE EMULATOR HOST tells the Google Cloud client libraries in your app and test runner which emulator port to connect to automatically. Passing --host-port=$ FIRESTORE EMULATOR HOST binds the Firestore emulator to that same address on startup.