← Назад к вопросам
Что происходит с commits при выполнении rebase?
2.0 Middle🔥 192 комментариев
#JavaScript Core
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Git rebase: что происходит с коммитами
Rebase - это один из самых мощных инструментов Git, но и самый запутанный для новичков. Понимание того, что происходит с коммитами во время rebase, критично для безопасной работы.
1. Основная идея rebase vs merge
Оба объединяют ветки, но по-разному:
// ИСХОДНАЯ ИСТОРИЯ
// main: A -- B -- C
// \
// feature: D -- E
// MERGE - создаёт commit с двумя parents
git merge feature
// main: A -- B -- C -- M (merge commit)
// \ /
// feature: D -- E
// История: линейная, но М имеет двух родителей
// REBASE - переписывает историю commits
git rebase main feature
// main: A -- B -- C
// feature: D' -- E'
// История: полностью линейная, D и E переписаны
2. Как работает rebase: пошагово
// ШАГ 1: Найти общего предка (merge base)
// main: A -- B -- C
// \
// feature: D -- E
// Общий предок: B
// ШАГ 2: Сохранить коммиты из feature (D, E)
// Git берёт разницу между B и E:
// patch1 = изменения из D
// patch2 = изменения из E
// ШАГ 3: Переместить feature на последний коммит main (C)
checkout feature // находимся на E
rebase main
// Теперь feature указывает на C
// ШАГ 4: Применить сохранённые patches
// Применить patch1 на C -> создать D' (новый коммит!)
// Применить patch2 на D' -> создать E' (новый коммит!)
// РЕЗУЛЬТАТ:
// main: A -- B -- C
// feature: D' -- E'
// D и E больше не существуют (если нет других ветвей на них)
3. Коммиты полностью переписываются
Важное свойство: при rebase создаются НОВЫЕ коммиты, старые не изменяются:
// Исходный коммит D
// hash: abc123
// message: "Добавил feature"
// parent: B (hash xyz789)
// changes: изменил файл.js
// После rebase создаётся D'
// hash: def456 (ДРУГОЙ хеш!)
// message: "Добавил feature" (сообщение то же)
// parent: C (hash qwe123) (ДРУГОЙ родитель!)
// changes: изменил файл.js (изменения те же)
// ВАЖНО: D и D' - это РАЗНЫЕ коммиты
// Если кто-то в другой ветке ссылается на D, это станет проблемой!
4. Проблемы при rebase: конфликты и история
// ПРОБЛЕМА 1: Конфликты при rebase
git rebase main feature
// Если D и E изменяют файлы, которые тоже изменились в main
// произойдет CONFLICT
// КОНФЛИКТ в файле:
// <<<<<<< HEAD (main версия)
// console.log('main version');
// =======
// console.log('feature version');
// >>>>>>> feature
// Нужно вручную разрешить конфликт
git add файл.js
git rebase --continue
// Или отменить rebase
git rebase --abort
// ПРОБЛЕМА 2: Потеря истории
feature branch имела 5 коммитов
После rebase эти 5 коммитов переписаны
Если кто-то потом попробует merge старую feature
произойдет УЖАС (двойные коммиты, конфликты)
5. Interactive rebase: переписывание истории
// СИНТАКСИС
git rebase -i HEAD~3
// Позволяет переписать последние 3 коммита
// ИНТЕРАКТИВНЫЙ РЕДАКТОР:
// pick d12345 Первый коммит
// pick e23456 Второй коммит
// pick f34567 Третий коммит
// КОМАНДЫ:
// pick - оставить коммит
// reword - изменить сообщение
// edit - остановиться перед этим коммитом
// squash - объединить с предыдущим
// fixup - объединить без сохранения сообщения
// drop - удалить коммит
// exec - выполнить команду
// ПРИМЕР: объединить 2 коммита в 1
// pick d12345 Первый коммит
// squash e23456 Второй коммит (объединится с первым)
// pick f34567 Третий коммит
// РЕЗУЛЬТАТ:
// Коммиты d и e объединены в один
// Появляется диалог редактирования сообщения
// Создаётся новый коммит вместо двух старых
// ПРИМЕР: изменить порядок коммитов
// pick f34567 Третий коммит (ПЕРЕМЕСТИЛИ СЮДА)
// pick d12345 Первый коммит
// pick e23456 Второй коммит
// РЕЗУЛЬТАТ: коммиты переписаны в новом порядке!
6. Когда использовать rebase vs merge
// REBASE лучше когда:
// 1. Работаешь один на фиче
// 2. Хочешь чистую, линейную историю
// 3. Коммиты ещё не запушены в public branch
git checkout feature
git rebase main // переписываем feature
// История чистая, без merge коммитов
// MERGE лучше когда:
// 1. Фича уже в shared branch (другие могут зависеть)
// 2. Коммиты уже запушены (git push)
// 3. Хочешь сохранить историю интеграции
git merge feature
// Создаётся merge коммит, старые коммиты не меняются
// ЗОЛОТОЕ ПРАВИЛО: никогда не rebase публичные коммиты!
// Если другие зависят от твоих коммитов, не переписывай их
7. Git reflog: восстановление после rebase
// Сделал rebase и пожалел? Не волнуйся!
// reflog хранит все движения HEAD
git reflog
// output:
// abc123 HEAD@{0}: rebase (finish)
// def456 HEAD@{1}: rebase (pick)
// ghi789 HEAD@{2}: checkout
// jkl012 HEAD@{3}: commit
// Вернуться к состоянию ДО rebase
git reset --hard jkl012
// Теперь как будто rebase не было
// Эта команда спасала мне жизнь много раз!
8. Проблемы и ошибки при rebase
// ОШИБКА 1: Rebasing публичного branch
git push origin feature
# После этого другие разработчики могли запулить feature
git rebase -i HEAD~3 # ОПАСНО!
git push --force origin feature # ЕЩЕ ОПАСНЕЕ!
// Последствия:
// - Другие разработчики имеют старые коммиты (abc123)
// - Ты перезаписал их на новые коммиты (def456)
// - Когда они попытаются push, будет конфликт
// - История запутается, дублируются коммиты
// РЕШЕНИЕ: используй git push --force-with-lease
// Это проверит, что никто не push'ил с момента твоего fetch
// ОШИБКА 2: Rebase с неправильным базисом
git rebase main feature
// Если main сам был переписан (кто-то rebasil его)
// Это может привести к странным результатам
// ОШИБКА 3: Потеря коммитов
git rebase -i HEAD~10
# Случайно выбрал 'drop' на важном коммите
# Чтобы восстановить:
git reset --hard HEAD@{1} # reflog спасает!
9. Rebase в practice: шаг за шагом
// СЦЕНАРИЙ: обновить feature с изменениями из main
// ШАГ 1: убедиться, что все коммиты закоммичены
git status # должно быть чисто
// ШАГ 2: fetched последние изменения
git fetch origin
// ШАГ 3: перейти на feature
git checkout feature
// ШАГ 4: начать rebase
git rebase origin/main
// Git автоматически:
// - найдёт общего предка
// - сохранит коммиты feature
// - переместит их на origin/main
// - применит patches
// ШАГ 5: если конфликты
git status # посмотри конфликты
# отредактируй файлы с <<<<<<
git add файл.js
git rebase --continue
// ШАГ 6: push (осторожно!)
git push origin feature --force-with-lease
// --force-with-lease безопаснее чем --force
10. Сравнение истории: rebase vs merge
// MERGE история (сложнее читать, но безопаснее)
A -- B -- C -- M -- F -- G
\ /
D -- E
// Коммиты остаются как есть
// Легко видеть, что когда-то была отдельная ветка
// Безопасно для публичных веток
// REBASE история (проще читать, но опаснее)
A -- B -- C -- D' -- E' -- F -- G
// Полностью линейная история
// Легко понять последовательность изменений
// Но оригинальные D и E потеряны
Практические советы
- Используй rebase для локальных фич
git rebase main feature # перед PR
- Никогда не rebase коммиты, которые уже в shared branch
# ПЛОХО
git push
git rebase -i HEAD~5
git push --force
# ХОРОШО
git rebase -i HEAD~5
git push # push один раз, до других
- Используй reflog для спасения
git reflog # найти старое состояние
git reset --hard HEAD@{N} # вернуться
- Проверь историю перед rebase
git log --oneline main..feature
# посмотри какие коммиты будут переписаны
Rebase - это мощный инструмент для чистой истории, но требует уважения и понимания. Когда сомневаешься - используй merge!