Пятница, 17:43. Твоя модель тренируется уже шесть часов. Loss красиво падает, метрики растут — ещё пара эпох и можно будет отправить результаты с победным эмодзи.
И тут приходит сообщение: «Срочно глянь PR, блокер для релиза».
Ты смотришь на терминал. Потом в чат. Потом снова на терминал.
git checkout feature/urgent-fix убьёт твой эксперимент. git stash — это русская рулетка для ML-кода с его конфигами, весами и кешами. Клонировать репозиторий заново? 47 гигабайт датасетов скажут тебе «спасибо».
Знакомо?
Большинство ML-инженеров живут в этом аду переключения контекста годами. А потом узнают про git worktree — и мир делится на «до» и «после».
Что такое Git Worktree (в двух словах)
Git worktree позволяет держать несколько веток в разных папках одновременно, при этом все они используют один .git. Никакого клонирования, никакого дублирования истории, никаких конфликтов при переключении.
Одна команда — и у тебя параллельная вселенная для эксперимента. Ещё одна — и ты ревьюишь PR коллеги, пока твоя модель спокойно тренируется в соседней директории.
Содержание
Часть 1: Основы Git Worktree — концепция, команды, структура
Часть 2: Worktree vs Альтернативы — почему не stash/clone/branches
Часть 3: ML-специфичные сценарии — параллельные эксперименты, изоляция environments, большие датасеты
Часть 4: Интеграция с Cursor — multi-root workspaces, tasks, настройки
Часть 5: Продвинутые техники — bare repos, автоматизация, cleanup
Заключение — takeaways и cheatsheet
К концу статьи у тебя будет готовый workflow, который можно внедрить в свой проект за 10 минут.
Погнали.
Часть 1: Основы Git Worktree
Аналогия, которая всё объясняет
Представь, что твой git-репозиторий — это офис. Обычно у тебя один рабочий стол (working directory), и чтобы переключиться на другую задачу, тебе нужно убрать все бумаги в ящик (stash), переложить новые, поработать, потом вернуть старые обратно.
Worktree — это когда у тебя появляется второй рабочий стол в том же офисе. Все шкафы с документами (.git) общие, но столов несколько. Можешь работать за одним, пока на другом разложен незавершённый проект.
В терминах git: один репозиторий, несколько рабочих директорий, каждая на своей ветке.
Базовые команды
Всё, что тебе нужно знать для старта — четыре команды:
Создать новый worktree:
# Создать worktree для существующей ветки git worktree add ../ml-classifier-experiment experiment/lr-sweep # Создать worktree с новой веткой git worktree add -b feature/new-arch ../ml-classifier-new-arch main
Посмотреть все worktrees:
git worktree list
Вывод будет примерно таким:
/home/user/ml-image-classifier abc1234 [main] /home/user/ml-classifier-experiment def5678 [experiment/lr-sweep] /home/user/ml-classifier-new-arch ghi9012 [feature/new-arch]
Удалить worktree:
git worktree remove ../ml-classifier-experiment
Почистить «мёртвые» записи:
git worktree prune
Это если ты удалил папку руками, а git ещё помнит о ней.
Структура директорий
Вот как это выглядит на диске:
~/projects/ ├── ml-image-classifier/ # Основной репозиторий (main) │ ├── .git/ # Единственный .git на все worktrees │ ├── src/ │ ├── data/ → /shared/datasets/ # Симлинк на данные │ ├── models/ │ └── train.py │ ├── ml-classifier-exp-lr-001/ # Worktree 1 (experiment/lr-sweep) │ ├── .git # Это ФАЙЛ, не папка! Ссылка на основной .git │ ├── src/ │ ├── data/ → /shared/datasets/ # Тот же симлинк │ ├── models/ │ └── train.py │ └── ml-classifier-transformer/ # Worktree 2 (feature/transformer) ├── .git # Тоже файл-ссылка ├── src/ └── ...
Важно: В worktree
.git— это текстовый файл с одной строкой:gitdir: /path/to/main/repo/.git/worktrees/name. Вся история, все объекты хранятся в основном репозитории.
Связь с ветками: правило одной ветки
Git не даст тебе создать два worktree на одной ветке. Логика простая: если ты редактируешь файлы в двух местах на одной ветке — это путь к безумию и конфликтам.
# Это сработает git worktree add ../exp-1 experiment/lr-001 # А это — нет, если experiment/lr-001 уже занята git worktree add ../exp-2 experiment/lr-001 # fatal: 'experiment/lr-001' is already checked out at '/home/user/exp-1'
Хочешь второй эксперимент — создай вторую ветку. Это не баг, это фича.
До и после: наглядно
Раньше (классический git):
# Тренируешь модель на feature/experiment-1 python train.py --lr 0.001 # Запущено, ждём 6 часов... # Нужно срочно посмотреть другую ветку git stash # Молимся, что ничего не сломается git checkout main # Смотрим код, делаем фикс git checkout feature/experiment-1 git stash pop # Иногда работает, иногда — конфликты python train.py --lr 0.001 # Начинаем заново...
Теперь (с worktree):
# В основной папке тренируем модель cd ~/ml-image-classifier python train.py --lr 0.001 # Запущено, работает... # Нужно глянуть main? Без проблем git worktree add ../ml-classifier-hotfix main cd ../ml-classifier-hotfix # Делаем что нужно, модель в соседней папке продолжает тренироваться # Закончили — удаляем cd .. git worktree remove ml-classifier-hotfix
Никаких stash, никаких прерванных экспериментов, никакой боли.
Часть 2: Worktree vs Альтернативы
«Окей, но я и так справляюсь с branches/stash/clone» — скажешь ты. Давай разберём, почему для ML-проектов worktree выигрывает почти всегда.
Таблица сравнения
Критерий | git checkout | git stash | git clone | git worktree |
|---|---|---|---|---|
Скорость переключения | Мгновенно | Мгновенно | Минуты | Мгновенно |
Параллельная работа | Нет | Нет | Да | Да |
Дисковое пространство | Минимум | Минимум | x2-3 репо | +~1% на worktree |
Сохранение процессов | Убивает | Убивает | Изолированы | Изолированы |
Общая история | Одна | Одна | Копии | Одна |
Синхронизация веток | Авто | Авто | Ручная | Авто |
Риск потери данных | Средний | Высокий | Низкий | Низкий |
Разбор каждого подхода
Git Checkout (переключение веток)
git checkout feature/experiment-2
Плюсы:
Просто и привычно
Нет накладных расходов
Минусы:
Убивает все запущенные процессы (тренировки, серверы)
Uncommitted changes? Конфликты или потеря
Невозможно работать над двумя задачами одновременно
Когда использовать: Быстрые правки в 2-3 файла, когда ничего не запущено.
Git Stash
git stash push -m "эксперимент lr=0.001" git checkout main # ... делаем дела ... git checkout feature/experiment git stash pop
Плюсы:
Сохраняет uncommitted изменения
Можно иметь несколько stash-ей
Минусы:
Не сохраняет untracked файлы (по умолчанию)
stash popна конфликтующих изменениях — больЛегко забыть что в stash-е
Не сохраняет запущенные процессы
Когда использовать: Срочное переключение на 5 минут, когда изменения минимальны.
ML-специфичная проблема: Конфиги, чекпоинты, кеши — часто в
.gitignore. Stash их не трогает, но checkout может привести к несовместимости.
Git Clone
git clone git@github.com:user/ml-project.git ml-project-experiment
Плюсы:
Полная изоляция
Никаких конфликтов между копиями
Можно работать параллельно
Минусы:
Дублирование всей истории (может быть гигабайты)
Ручная синхронизация (
git pullв каждой копии)Датасеты нужно копировать или настраивать симлинки вручную
N репозиториев = N×размер на диске
Когда использовать: Когда нужна полная изоляция от основного репо (например, эксперименты с ломающими изменениями в зависимостях).
Git Worktree
git worktree add ../ml-project-experiment feature/experiment
Плюсы:
Мгновенное создание (~секунда)
Общий
.git— экономия местаАвтоматическая синхронизация веток
Параллельная работа без ограничений
Процессы изолированы по директориям
Минусы:
Нельзя два worktree на одну ветку
Нужно следить за cleanup старых worktrees
Менее известен (коллеги могут не понять структуру)
Когда использовать: Практически всегда для ML-проектов.
Вердикт для ML
Если ты работаешь с машинным обучением, worktree — твой выбор по умолчанию. Вот почему:
Долгие процессы — тренировки идут часами. Worktree не прерывает их.
Эксперименты — запустил три варианта гиперпараметров в трёх worktrees, сравниваешь результаты.
Большие данные — симлинки на датасеты работают идентично во всех worktrees.
Code review — создал worktree для PR коллеги, посмотрел, удалил. Основная работа не тронута.
Единственный случай для clone: Тебе нужно радикально изменить зависимости (другая версия CUDA, несовместимый PyTorch) и ты не хочешь рисковать основным репо.
Единственный случай для stash: «Подожди 30 секунд, гляну одну строчку в main и вернусь».
Во всех остальных случаях — worktree.
Часть 3: ML-специфичные сценарии
Теория — это хорошо. Давай разберём конкретные ситуации, с которыми ты сталкиваешься каждый день.
Сценарий 1: Параллельные эксперименты с гиперпараметрами
Задача: Запустить три эксперимента с разными learning rates одновременно.
Структура:
# Создаём worktrees для каждого эксперимента git worktree add -b experiment/lr-001 ../ml-proj-lr-001 main git worktree add -b experiment/lr-0001 ../ml-proj-lr-0001 main git worktree add -b experiment/lr-00001 ../ml-proj-lr-00001 main
После этого структура выглядит так:
~/projects/ ├── ml-image-classifier/ # main — здесь основная разработка ├── ml-proj-lr-001/ # experiment/lr-001 ├── ml-proj-lr-0001/ # experiment/lr-0001 └── ml-proj-lr-00001/ # experiment/lr-00001
Запуск экспериментов:
# Терминал 1 cd ~/projects/ml-proj-lr-001 python train.py --lr 0.001 --experiment-name "lr-001" # Терминал 2 cd ~/projects/ml-proj-lr-0001 python train.py --lr 0.0001 --experiment-name "lr-0001" # Терминал 3 cd ~/projects/ml-proj-lr-00001 python train.py --lr 0.00001 --experiment-name "lr-00001"
Три модели тренируются параллельно. Каждая в своей директории. Никаких конфликтов.
После экспериментов:
# Лучший результат на lr=0.0001? Мержим в main cd ~/projects/ml-image-classifier git merge experiment/lr-0001 # Удаляем ненужные worktrees git worktree remove ../ml-proj-lr-001 git worktree remove ../ml-proj-lr-0001 git worktree remove ../ml-proj-lr-00001 # Чистим ветки git branch -d experiment/lr-001 experiment/lr-0001 experiment/lr-00001
Сценарий 2: Изоляция Python environments
Проблема: Один эксперимент требует PyTorch 2.0, другой — PyTorch 1.13 (для совместимости со старым кодом).
Решение: Каждый worktree имеет свой .venv:
# Основной проект с PyTorch 2.0 cd ~/projects/ml-image-classifier python -m venv .venv source .venv/bin/activate pip install torch==2.0.0 # Worktree для legacy эксперимента git worktree add -b experiment/legacy-model ../ml-proj-legacy main cd ../ml-proj-legacy python -m venv .venv source .venv/bin/activate pip install torch==1.13.0
Или с conda:
# Создаём окружения conda create -n ml-proj-py39 python=3.9 pytorch=1.13 -y conda create -n ml-proj-py311 python=3.11 pytorch=2.0 -y # В каждом worktree активируем нужное cd ~/projects/ml-proj-legacy conda activate ml-proj-py39 cd ~/projects/ml-image-classifier conda activate ml-proj-py311
Важно:
.venv/должен быть в.gitignore. Каждый worktree создаёт свой environment, они не шарятся.
Автоматизация с direnv:
Создай .envrc в каждом worktree:
# ~/projects/ml-proj-legacy/.envrc source .venv/bin/activate export CUDA_VISIBLE_DEVICES=0
# ~/projects/ml-image-classifier/.envrc source .venv/bin/activate export CUDA_VISIBLE_DEVICES=1
Теперь при cd в директорию автоматически активируется нужный environment.
Сценарий 3: Работа с большими датасетами
Проблема: У тебя 200GB данных в /data/imagenet/. Копировать в каждый worktree — безумие.
Решение: Симлинки
# Структура данных (вне репозитория) /shared/ └── datasets/ ├── imagenet/ # 200GB ├── coco/ # 50GB └── custom/ # 10GB # В основном репозитории cd ~/projects/ml-image-classifier ln -s /shared/datasets/imagenet data/imagenet ln -s /shared/datasets/coco data/coco
Важно для .gitignore:
# .gitignore data/imagenet data/coco data/custom # Но трекаем структуру !data/.gitkeep # Игнорируем чекпоинты и кеши checkpoints/ *.pt *.pth __pycache__/ .cache/
При создании worktree симлинки копируются автоматически (если они закоммичены как симлинки, а не добавлены в .gitignore).
Если симлинки в .gitignore, создай скрипт setup_data.sh:
#!/bin/bash # setup_data.sh — запускать после создания worktree ln -sf /shared/datasets/imagenet data/imagenet ln -sf /shared/datasets/coco data/coco echo "Data symlinks created!"
DVC (Data Version Control):
Если ты используешь DVC для версионирования данных:
# Worktree подхватывает .dvc файлы автоматически cd ../ml-proj-experiment dvc pull # Скачивает данные по симлинкам/кешу
DVC хранит данные в общем кеше (~/.dvc/cache), так что даже при dvc pull в новом worktree данные не дублируются.
Сценарий 4: Code Review без прерывания работы
Ситуация: Коллега просит посмотреть PR #42, но у тебя тренируется модель.
Классический подход (боль):
# Останавливаем всё Ctrl+C # RIP 4 часа тренировки git stash git checkout feature/colleague-pr # Смотрим код git checkout - git stash pop # Перезапускаем тренировку заново...
С worktree (счастье):
# Модель продолжает тренироваться в текущей директории # Создаём временный worktree для review git fetch origin git worktree add ../ml-proj-review-pr42 origin/feature/colleague-pr # Открываем в новом окне Cursor cursor ../ml-proj-review-pr42 # Смотрим код, оставляем комментарии # ... # Закончили — удаляем git worktree remove ../ml-proj-review-pr42
Вся операция занимает 30 секунд на setup и не трогает твой текущий эксперимент.
Pro tip: Для частых review создай alias:
# ~/.bashrc или ~/.zshrc review-pr() { git fetch origin git worktree add "../review-pr-$1" "origin/$2" cursor "../review-pr-$1" } # Использование: review-pr 42 feature/new-model
Часть 4: Интеграция с Cursor
Worktree сам по себе мощный. Но в связке с Cursor он становится ещё удобнее. Разберём, как выжать максимум.
Открытие worktree как отдельного окна
Самый простой способ — открыть каждый worktree в отдельном окне Cursor:
# Основной проект cursor ~/projects/ml-image-classifier # Эксперимент в новом окне cursor ~/projects/ml-proj-lr-001
Или из терминала внутри Cursor:
# Создаём worktree и сразу открываем git worktree add ../ml-proj-experiment experiment/new-arch cursor ../ml-proj-experiment
Каждое окно — независимый контекст. Свой терминал, свой git status, свои открытые файлы.
Multi-root Workspace
Если хочешь видеть все worktrees в одном окне — используй multi-root workspace.
Создай файл ml-project.code-workspace:
{ "folders": [ { "name": "[MAIN] ml-image-classifier", "path": "ml-image-classifier" }, { "name": "[EXP] LR-001", "path": "ml-proj-lr-001" }, { "name": "[EXP] Transformer", "path": "ml-proj-transformer" } ], "settings": { "files.exclude": { "**/__pycache__": true, "**/.pytest_cache": true, "**/checkpoints": true }, "python.analysis.extraPaths": [ "${workspaceFolder:[MAIN] ml-image-classifier}/src" ] } }
Открыть workspace:
cursor ml-project.code-workspace
Теперь в sidebar видны все три проекта. Можно переключаться между ними, сравнивать код, копировать файлы.
Совет: Используй префиксы в именах (
[MAIN],[EXP],[DEV]), чтобы быстро различать worktrees.
Cursor Tasks для Worktree Management
Автоматизируй рутину через Cursor Tasks. Создай .cursor/tasks.json:
{ "version": "2.0.0", "tasks": [ { "label": "Worktree: Create", "type": "shell", "command": "git worktree add -b ${input:branchName} ../${input:folderName} main", "problemMatcher": [], "presentation": { "reveal": "always", "panel": "new" } }, { "label": "Worktree: Remove", "type": "shell", "command": "git worktree remove ../${input:folderName}", "problemMatcher": [] }, { "label": "Worktree: List", "type": "shell", "command": "git worktree list", "problemMatcher": [], "presentation": { "reveal": "always" } }, { "label": "Worktree: Train", "type": "shell", "command": "cd ../${input:folderName} && source .venv/bin/activate && python train.py", "problemMatcher": [], "presentation": { "reveal": "always", "panel": "dedicated" }, "isBackground": true }, { "label": "Worktree: Cleanup", "type": "shell", "command": "git worktree prune -v", "problemMatcher": [] } ], "inputs": [ { "id": "branchName", "type": "promptString", "description": "Branch name (e.g., experiment/lr-001)" }, { "id": "folderName", "type": "promptString", "description": "Folder name (e.g., ml-proj-lr-001)" } ] }
Использование:
Cmd/Ctrl + Shift + P→ "Tasks: Run Task"Выбери
Worktree: CreateВведи имя ветки и папки
Done!
Настройки Python Interpreter per Worktree
Каждый worktree может иметь свой Python interpreter. Cursor подхватывает это автоматически.
В каждом worktree создай .vscode/settings.json:
{ "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", "python.terminal.activateEnvironment": true, "python.analysis.extraPaths": ["${workspaceFolder}/src"] }
Или для conda:
{ "python.defaultInterpreterPath": "~/miniconda3/envs/ml-proj-py311/bin/python", "python.condaPath": "~/miniconda3/bin/conda" }
Важно:
.vscode/можно добавить в.gitignore, чтобы настройки были локальными для каждого worktree.
Terminal Profiles для разных Worktrees
Настрой разные terminal profiles для быстрого переключения:
В settings.json (глобальном или workspace):
{ "terminal.integrated.profiles.linux": { "ML Main": { "path": "/bin/bash", "args": ["-c", "cd ~/projects/ml-image-classifier && source .venv/bin/activate && exec bash"] }, "ML Experiment": { "path": "/bin/bash", "args": ["-c", "cd ~/projects/ml-proj-lr-001 && source .venv/bin/activate && exec bash"] } }, "terminal.integrated.defaultProfile.linux": "ML Main" }
Теперь при создании нового терминала можно выбрать профиль — и сразу оказаться в нужном worktree с активированным environment.
Часть 5: Продвинутые техники
Для тех, кто хочет выжать из worktree максимум.
Bare Repository Pattern
Обычно у тебя есть «основной» репозиторий с checked out веткой (обычно main), и worktrees — дополнительные. Но есть альтернативный подход: bare repository.
Что это: Репозиторий без рабочей директории. Только .git содержимое.
Зачем: Все ветки равноправны. Нет «главного» worktree. Чище структура.
Setup:
# Клонируем как bare git clone --bare git@github.com:user/ml-image-classifier.git ml-image-classifier.git # Переходим внутрь cd ml-image-classifier.git # Создаём worktrees для нужных веток git worktree add ../ml-main main git worktree add ../ml-dev develop git worktree add ../ml-experiment experiment/transformer
Структура:
~/projects/ ├── ml-image-classifier.git/ # Bare repo (только .git) ├── ml-main/ # worktree → main ├── ml-dev/ # worktree → develop └── ml-experiment/ # worktree → experiment/transformer
Когда использовать:
Работаешь с несколькими долгоживущими ветками одновременно
Не хочешь иметь "главный" worktree
Нужна чёткая организация проекта
Когда НЕ использовать:
Простой проект с одной основной веткой
Временные эксперименты (обычный подход проще)
Worktree + tmux/screen для долгих тренировок
Тренировка на 12 часов? SSH-соединение может оборваться. Решение: tmux или screen.
Базовый workflow:
# Создаём tmux сессию для эксперимента tmux new-session -d -s exp-lr-001 # Отправляем команды в сессию tmux send-keys -t exp-lr-001 "cd ~/projects/ml-proj-lr-001" Enter tmux send-keys -t exp-lr-001 "source .venv/bin/activate" Enter tmux send-keys -t exp-lr-001 "python train.py --lr 0.001" Enter # Можно отключиться — тренировка продолжится
Скрипт для запуска эксперимента:
#!/bin/bash # run_experiment.sh WORKTREE_PATH=$1 SESSION_NAME=$2 TRAIN_ARGS=$3 # Создаём сессию tmux new-session -d -s "$SESSION_NAME" # Запускаем тренировку tmux send-keys -t "$SESSION_NAME" "cd $WORKTREE_PATH && source .venv/bin/activate && python train.py $TRAIN_ARGS" Enter echo "Experiment started in tmux session: $SESSION_NAME" echo "Attach with: tmux attach -t $SESSION_NAME"
Использование:
./run_experiment.sh ~/projects/ml-proj-lr-001 exp-lr-001 "--lr 0.001 --epochs 100" ./run_experiment.sh ~/projects/ml-proj-lr-0001 exp-lr-0001 "--lr 0.0001 --epochs 100" # Проверить статус tmux list-sessions # Подключиться к сессии tmux attach -t exp-lr-001
Shell Aliases и Functions
Добавь в ~/.bashrc или ~/.zshrc:
# Быстрое создание worktree для эксперимента wt-exp() { local name=$1 local base=${2:-main} git worktree add -b "experiment/$name" "../exp-$name" "$base" cd "../exp-$name" echo "Created worktree: experiment/$name" } # Быстрое создание worktree для фичи wt-feature() { local name=$1 local base=${2:-main} git worktree add -b "feature/$name" "../feature-$name" "$base" cd "../feature-$name" } # Удаление worktree с подтверждением wt-remove() { local path=$1 echo "Removing worktree: $path" read -p "Are you sure? (y/n) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then git worktree remove "$path" echo "Removed!" fi } # Список worktrees с красивым выводом wt-list() { git worktree list | while read -r line; do path=$(echo "$line" | awk '{print $1}') branch=$(echo "$line" | grep -o '\[.*\]') echo " $path $branch" done } # Переход в worktree по имени ветки wt-cd() { local branch=$1 local path=$(git worktree list | grep "\[$branch\]" | awk '{print $1}') if [ -n "$path" ]; then cd "$path" echo "Switched to: $path" else echo "Worktree for branch '$branch' not found" fi }
Примеры использования:
wt-exp transformer-v2 # Создаёт experiment/transformer-v2 wt-feature new-dataloader # Создаёт feature/new-dataloader wt-list # Красивый список wt-cd experiment/lr-001 # Переход в worktree по ветке wt-remove ../exp-old # Удаление с подтверждением
Cleanup: когда и как удалять Worktrees
Worktrees накапливаются. Вот стратегии cleanup:
1. Ручная проверка раз в неделю:
git worktree list # Удаляем ненужные git worktree remove ../old-experiment
2. Автоматический prune:
# Удаляет записи о worktrees, папки которых уже удалены git worktree prune # С verbose выводом git worktree prune -v
3. Скрипт для очистки старых worktrees:
#!/bin/bash # cleanup_worktrees.sh DAYS_OLD=${1:-7} # По умолчанию ��тарше 7 дней echo "Worktrees older than $DAYS_OLD days:" git worktree list --porcelain | grep "^worktree" | cut -d' ' -f2 | while read -r path; do if [ -d "$path" ]; then # Проверяем дату последней модификации last_mod=$(find "$path" -type f -name "*.py" -mtime -"$DAYS_OLD" | head -1) if [ -z "$last_mod" ]; then echo " OLD: $path" fi fi done echo "" echo "Run 'git worktree remove <path>' to remove"
4. Git hooks для напоминания:
Добавь в .git/hooks/post-checkout:
#!/bin/bash # Напоминание о cleanup каждые 10 checkouts COUNT_FILE=".git/worktree_check_count" count=$(cat "$COUNT_FILE" 2>/dev/null || echo 0) count=$((count + 1)) if [ $count -ge 10 ]; then echo "" echo ">>> Time to cleanup worktrees?" git worktree list echo 0 > "$COUNT_FILE" else echo $count > "$COUNT_FILE" fi
Заключение
Ключевые Takeaways
Worktree ≠ clone. Один
.git, несколько рабочих директорий. Экономия места и автоматическая синхронизация веток.Для ML — must have. Долгие тренировки, параллельные эксперименты, изоляция environments — worktree решает все эти проблемы.
Одна ветка = один worktree. Это ограничение, но оно защищает от хаоса.
Симлинки — твой друг. Большие датасеты не нужно копировать. Один симлинк — и данные доступны во всех worktrees.
Cursor + worktree = мощь. Multi-root workspaces, tasks, отдельные interpreters — всё работает из коробки.
Автоматизируй. Shell aliases, Cursor tasks, tmux скрипты — один раз настроил, потом экономишь часы.
Не забывай cleanup. Worktrees накапливаются.
git worktree prune— твой друг.
Quick Reference
# ═══════════════════════════════════════════════════════ # GIT WORKTREE CHEATSHEET # ═══════════════════════════════════════════════════════ # СОЗДАНИЕ git worktree add <path> <branch> # Существующая ветка git worktree add -b <new-branch> <path> main # Новая ветка от main # ПРОСМОТР git worktree list # Список всех worktrees git worktree list --porcelain # Машиночитаемый формат # УДАЛЕНИЕ git worktree remove <path> # Удалить worktree git worktree remove -f <path> # Принудительно (есть изменения) # ОЧИСТКА git worktree prune # Удалить мёртвые записи git worktree prune -v # С подробностями # БЛОКИРОВКА (защита от случайного удаления) git worktree lock <path> # Заблокировать git worktree unlock <path> # Разблокировать # ВОССТАНОВЛЕНИЕ git worktree repair # Починить сломанные связи # ═══════════════════════════════════════════════════════ # ТИПИЧНЫЕ СЦЕНАРИИ # ═══════════════════════════════════════════════════════ # Эксперимент с гиперпараметрами git worktree add -b experiment/lr-001 ../exp-lr-001 main cd ../exp-lr-001 && python train.py --lr 0.001 # Code review git fetch origin git worktree add ../review-pr-42 origin/feature/new-model cursor ../review-pr-42 # Hotfix без остановки тренировки git worktree add ../hotfix main cd ../hotfix && # fix, commit, push git worktree remove ../hotfix
Попробуй сейчас
Хватит читать — пора действовать. Вот план на ближайшие 10 минут:
Шаг 1: Открой свой ML-проект
cd ~/your-ml-project
Шаг 2: Создай первый worktree
git worktree add -b experiment/test-worktree ../my-first-worktree main
Шаг 3: Открой его в Cursor
cursor ../my-first-worktree
Шаг 4: Убедись, что всё р��ботает
git worktree list
Шаг 5: Удали тестовый worktree
git worktree remove ../my-first-worktree git branch -d experiment/test-worktree
Готово. Теперь ты знаешь, как это работает.
В следующий раз, когда коллега попросит «срочно глянуть PR» посреди 8-часовой тренировки — ты знаешь что делать.
Если статья была полезной — поделись с коллегами. Чем больше людей знают про worktree, тем меньше убитых экспериментов в мире.
