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

Newsletter

Receba os melhores artigos toda semana

Sem spam. Só conteúdo de qualidade sobre IA & Dev.

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

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