← Todos os textos

Cada worktree com a sua própria base de dados

Faço quase todo o meu trabalho em worktrees do git. Tanto a programação com agentes como o desenvolvimento a sério de funcionalidades correm num worktree, para que o que estou a fazer fique isolado das outras frentes. Este fluxo é útil porque posso estar a trabalhar numa coisa, largá-la e passar a outra sem pisar o que tenho aberto ao lado.

Quem diria que os worktrees (uma funcionalidade que ignorei no git help durante uma década) viriam a ser a tecnologia matadora de 2026.

Se não estás familiarizado com os worktrees, podes ler sobre eles aqui.

Há um problema. Os worktrees clonam o teu código. Não clonam nada que não esteja no git, e há duas coisas dessas de que precisas: os ficheiros ignorados pelo git e uma base de dados. Por isso cada worktree que crias liga-se, bem-disposto, ao mesmo Postgres local. No momento em que um ramo corre uma migração, altera o esquema de que os outros três dependem, e lá se vai o meu isolamento perfeito.

Então escrevi uma pequena ferramenta para resolver isto: o wtdb.

A minha configuração é assim:

  • main-repo/: sempre a seguir origin/main, com as migrações a correr depois de cada pull. A cópia de referência limpa.
  • main-repo-worktree-feat-blah-blah/: um worktree de um ramo de funcionalidade com a sua própria base de dados, mais a cache e os node_modules copiados do repositório principal.
  • main-repo-worktree-feat-foo-bar/: outro worktree de um ramo de funcionalidade com a sua própria base de dados, mais a cache e os node_modules copiados do repositório principal.

Quando adiciono um worktree, o wtdb liga-se ao post-checkout do git e faz as três coisas aborrecidas que ninguém configura à mão:

  1. Clona a base de dados. Usa o CREATE DATABASE ... TEMPLATE do Postgres, por isso é uma cópia quase instantânea dos teus dados de desenvolvimento, não um dump e restauro durante o qual vais fazer um café.
  2. Copia o teu ficheiro env e reescreve o URL da base de dados para apontar para a nova cópia.
  3. Copia os bocados ignorados pelo git de que realmente precisas. Isto é node_modules e companhia, com clones copy-on-write, para não gastares espaço em disco.

Agora posso correr um servidor de desenvolvimento contra qualquer worktree e deixar um agente correr as migrações e alterações de esquema que lhe apetecer na sua própria caixa de areia.

Começar é uma instalação e três comandos:

# Always check the source code of a new tool before installing it.
# I know this is a bad practice. I will make this available on homebrew soon. Maybe.
curl -fsSL https://raw.githubusercontent.com/willhackett/wtdb/main/install.sh | sh

wtdb init      # writes a starter .wtdb.json
wtdb install   # installs the post-checkout hook
wtdb sync      # provision the current worktree by hand

A configuração é pequena. É um ficheiro .wtdb.json na raiz do repositório.

{
  "envFile": ".dev.vars",
  "dbEnvVar": "DATABASE_URL",
  "pathsToCopy": ["node_modules", ".next"]
}

pathsToCopy é tudo o que o teu worktree precisa para correr e está ignorado pelo git. O .next aqui pressupõe Next.js, troca-o pela cache de build que usares.

Há também o wtdb status para ver que worktree é dono de que base de dados, e o wtdb prune para largar as órfãs depois de apagares um worktree. Gostava que o git acrescentasse algum tipo de hooks de worktree para eu nem precisar do wtdb prune.

Para já só existe um adaptador para Postgres, porque é o que eu uso. A camada de base de dados é uma interface simples (Copy e Drop), por isso, se usas outra coisa, acrescentar um adaptador demora uns minutos. Os PRs são bem-vindos.

Github: willhackett/wtdb.