Пятница, 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, тем меньше убитых экспериментов в мире.
