Переписывание истории¶
Git позволяет изменять историю коммитов: объединять коммиты, менять их порядок, редактировать сообщения или удалять коммиты. Это мощный инструмент, но требующий осторожности.
Когда можно переписывать историю?¶
✅ Безопасно: - В локальных фич-ветках, которые еще не отправлены на сервер. - В личных форках, где никто другой не работает. - Перед созданием Pull Request для очистки истории.
❌ Опасно (нельзя):
- В общих ветках (main, develop), куда уже делали пуш другие разработчики.
- В ветках, над которыми работают коллеги.
Золотое правило: Никогда не переписывайте историю, если коммиты уже отправлены в общий репозиторий и могли быть использованы другими людьми.
Интерактивный Rebase¶
Основной инструмент для переписывания истории — git rebase -i.
Запуск интерактивного режима¶
git rebase -i HEAD~N
Где N — количество последних коммитов для редактирования.
Пример для 4 коммитов:
git rebase -i HEAD~4
Откроется редактор со списком коммитов:
pick a1b2c3d Добавить форму логина
pick e4f5g6h Исправить стили
pick h7i8j9k Добавить тесты
pick l0m1n2o Обновить документацию
Команды для каждого коммита¶
Замените pick на одну из команд:
| Команда | Описание |
|---|---|
p (pick) |
Оставить коммит без изменений |
r (reword) |
Изменить сообщение коммита |
e (edit) |
Остановиться для внесения изменений в код |
s (squash) |
Объединить с предыдущим коммитом |
f (fixup) |
Как squash, но отбросить сообщение |
d (drop) |
Удалить коммит полностью |
x (exec) |
Выполнить команду shell |
Пример: Объединение коммитов (Squash)¶
Хотим объединить 4 коммита в один чистый:
pick a1b2c3d Добавить форму логина
squash e4f5g6h Исправить стили
squash h7i8j9k Добавить тесты
squash l0m1n2o Обновить документацию
После сохранения откроется редактор для написания итогового сообщения:
Добавить полную функциональность авторизации
- Реализована форма входа
- Добавлена валидация
- Написаны тесты
- Обновлена документация API
Пример: Изменение порядка коммитов¶
Просто поменяйте строки местами:
pick a1b2c3d Добавить форму логина
pick h7i8j9k Добавить тесты
pick e4f5g6h Исправить стили
pick l0m1n2o Обновить документацию
Пример: Редактирование коммита (Edit)¶
Если нужно изменить содержимое коммита (добавить забытый файл):
pick a1b2c3d Добавить форму логина
edit e4f5g6h Исправить стили
pick h7i8j9k Добавить тесты
Git остановится на коммите e4f5g6h:
Stopped at e4f5g6h... Исправить стили
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Внесите изменения:
# Добавить забытый файл
git add забытый-файл.css
# Изменить коммит
git commit --amend --no-edit
# Продолжить rebase
git rebase --continue
Изменение последнего коммита¶
Если нужно просто исправить сообщение или добавить файл в последний коммит:
# Изменить сообщение
git commit --amend -m "Новое сообщение"
# Добавить файл без изменения сообщения
git add забытый-файл
git commit --amend --no-edit
Удаление чувствительных данных из истории¶
Если вы случайно закоммитили пароль или ключ:
С помощью git filter-repo (рекомендуется)¶
# Удалить файл из всей истории
git filter-repo --path path/to/secret.txt --invert-paths
# Удалить строку из всех файлов
git filter-repo --replace-text <файл-с-правилами>
С помощью BFG Repo-Cleaner¶
Быстрее и проще для больших репозиториев:
# Удалить файлы с определенным именем
bfg --delete-files secret.txt
# Удалить строки с паролями
bfg --replace-text passwords.txt
После очистки нужно сделать force push:
git push --force-with-lease origin main
Важно: После удаления чувствительных данных немедленно смените скомпрометированные пароли и ключи!
Разделение одного коммита на несколько¶
Если сделали большой коммит и хотите разбить его на логические части:
# Откатиться к коммиту перед нужным
git reset --soft HEAD~1
# Теперь все изменения в индексе
# Сделайте первый коммит
git add часть1
git commit -m "Первая часть"
# Второй коммит
git add часть2
git commit -m "Вторая часть"
# И так далее
Или через интерактивный rebase с командой edit.
Последствия переписывания истории¶
После переписывания истории хеши всех измененных коммитов меняются. Если ветка уже была на сервере:
- Локально история изменилась.
- На сервере осталась старая история.
- При попытке обычного
git pushполучите ошибку.
Нужен force push:
git push --force-with-lease origin <ветка>
Внимание: Все, кто скачал старую версию ветки, должны будут делать
git fetchиgit reset --hard origin/<ветка>, чтобы синхронизироваться.
Альтернативы переписыванию истории¶
Если история уже общая, используйте: - Revert — для отмены ошибочных коммитов. - Новые коммиты — для исправления ошибок.