← Назад к вопросам

Что такое Squash?

1.8 Middle🔥 151 комментариев
#Git и VCS

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Squash в Git: объединение коммитов

Squash — это операция в Git, которая объединяет несколько коммитов в один. Она полезна для очистки истории, перед тем как мерджить pull request в основную ветку. Squash убирает лишние intermediate коммиты и создаёт чистую историю разработки.

Основная идея

Вместо истории вроде:

commit 3: Fix typo
commit 2: WIP: refactoring
commit 1: Add new feature

Squash создаёт:

commit 1: Add new feature (includes fixes and refactoring)

Все изменения остаются, но история становится линейной и понятной.

Типы Squash операций

1. Interactive Rebase (самый гибкий)

# Объединить последние 3 коммита
git rebase -i HEAD~3

Отворится интерактивный редактор:

pick 1234567 Add new feature
pick 2345678 WIP: refactoring
pick 3456789 Fix typo

Изменяем на:

pick 1234567 Add new feature
squash 2345678 WIP: refactoring        # или 's' вместо 'squash'
squash 3456789 Fix typo

Сохраняем (:wq в Vim), и Git просит новое сообщение коммита:

# Combine commits
Add new feature

WIP: refactoring
Fix typo

Редактируем в итоговое:

Add new feature with refactoring

Результат:

$ git log --oneline -3
1234567 Add new feature with refactoring

2. Soft Reset (простой способ)

# Вернуться на 3 коммита назад, но сохранить изменения
git reset --soft HEAD~3

# Теперь все файлы в staging area (green в 'git status')
git status
# modified: file1.py
# modified: file2.py

# Коммитим один раз
git commit -m "Add new feature with refactoring and fixes"

Это эквивалент squash, но без interactive rebase.

3. GitHub Squash при Merge

На GitHub можно squash автоматически при мерже PR:

┌─────────────────────┐
│ Pull Request #123   │
│ "Add feature X"     │
├─────────────────────┤
│ Commits:            │
│ - WIP: start        │
│ - fix bug           │
│ - refactor          │
│ - final polish      │
└─────────────────────┘
         ↓ (merge with "Squash and merge")
┌─────────────────────┐
│ Main branch         │
│ - Add feature X     │ ← Все 4 коммита в один
└─────────────────────┘

На GitHub:

  1. Open Pull Request
  2. Нажимаем на "Squash and merge" (вместо обычного "Merge")
  3. GitHub автоматически объединит все коммиты

Реальный пример: разработка feature

До Squash (история грязная)

$ git log --oneline
a1b2c3d Fix typo in docstring
5f6g7h8 Refactor payment validation
9i0j1k2 WIP: payment module
3l4m5n6 Add payment support
main    Previous release

Squash процесс

# Находимся на feature ветке
git checkout feature/payment

# Начинаем interactive rebase от main
git rebase -i main
# или
git rebase -i HEAD~4  # последних 4 коммита

В редакторе:

pick 3l4m5n6 Add payment support
s 9i0j1k2 WIP: payment module           # squash
s 5f6g7h8 Refactor payment validation   # squash
s a1b2c3d Fix typo in docstring          # squash

Сохраняем, редактируем message:

Add payment module with validation

- Implement payment processing
- Add validation for payment data
- Fix documentation

Результат:

$ git log --oneline
newsha123 Add payment module with validation
main      Previous release

Пушим на GitHub

# Нужно force-push, так как переписали историю
git push origin feature/payment --force-with-lease

Важно: --force-with-lease безопаснее чем --force, потому что проверит, что никто не запушил новые коммиты с тех пор.

Squash vs Merge vs Rebase

ОперацияКоммитыИсторияКогда использовать
MergeОба веткиДве ветвиДолгоживущие feature ветки
RebaseПереписываютсяЛинейнаяЧистая история, малые фичи
SquashОдин новыйОчень чистаяPull Requests, готовый код
Merge:
o--o--o (main)
 |     \
 |      o--o--o (feature)
 |              |
 o--o--o--------o (merge commit)

Rebase:
o--o--o (main)
        |
        o--o--o (feature, перезаписано)

Squash:
o--o--o (main)
 |     
 |     o (один коммит со всеми изменениями)
 |    /
 o--o (merged)

Практические примеры

Пример 1: Разработчик перед PR

# На локальной ветке 10 коммитов, но хотим отправить один PR
git log --oneline
head~9 Initial idea
head~8 WIP
head~7 Fix issue
head~6 Refactor
head~5 Add tests
head~4 Fix tests
head~3 Review changes
head~2 Final touches
head~1 Typo fix
head   Done

# Squashим
git rebase -i main
# Все коммиты после main делаем 'squash'

# Результат: один красивый коммит в PR

Пример 2: Очистка грязной истории

# Текущая ветка
git log --oneline | head -5
a1b2c3d oops, forgot this
9i0j1k2 WIP WIP WIP
5f6g7h8 Actually this
3l4m5n6 Start here

# Squashим последние 4 коммита
git reset --soft HEAD~4
git commit -m "Implement feature properly"

# История чистая
git log --oneline | head -1
newsha1 Implement feature properly

Пример 3: GitHub через Web UI

1. Открываем PR
2. Все коммиты видны в "Commits" табе
3. Нажимаем кнопку "Squash and merge"
4. GitHub автоматически объединит коммиты
5. Ветка удаляется (если включено)

Опасности и как их избежать

Опасность 1: Потеря истории при --force

# Опасно! Может затереть работу других
git push origin feature --force

# Безопасно! Проверит, что ничего не потеряется
git push origin feature --force-with-lease

Опасность 2: Squash в общей ветке

# Плохо: squash commits в main
# Это переписывает историю, которая уже на сервере!
git checkout main
git rebase -i HEAD~3  # ← НИКОГДА так не делай

# Хорошо: squash только в own feature ветке
git checkout feature/my-feature
git rebase -i main  # ← Тут OK

Опасность 3: Забыть --soft

# Потеряешь все изменения!
git reset --hard HEAD~3  # ← ОПАСНО!

# Правильно для squash
git reset --soft HEAD~3  # ← Сохраняет изменения

Лучшие практики

  1. Squash перед PR: Очищай историю перед отправкой на review
  2. Используй --force-with-lease: Безопаснее чем --force
  3. Никогда squash не в feature ветке: Только в своих ветках
  4. Хорошее commit message: После squash напиши ясный message
  5. На GitHub используй "Squash and merge": Вместо manual rebase

Отмена squash

# Если случайно squashил и хочешь отмену
git reflog  # Найди старый HEAD
git reset --hard a1b2c3d  # Вернись к старому состоянию

Squash — мощный инструмент для сохранения чистоты Git истории. Его главная цель — сделать историю проекта понятной и легко читаемой при просмотре git log!