Git Advanced: профессиональные техники работы с репозиторием

От rebase до bisect: инструменты для эффективной работы с Git

Владение базовыми командами Git — это стартовая точка, но не финишная черта. Команды commit , push , pull и merge покрывают 80% повседневных задач, но оставшиеся 20% — именно те ситуации, где теряются часы и нервы. Хот-фиксы в продакшене, запутанная история коммитов, параллельная работа над несколькими фичами, случайно удалённые ветки — всё это требует продвинутых техник. В 404gen мы работаем над проектами со средним бюджетом от 3 млн рублей, где команда может насчитывать 8–15 разработчиков, а история репозитория — тысячи коммитов. На таком масштабе правильное использование Git напрямую влияет на скорость поставки и стоимость поддержки. В этой статье разберём инструменты, которые отделяют профессиональную работу с репозиторием от любительской. Cherry-pick: точечный перенос изменений между ветками git cherry-pick — команда, которую часто недооценивают новички и злоупотребляют опытные разработчики. Суть проста: взять конкретный коммит из любой ветки и применить его к текущей, не перенося всю ветку целиком. Когда это нужно Хот-фикс в несколько веток одновременно. Вы исправили критический баг в main , но он воспроизводится и в release/2.3 , и в release/2.2 . Вместо того чтобы исправлять трижды, делаете cherry-pick одного коммита. Спасение нужного коммита из неудачной ветки. Ветка содержит полезную фичу среди сырого кода — переносите только готовое. Перенос между независимыми линиями разработки. Монорепозитории с несколькими продуктами, где фиксы в общей библиотеке нужно синхронизировать. # Перенести один коммит git cherry-pick a1b2c3d # Перенести диапазон коммитов (исключая первый) git cherry-pick a1b2c3d..f4e5d6c # Перенести диапазон коммитов (включая первый) git cherry-pick a1b2c3d^..f4e5d6c # Перенести без автоматического коммита (для последующего редактирования) git cherry-pick --no-commit a1b2c3d # Продолжить после разрешения конфликтов git cherry-pick --continue # Отменить cherry-pick git cherry-pick --abort Важный нюанс: cherry-pick создаёт новый коммит с тем же содержимым, но другим SHA. Это означает, что при последующем мерже оригинальной ветки Git может применить изменения повторно — следите за этим и используйте git log --cherry-pick для диагностики дублей. Практика 404gen: мы используем cherry-pick строго для хот-фиксов. Для переноса фич между ветками всегда предпочитаем rebase или merge — это сохраняет читаемую историю и не создаёт дублирующих коммитов. Interactive Rebase: переписывание истории как инструмент качества Interactive rebase ( git rebase -i ) — один из самых мощных инструментов Git и при этом один из наиболее пугающих для тех, кто не разобрался с его логикой. Он позволяет переписать историю ветки: переупорядочить коммиты, объединить несколько в один, разбить один на несколько, изменить сообщения, удалить лишнее. Основные операции # Интерактивный rebase последних 5 коммитов git rebase -i HEAD~5 # Интерактивный rebase относительно ветки main git rebase -i main После выполнения откроется редактор со списком коммитов. Каждая строка начинается с команды: pick — оставить коммит как есть reword (r) — оставить коммит, изменить только сообщение edit (e) — остановиться на коммите для ручного редактирования squash (s) — объединить с предыдущим коммитом, объединить сообщения fixup (f) — объединить с предыдущим, выбросить сообщение этого коммита drop (d) — удалить коммит полностью exec (x) — выполнить произвольную shell-команду между коммитами # Пример редактора после git rebase -i HEAD~4 pick 1a2b3c4 feat: add user authentication pick 5d6e7f8 wip: fix typo pick 9g0h1i2 wip: another fix pick 3j4k5l6 feat: add password reset # Преобразуем в: pick 1a2b3c4 feat: add user authentication fixup 5d6e7f8 wip: fix typo fixup 9g0h1i2 wip: another fix pick 3j4k5l6 feat: add password reset Результат: два осмысленных коммита вместо четырёх, включая два «wip»-мусора. Именно такая история понятна коллегам через полгода и помогает при git bisect находить регрессии. Разбивка одного коммита на несколько # В редакторе rebase выбираем "edit" для нужного коммита # Git останавливается. Откатываем коммит, оставляя изменения: git reset HEAD^ # Теперь стейджируем и коммитим части по отдельности git add src/auth/login.ts git commit -m "feat: add login endpoint" git add src/auth/register.ts git commit -m "feat: add registration endpoint" # Продолжаем rebase git rebase --continue Золотое правило: никогда не делайте rebase публичных веток, которые уже запушены и используются другими разработчиками. Это перезапишет SHA коммитов и создаст конфликты у всех участников. Interactive rebase — только для локальных или feature-веток до мержа. Git Worktrees: несколько рабочих деревьев из одного репозитория Git Worktrees — функция, появившаяся в Git 2.5 (2015), но до сих пор малоизвестная даже среди опытных разработчиков. Она позволяет иметь несколько рабочих директорий, привязанных к одному репозиторию, без клонирования. Проблема, которую решает worktree Сценарий: вы на полпути в разработке сложной фичи в ветке feature/payment-gateway . Прилетает срочный баг в продакшене. Варианты без worktree: Stash текущей работы → переключиться → исправить → переключиться обратно → pop stash. Рисково, если stash конфликтует. Клонировать репозиторий второй раз. Занимает место и время, нужно настраивать окружение заново. С worktree — создаёте отдельную директорию для хот-фикса, не трогая текущую рабочую копию: # Создать worktree с новой веткой git worktree add ../404gen-hotfix -b hotfix/critical-bug # Создать worktree из существующей ветки git worktree add ../404gen-release release/2.3 # Список всех worktrees git worktree list # Удалить worktree (после завершения работы) git worktree remove ../404gen-hotfix После этого в директории ../404gen-hotfix у вас полноценная рабочая копия с веткой hotfix/critical-bug . Можно открыть её в отдельном окне редактора, запустить тесты, закоммитить и запушить — совершенно независимо от основной копии. При этом Git-объекты общие: нет дублирования истории, занимает только разницу в файлах. Применение в CI/CD и параллельной разработке Worktrees особенно полезны в следующих сценариях: Code review с параллельным кодингом. Открываете ветку коллеги в отдельном worktree для review, продолжая работу в основном. Сравнение поведения двух версий. Запускаете приложение из двух worktrees одновременно на разных портах. Работа с long-running задачами. Один worktree компилирует сборку, другой — в активной разработке. # Практический пример: открыть ветку коллеги для review git worktree add ../review-pr-142 origin/feature/new-dashboard cd ../review-pr-142 npm install && npm run dev -- --port 5174 # Теперь открываем localhost:5174 и сравниваем с localhost:5173 Git Bisect: бинарный поиск регрессии git bisect — команда для автоматизированного поиска коммита, который сломал функциональность. Использует алгоритм бинарного поиска: вы указываете «хороший» коммит (где работало) и «плохой» (где не работает), Git поочерёдно чекаутит середину диапазона, вы проверяете и говорите «хорошо» или «плохо». За log₂(N) шагов находите виновный коммит. # Начать поиск git bisect start # Отметить текущий HEAD как плохой git bisect bad # Отметить коммит, где всё работало (например, неделю назад) git bisect good v2.1.0 # Git переключается на середину. Проверяем и говорим: git bisect good # или git bisect bad # После нахождения виновника — сброс git bisect reset Автоматизированный bisect Если у вас есть автотест, который воспроизводит баг, можно полностью автоматизировать поиск: # Скрипт возвращает 0 (хорошо) или не-0 (плохо) git bisect run npm test -- --testNamePattern="payment processing" # Или с произвольным скриптом git bisect run ./scripts/check-bug.sh На репозитории с 1000 коммитами bisect найдёт виновника за 10 шагов. Без bisect разработчик может потратить на поиск регрессии часы ручного просмотра изменений. Git Reflog: машина времени для удалённых коммитов Reflog — журнал всех изменений, которые происходили с HEAD и ссылками в вашем локальном репозитории. Это «чёрный ящик» Git, который хранит информацию даже об удалённых коммитах и ветках в течение 90 дней (по умолчанию). # Посмотреть reflog HEAD git reflog # Вывод: # a1b2c3d HEAD@{0}: commit: feat: add export feature # 5d6e7f8 HEAD@{1}: rebase -i (finish): returning to refs/heads/feature/export # 9g0h1i2 HEAD@{2}: rebase -i (squash): feat: add export feature # 3j4k5l6 HEAD@{3}: checkout: moving from main to feature/export # Восстановить ветку, удалённую случайно git checkout -b recovered-branch HEAD@{5} # Восстановить коммиты после неудачного reset --hard git reset --hard HEAD@{3} Типичная история: разработчик делает git reset --hard не на ту ветку и «теряет» несколько коммитов. Паника. Но reflog хранит все позиции HEAD — находим нужный, создаём ветку, всё восстановлено. Именно поэтому Git считается одной из самых надёжных систем контроля версий: потерять данные в локальном репозитории практически невозможно, если знать о reflog. Git Stash: продвинутое использование Большинство разработчиков знает git stash и git stash pop . Но stash значительно мощнее в своём полном применении. # Сохранить с именем git stash push -m "wip: payment form validation" # Сохранить включая untracked файлы git stash push -u # Сохранить только часть изменений (интерактивно) git stash push -p # Список всех stash git stash list # stash@{0}: On feature/payments: wip: payment form validation # stash@{1}: On main: wip: dashboard charts # Применить конкретный stash без удаления из стека git stash apply stash@{1} # Создать ветку из stash (самый безопасный способ) git stash branch feature/extracted-work stash@{0} # Посмотреть diff stash без применения git stash show -p stash@{0} Команда git stash branch — особенно полезна, когда понимаете, что «временная» работа в stash выросла в полноценную фичу. Создаёт новую ветку, применяет stash и удаляет его из стека. Продвинутая работа с git log и поиск по истории История репозитория — это документация. Умение быстро находить нужную информацию в истории экономит часы расследований. # Красивый граф истории git log --oneline --graph --all --decorate # Поиск по содержимому коммита (pickaxe) # Найти все коммиты, где добавлялась или удалялась строка git log -S "processPayment" --source --all # Поиск по регулярному выражению git log -G "api/v[0-9]+/payments" # Найти коммиты по автору за период git log --author="Ivan Petrov" --since="2 weeks ago" --oneline # Что изменилось в конкретном файле git log -p -- src/payments/processor.ts # Аннотация файла: кто и когда написал каждую строку git blame -L 42,60 src/payments/processor.ts # Поиск с игнорированием пробелов git blame -w src/payments/processor.ts Git log с форматированием для отчётов # Список изменений за спринт (для отчёта) git log --since="2026-05-01" --until="2026-05-14" \ --pretty=format:"%h | %ad | %an | %s" \ --date=short # Статистика по файлам в диапазоне git diff --stat main..feature/new-api # Сравнить ветки (что есть в feature, но нет в main) git log main..feature/new-api --oneline Практика: реальные сценарии и решения Сценарий 1: Хот-фикс в нескольких релизных ветках # 1. Исправляем баг в main git checkout main git commit -m "fix: prevent SQL injection in search endpoint" # 2. Запоминаем SHA git log --oneline -1 # a1b2c3d fix: prevent SQL injection in search endpoint # 3. Cherry-pick в релизные ветки git checkout release/2.3 git cherry-pick a1b2c3d git checkout release/2.2 git cherry-pick a1b2c3d # 4. Пушим все три git push origin main release/2.3 release/2.2 Сценарий 2: Очистка истории перед PR # Feature-ветка с 12 коммитами, из которых 7 — мусор git log --oneline # 8a9b0c1 fix test # 7b8c9d0 fix test again # 6c7d8e9 wip # 5d6e7f8 wip: trying different approach # 4e5f6g7 fix lint # 3f4g5h6 feat: add payment webhook handling # 2g3h4i5 wip # ... # Интерактивный rebase — объединяем в 2 осмысленных коммита git rebase -i main # В редакторе оставляем pick на смысловых коммитах, # fixup на мусоре. Результат: 2 чистых коммита # После этого PR становится читаемым и проходит review быстрее Сценарий 3: Восстановлен