chore(dev): run the dev stack in multiple git worktrees

Drop fixed container names so each worktree gets its own containers,
add docker/dev/worktree.sh to set up and tear down a worktree, and
document it under a new Development section in the README.
This commit is contained in:
Herculino Trotta committed 2026-11-08 02:48:59 -03:00
1 parent 914c665faf
commit a691da7523
4 files changed
+98 -5

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
# Shell scripts run inside Linux containers and Git Bash, which fail on CRLF
*.sh text eol=lf
+42
View File
@@ -117,6 +117,48 @@ You can now access localhost:OUTBOUND_PORT
> - If you're planning on running this behind Tailscale or other similar service also add your machine given IP to `DJANGO_ALLOWED_HOSTS` > - If you're planning on running this behind Tailscale or other similar service also add your machine given IP to `DJANGO_ALLOWED_HOSTS`
> - If you're going to use another IP that isn't localhost, add it to `DJANGO_ALLOWED_HOSTS`, without `http://` > - If you're going to use another IP that isn't localhost, add it to `DJANGO_ALLOWED_HOSTS`, without `http://`
## Development
The development stack runs from `docker-compose.dev.yml`:
```bash
$ docker compose -f docker-compose.dev.yml up -d
```
Set `COMPOSE_FILE=docker-compose.dev.yml` in your `.env` to drop the `-f` flag.
### Working in multiple git worktrees
You can run one dev stack per [git worktree](https://git-scm.com/docs/git-worktree), side by side. Each worktree gets its own containers, database and volumes, because Compose names them after the worktree's folder.
A new worktree has no `.env` (it's gitignored). After creating one, run this from the worktree's root:
```bash
$ sh docker/dev/worktree.sh
```
It copies `.env` from your main checkout, gives the worktree its own host ports (printed when it finishes) and installs `frontend/node_modules` for tools you run outside Docker. The database starts empty.
To stop the worktree's containers and delete its volumes before removing it:
```bash
$ sh docker/dev/worktree.sh teardown
```
The commands work on Linux, macOS and Windows (Git Bash or WSL). PowerShell and cmd have no `sh`, so on Windows set up git aliases once in your clone; they run through Git's bundled shell from any terminal, and every worktree of the clone shares them:
```bash
git config alias.wt-setup '!sh docker/dev/worktree.sh'
git config alias.wt-teardown '!sh docker/dev/worktree.sh teardown'
```
Run those two lines in Git Bash or PowerShell; cmd doesn't understand the single quotes.
Then use `git wt-setup` and `git wt-teardown`. Tools that create worktrees for you, such as Orca, Conductor or Superset, usually have setup and archive hooks: put these commands there.
> [!NOTE]
> Ports come from the worktree's folder name, so two worktrees can rarely land on the same ones. If `docker compose up` reports a port in use, change `OUTBOUND_PORT`, `WEBPACK_OUTBOUND_PORT` or `SQL_OUTBOUND_PORT` in that worktree's `.env`.
## Latest changes ## Latest changes
Features are only added to `main` when ready, if you want to run the latest version, you must build from source or use the `:nightly` tag on docker. Keep in mind that there can be undocumented breaking changes. Features are only added to `main` when ready, if you want to run the latest version, you must build from source or use the `:nightly` tag on docker. Keep in mind that there can be undocumented breaking changes.
+11 -5
View File
@@ -11,7 +11,6 @@ services:
context: . context: .
dockerfile: ./docker/dev/django/Dockerfile dockerfile: ./docker/dev/django/Dockerfile
image: wygiwyh_dev_server image: wygiwyh_dev_server
container_name: wygiwyh_dev_server
volumes: volumes:
- ./app/:/usr/src/app/:z - ./app/:/usr/src/app/:z
- ./frontend/:/usr/src/frontend:z - ./frontend/:/usr/src/frontend:z
@@ -21,6 +20,9 @@ services:
- "${OUTBOUND_PORT:-8000}:${INTERNAL_PORT:-8000}" - "${OUTBOUND_PORT:-8000}:${INTERNAL_PORT:-8000}"
env_file: env_file:
- .env - .env
environment:
# The browser loads assets straight from vite, so Django must point at the published port
- DJANGO_VITE_DEV_SERVER_PORT=${WEBPACK_OUTBOUND_PORT:-5173}
depends_on: depends_on:
- db - db
- vite - vite
@@ -31,21 +33,20 @@ services:
context: . context: .
dockerfile: ./docker/dev/vite/Dockerfile dockerfile: ./docker/dev/vite/Dockerfile
image: wygiwyh_dev_node image: wygiwyh_dev_node
container_name: wygiwyh_dev_node
volumes: volumes:
- ./frontend/:/usr/src/frontend - ./frontend/:/usr/src/frontend
- ./app/:/usr/src/app/ - ./app/:/usr/src/app/
# http://jdlm.info/articles/2016/03/06/lessons-building-node-app-docker.html # http://jdlm.info/articles/2016/03/06/lessons-building-node-app-docker.html
- wygiwyh_node_modules:/usr/src/frontend/node_modules - wygiwyh_node_modules:/usr/src/frontend/node_modules
ports: ports:
- '${WEBPACK_OUTBOUND_PORT}:5173' - '${WEBPACK_OUTBOUND_PORT:-5173}:${WEBPACK_OUTBOUND_PORT:-5173}'
environment: environment:
- WATCHPACK_POLLING=true - WATCHPACK_POLLING=true
- VITE_DEV_SERVER_PORT=${WEBPACK_OUTBOUND_PORT:-5173}
restart: unless-stopped restart: unless-stopped
db: db:
image: postgres:15 image: postgres:15
container_name: ${SQL_HOST}
volumes: volumes:
- wygiwyh_dev_postgres_data:/var/lib/postgresql/data/ - wygiwyh_dev_postgres_data:/var/lib/postgresql/data/
environment: environment:
@@ -53,5 +54,10 @@ services:
- POSTGRES_PASSWORD=${SQL_PASSWORD} - POSTGRES_PASSWORD=${SQL_PASSWORD}
- POSTGRES_DB=${SQL_DATABASE} - POSTGRES_DB=${SQL_DATABASE}
ports: ports:
- '${SQL_PORT}:5432' - '${SQL_OUTBOUND_PORT:-${SQL_PORT:-5432}}:5432'
networks:
default:
# Keeps .env files that point SQL_HOST at the old fixed container name working
aliases:
- ${SQL_HOST:-db}
restart: unless-stopped restart: unless-stopped
+43
View File
@@ -0,0 +1,43 @@
#!/bin/sh
# Prepares or tears down the dev environment of an extra git worktree.
# sh docker/dev/worktree.sh copy .env from the main checkout with free host ports, install host node_modules
# sh docker/dev/worktree.sh teardown stop this worktree's containers and delete its volumes
# Plain POSIX sh: no GNU-only flags, so it runs on Linux, macOS and Git for Windows.
set -eu
if [ "${1:-setup}" = "teardown" ]; then
# Without .env compose can't find its config, and nothing was ever started here
[ -f .env ] || exit 0
exec docker compose down -v --remove-orphans
fi
main=$(git worktree list --porcelain | head -n 1 | cut -d ' ' -f 2-)
if [ "$main" = "$(git rev-parse --show-toplevel)" ]; then
echo "This is the main checkout, nothing to do." >&2
exit 0
fi
if [ ! -f .env ]; then
if [ ! -f "$main/.env" ]; then
echo "No .env in the main checkout ($main). Create it from .env.example first." >&2
exit 1
fi
# Same folder name -> same offset, so re-creating a worktree keeps its ports
off=$(( $(basename "$PWD" | cksum | cut -d ' ' -f 1) % 100 + 1 ))
grep -v -E '^(OUTBOUND_PORT|WEBPACK_OUTBOUND_PORT|SQL_OUTBOUND_PORT)=' "$main/.env" > .env || true
{
echo ""
echo "# Host ports for this worktree, set by docker/dev/worktree.sh"
echo "OUTBOUND_PORT=$((18000 + off))"
echo "WEBPACK_OUTBOUND_PORT=$((15100 + off))"
echo "SQL_OUTBOUND_PORT=$((15400 + off))"
} >> .env
echo "Created .env: app on http://localhost:$((18000 + off))"
fi
# For tools run on the host (the vite container keeps its own copy in a volume)
if command -v npm > /dev/null 2>&1; then
npm ci --prefix frontend --no-audit --no-fund
else
echo "npm not found, skipping frontend/node_modules." >&2
fi