Elton José logo
Elton José
Git Worktrees

Git Worktrees + Agentes: Como Rodar Múltiplos Agentes em Paralelo Sem Conflito de Branch

Git Worktrees + Agentes: Como Rodar Múltiplos Agentes em Paralelo Sem Conflito de Branch
0 visualizações
12 minutos de leitura
#Git Worktrees
Sumário

Git Worktrees + Agentes: Como Rodar Múltiplos Agentes em Paralelo Sem Conflito de Branch

Imagine o seguinte cenário.

Você tem um sprint com três tarefas paralelas: refatorar o módulo de autenticação, escrever testes para o serviço de pagamentos, e implementar a nova feature de notificações. São três tarefas independentes — sem dependências entre si. Deveriam poder acontecer em paralelo.

Você tem acesso a agentes de IA. Por que não colocar três agentes para trabalhar ao mesmo tempo, cada um em uma tarefa?

O problema: todos os três agentes precisariam trabalhar no mesmo repositório. No mesmo working directory. Na mesma branch checada.

O agente de refatoração muda src/auth/middleware.ts. O agente de testes cria src/payments/service.test.ts. O agente de features edita src/notifications/index.ts. Se os três estiverem no mesmo diretório, você tem conflitos de arquivo, estados inconsistentes, e stashes que viram pesadelo.

Git Worktrees resolve isso de forma elegante. É uma feature nativa do Git, existe desde 2015, e a maioria dos devs nunca usou.


O Que São Git Worktrees

Um worktree é um diretório de trabalho associado a um repositório Git. Por padrão, você tem um só — o diretório raiz onde você clonou o repo. Git Worktrees permite criar múltiplos working directories adicionais, cada um com sua própria branch checada, todos compartilhando o mesmo objeto de repositório (o .git/ interno).

A diferença para clonar o repo várias vezes:

# Abordagem ruim: 3 clones separados
~/projects/meu-repo-auth/          # clone 1, branch: feat/auth-refactor
~/projects/meu-repo-payments/      # clone 2, branch: feat/payment-tests
~/projects/meu-repo-notifications/ # clone 3, branch: feat/notifications

# Problemas: ocupa 3x o espaço, mudanças em um não aparecem no outro,
# cada um tem seu node_modules, você precisa sincronizar manualmente

# Abordagem com Worktrees: 1 repo, 3 working directories
~/projects/meu-repo/               # repositório principal (branch: main)
~/projects/meu-repo-wt/auth/       # worktree 1, branch: feat/auth-refactor
~/projects/meu-repo-wt/payments/   # worktree 2, branch: feat/payment-tests
~/projects/meu-repo-wt/notifs/     # worktree 3, branch: feat/notifications

# Vantagens: 1 objeto de repo, git fetch atualiza todos,
# branches visíveis em todos os worktrees, espaço compartilhado para objetos git

Comandos Básicos

# Criar um worktree com uma branch nova
git worktree add ../meu-repo-wt/auth -b feat/auth-refactor

# Criar um worktree com uma branch existente
git worktree add ../meu-repo-wt/payments feat/payment-tests

# Criar um worktree para uma branch remota
git worktree add ../meu-repo-wt/staging origin/staging

# Listar todos os worktrees
git worktree list

# Remover um worktree (depois de fazer merge)
git worktree remove ../meu-repo-wt/auth

# Remover worktree forçado (se tiver mudanças não comitadas)
git worktree remove --force ../meu-repo-wt/auth

# Limpar referências de worktrees removidos manualmente
git worktree prune

Saída do git worktree list:

/Users/elton/projects/meu-repo              abc1234 [main]
/Users/elton/projects/meu-repo-wt/auth      def5678 [feat/auth-refactor]
/Users/elton/projects/meu-repo-wt/payments  ghi9012 [feat/payment-tests]
/Users/elton/projects/meu-repo-wt/notifs    jkl3456 [feat/notifications]

O Workflow com Múltiplos Agentes

Com worktrees, você pode apontar cada instância de Claude Code (ou qualquer agente) para um diretório diferente — e cada um trabalha de forma completamente isolada.

Setup Manual

# 1. Cria os worktrees
git worktree add ../blog-wt/dispatch -b feat/claude-dispatch-post
git worktree add ../blog-wt/steering -b feat/steering-files-post
git worktree add ../blog-wt/kiro -b feat/kiro-post

# 2. Instala dependências em cada worktree
# (ou usa symlinks para node_modules — veja seção de armadilhas)
cd ../blog-wt/dispatch && yarn install
cd ../blog-wt/steering && yarn install
cd ../blog-wt/kiro && yarn install

# 3. Inicia Claude Code em cada worktree (3 terminais)
# Terminal 1:
cd ../blog-wt/dispatch
claude "Cria o post sobre Claude Dispatch em content/20260409_claude_dispatch/index.mdx seguindo o padrão MDX do projeto"

# Terminal 2:
cd ../blog-wt/steering
claude "Cria o post sobre Steering Files em content/20260410_steering_files/index.mdx"

# Terminal 3:
cd ../blog-wt/kiro
claude "Cria o post sobre AWS Kiro em content/20260411_aws_kiro/index.mdx"

Os três agentes trabalham em paralelo, em branches separadas, sem saber da existência um do outro.

Script de Automação

Para times que usam worktrees + agentes com frequência, um script de setup reduz o atrito:

#!/bin/bash
# setup-agent-worktrees.sh

REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
WT_BASE="$HOME/projects/${REPO_NAME}-wt"

setup_worktree() {
  local name=$1
  local branch=$2
  local instruction=$3
  local wt_path="${WT_BASE}/${name}"

  echo "🌿 Criando worktree: $name ($branch)"
  git worktree add "$wt_path" -b "$branch" 2>/dev/null || \
    git worktree add "$wt_path" "$branch"

  echo "📦 Instalando dependências em $name..."
  (cd "$wt_path" && yarn install --frozen-lockfile --silent)

  if [ -n "$instruction" ]; then
    echo "🤖 Iniciando agente em $name..."
    (cd "$wt_path" && claude "$instruction") &
    echo "  PID do agente: $!"
  fi
}

cleanup_worktree() {
  local name=$1
  local wt_path="${WT_BASE}/${name}"

  echo "🧹 Removendo worktree: $name"
  git worktree remove "$wt_path" --force
  git worktree prune
}

# Uso:
# ./setup-agent-worktrees.sh setup auth "Refatora src/auth/ seguindo as specs em .kiro/specs/auth/"
# ./setup-agent-worktrees.sh cleanup auth

case "$1" in
  setup)   setup_worktree "$2" "feat/$2-$(date +%Y%m%d)" "$3" ;;
  cleanup) cleanup_worktree "$2" ;;
  list)    git worktree list ;;
esac
Diagrama de 3 agentes Claude Code rodando em paralelo em worktrees separados do mesmo repositório Git

Integração com Claude Code

O Claude Code tem uma feature nativa que usa worktrees internamente: quando você usa o parâmetro isolation: "worktree" em tasks do Agent SDK, o agente recebe automaticamente um worktree isolado para trabalhar.

Para quem usa Claude Code como orquestrador de subagentes, você pode configurar isso explicitamente:

// Orquestrando múltiplos agentes com worktrees isolados
const tasks = [
  {
    description: "Refatorar módulo de autenticação",
    isolation: "worktree",
    prompt: `Refatora src/auth/ seguindo as specs em .kiro/specs/auth/.
             Execute yarn type-check e yarn test antes de finalizar.`
  },
  {
    description: "Escrever testes para payment service",
    isolation: "worktree",
    prompt: `Cria testes unitários e de integração para src/payments/service.ts.
             Coverage mínimo de 90%. Use Vitest.`
  },
  {
    description: "Implementar feature de notificações",
    isolation: "worktree",
    prompt: `Implementa o módulo de notificações conforme spec em
             .kiro/specs/notifications/. Inclui testes.`
  }
];

// Claude Code cria um worktree por task, roda em paralelo,
// e retorna o resultado de cada um independentemente

Quando a task termina com isolation: "worktree", o Claude Code retorna o caminho do worktree e a branch criada — você então decide se faz merge, abre um PR, ou descarta.


Armadilhas e Como Evitar

node_modules em Cada Worktree

O problema mais comum: cada worktree precisa de suas próprias dependências instaladas. Para projetos grandes com node_modules pesado, isso pode consumir muito espaço em disco.

Solução 1 — Symlink: se a versão do package.json é idêntica em todos os worktrees (o que é o caso se estão todos na mesma base de código), você pode criar um symlink:

# Após criar o worktree
cd ../meu-repo-wt/auth
ln -s ../../meu-repo/node_modules ./node_modules

Funciona bem para projetos onde os worktrees divergem pouco do main. Não funciona se cada worktree vai adicionar dependências diferentes.

Solução 2 — pnpm: o pnpm usa hard links e um store global de pacotes, então o custo de node_modules por worktree é muito menor. Se você está em um projeto novo, pnpm + worktrees é uma combinação muito eficiente.

Lock Files Conflitando

Se dois agentes em worktrees diferentes rodarem yarn add ou npm install ao mesmo tempo, os lock files podem ficar em estados inconsistentes. A regra simples: não deixe agentes modificar package.json ou lock files sem aprovação explícita. Coloque isso no seu CLAUDE.md:

## Restrições

- NÃO modifique package.json ou yarn.lock sem aprovação explícita
- NÃO rode `yarn add` ou `npm install` para novas dependências

Variáveis de Ambiente

Se você usa .env no projeto, cada worktree precisa do seu próprio .env. Geralmente o .env está no .gitignore, então não é copiado automaticamente para o novo worktree.

# Após criar o worktree, copia o .env
cp .env ../meu-repo-wt/auth/.env

Para projetos com variáveis de ambiente complexas, um script de setup que copia o .env base é útil.

Branches Já Checadas

Uma restrição do Git: você não pode ter a mesma branch checada em dois worktrees ao mesmo tempo. Se você tentar:

git worktree add ../wt/novo feat/branch-ja-checada
# Error: 'feat/branch-ja-checada' is already checked out

Solução: sempre crie uma branch nova por worktree, ou verifique antes com git worktree list.

Processos que Assumem CWD

Alguns scripts assumem que o current working directory é a raiz do repositório. Em worktrees, o REPO_ROOT pode ser diferente do GIT_DIR. Para scripts que usam __dirname ou process.cwd() em Node.js, isso geralmente não é problema. Para scripts shell que fazem cd $(git rev-parse --show-toplevel), funciona normalmente.


Worktrees em CI/CD: Paralelismo Além do Dev Local

O uso de worktrees não precisa ficar restrito ao ambiente de desenvolvimento local. Em pipelines de CI/CD, worktrees permitem que múltiplos jobs de agente trabalhem no mesmo repositório em paralelo sem interferência.

Um caso concreto: imagine um pipeline que roda semanalmente e executa quatro agentes em paralelo, cada um melhorando um aspecto diferente do código:

# .github/workflows/ai-improvement-pipeline.yml

name: Weekly AI Improvement Pipeline

on:
  schedule:
    - cron: '0 3 * * 1'  # Toda segunda às 3h

jobs:
  setup:
    runs-on: ubuntu-latest
    outputs:
      worktree-base: ${{ steps.setup.outputs.path }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # precisa do histórico completo para worktrees

      - name: Setup worktrees
        id: setup
        run: |
          git config user.email "[email protected]"
          git config user.name "CI Agent"
          echo "path=$(pwd)" >> $GITHUB_OUTPUT

  agent-test-coverage:
    needs: setup
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Create worktree for test coverage
        run: |
          git worktree add ../wt-coverage -b improvement/test-coverage-$(date +%Y%m%d)
          cd ../wt-coverage
          # Roda Claude Code para melhorar cobertura de testes
          npx claude "Analisa os arquivos em src/ com coverage < 70%.
                      Para cada um, adiciona testes unitários até atingir
                      80% de cobertura. Use Vitest."

  agent-accessibility:
    needs: setup
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Create worktree for accessibility
        run: |
          git worktree add ../wt-a11y -b improvement/accessibility-$(date +%Y%m%d)
          cd ../wt-a11y
          npx claude "Revisa todos os componentes React em src/components/.
                      Adiciona aria-label onde falta, corrige contraste de
                      cores, garante navegação por teclado."

Cada job roda em um runner separado, com seu próprio worktree, em sua própria branch. O resultado são PRs independentes que o time pode revisar e mergear separadamente.

Isso não é ficção científica — é uma extensão natural de como CI/CD já funciona, combinada com a capacidade dos agentes de fazer trabalho de código real.


Pattern: Orquestrador de Worktrees

Para times que adotam paralelismo de agentes como prática regular, faz sentido ter um orquestrador que gerencia o ciclo de vida dos worktrees de forma mais sofisticada:

# worktree_orchestrator.py

import subprocess
import os
from dataclasses import dataclass
from typing import Optional
from pathlib import Path

@dataclass
class AgentTask:
    name: str
    branch: str
    instruction: str
    base_branch: str = "main"

class WorktreeOrchestrator:
    def __init__(self, repo_root: str, wt_base: str):
        self.repo_root = Path(repo_root)
        self.wt_base = Path(wt_base)
        self.wt_base.mkdir(parents=True, exist_ok=True)
        self.active_worktrees: dict[str, Path] = {}

    def create(self, task: AgentTask) -> Path:
        wt_path = self.wt_base / task.name
        branch = task.branch

        # Cria branch a partir da base especificada
        subprocess.run([
            "git", "worktree", "add",
            str(wt_path), "-b", branch,
            task.base_branch
        ], cwd=self.repo_root, check=True)

        # Copia .env se existir
        env_file = self.repo_root / ".env"
        if env_file.exists():
            (wt_path / ".env").write_text(env_file.read_text())

        self.active_worktrees[task.name] = wt_path
        return wt_path

    def run_agent(self, task: AgentTask) -> Optional[str]:
        wt_path = self.create(task)

        result = subprocess.run(
            ["claude", "--dangerously-skip-permissions", task.instruction],
            cwd=wt_path,
            capture_output=True,
            text=True
        )

        return result.stdout if result.returncode == 0 else None

    def cleanup(self, name: str):
        if name not in self.active_worktrees:
            return
        wt_path = self.active_worktrees[name]
        subprocess.run([
            "git", "worktree", "remove", str(wt_path), "--force"
        ], cwd=self.repo_root)
        subprocess.run(["git", "worktree", "prune"], cwd=self.repo_root)
        del self.active_worktrees[name]

    def cleanup_all(self):
        for name in list(self.active_worktrees.keys()):
            self.cleanup(name)


# Uso:
orchestrator = WorktreeOrchestrator(
    repo_root="/Users/elton/projects/blog",
    wt_base="/Users/elton/projects/blog-wt"
)

tasks = [
    AgentTask(
        name="auth-refactor",
        branch="feat/auth-refactor",
        instruction="Refatora src/auth/ seguindo as specs em .kiro/specs/auth/"
    ),
    AgentTask(
        name="payment-tests",
        branch="feat/payment-tests",
        instruction="Adiciona testes para src/payments/service.ts. Coverage >= 90%."
    ),
]

# Executa em paralelo via threads ou asyncio
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor(max_workers=len(tasks)) as executor:
    futures = [executor.submit(orchestrator.run_agent, task) for task in tasks]
    results = [f.result() for f in futures]

# Limpa worktrees após uso
orchestrator.cleanup_all()

Esse padrão transforma worktrees de uma ferramenta manual para uma primitiva de orquestração programática — o que é exatamente o nível de abstração certo para times que querem escalar o uso de agentes de forma confiável.


Quando Não Usar Worktrees

Worktrees são ótimos para tarefas paralelas independentes. Eles não são a solução certa para:

Tarefas com dependências entre si: se o agente de autenticação precisa que o agente de testes termine primeiro para validar algo, worktrees não ajudam — o problema é de orquestração, não de isolamento.

Revisão contínua de código: se você quer que um agente revise o código que outro está escrevendo em tempo real, worktrees separados dificultam isso. Nesse caso, um único agente com acesso a ambas as branches é melhor.

Projetos com estado externo compartilhado: se os agentes precisam compartilhar um banco de dados local, um servidor de desenvolvimento, ou qualquer recurso externo, worktrees não resolvem o problema de conflito — apenas o de isolamento de código.


O Padrão no Ecossistema

O uso de worktrees para isolamento de agentes está se tornando um padrão emergente. O Claude Code já usa internamente. O Kiro tem planos de integração nativa conforme o produto amadurece. Frameworks como AutoGen e CrewAI estão adicionando suporte a ambientes isolados por agente.

Para times que estão evoluindo de "1 agente por vez" para "múltiplos agentes em paralelo", aprender Git Worktrees hoje é um investimento de baixo custo com retorno imediato. É uma feature nativa do Git — sem dependências novas, sem ferramentas extras, sem custos adicionais.


Recursos

Newsletter

Receba os artigos mais relevantes da semana, sem quebrar seu ritmo de leitura

Um resumo semanal com os melhores posts sobre IA, engenharia de software e tecnologia, enviado no melhor momento para continuar a conversa depois da leitura.

Foto de Elton José

Escrito por

eltonjose

Engenheiro de software e estrategista de produtos digitais, focado em IA pragmática e em transformar experiências de trabalho remoto em aprendizados aplicáveis. Compartilho frameworks e decisões reais que uso em consultorias e projetos.

  • Principais temasGit Worktrees, Agentic AI
  • Formato do conteúdoGuia prático + insights de carreira