git commit --allow-empty: создание пустого коммита
Обычно Git отказывается создавать коммит, если нет никаких изменений в файлах. Это логичная защита — зачем сохранять точку в истории, если ничего не изменилось?
Однако, есть специальные ситуации, когда вам нужен пустой коммит:
- Запуск CI/CD — Вы хотите перезапустить сборку/тесты, не меняя код
- Маркеры в истории — Вы хотите отметить важное событие (начало спринта, релиз)
- Тестирование hooks — Вы хотите проверить pre-commit или pre-push hooks без реальных изменений
- Monorepo структуры — Вы хотите создать корневой коммит для отдельной части проекта
Вот здесь вам помогает флаг --allow-empty, который позволяет создать коммит даже без изменений.
В этой статье разберём:
- Синтаксис
git commit --allow-empty - Реальные примеры использования
- Как просмотреть пустые коммиты в истории
- Лучшие практики при работе с пустыми коммитами
- Связь с Conventional Commits
Синтаксис #
Базовый пустой коммит #
$ git commit --allow-empty -m "Ваше сообщение"
Пустой коммит с подробным описанием #
$ git commit --allow-empty -m "Краткое описание" -m "Подробное описание"
Или в режиме редактора #
$ git commit --allow-empty
# Откроется редактор для написания сообщения
Коммит, пропуская hooks #
$ git commit --allow-empty --no-verify -m "Сообщение"
Случай 1: Запуск CI/CD вручную #
Это один из самых частых и практичных примеров использования --allow-empty. Представьте, что у вас есть GitHub Actions или другой CI/CD сервис, который автоматически запускается при каждом push’е.
Сценарий: Вы отправили код, и CI/CD обнаружил непостоянное падение теста (flaky test). Тест прошёл со случайной ошибкой, но код правильный. Вам нужно перезапустить тесты без изменения кода.
# Способ 1 (неправильно): создаёте файл, коммитите его, потом удаляете
$ touch dummy.txt
$ git add dummy.txt
$ git commit -m "Trigger CI"
$ rm dummy.txt
# Результат: бесполезный коммит в истории ❌
# Способ 2 (правильно): пустой коммит
$ git commit --allow-empty -m "ci: переза пуск CI/CD для проверки"
$ git push
# Результат: CI/CD перезапустится, история чистая ✓
Пример GitHub Actions workflow #
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy
run: ./deploy.sh
Если вам нужно перезапустить деплой:
$ git commit --allow-empty -m "chore: переза пуск деплоя"
$ git push
GitHub Actions увидит push и автоматически запустит workflow.
Alias для быстрого перезапуска CI #
Добавьте в ~/.gitconfig:
[alias]
ci-retrigger = commit --allow-empty -m "ci: retrigger"
ci-redeploy = commit --allow-empty -m "ci: redeploy"
Использование:
$ git ci-retrigger && git push
Случай 2: Маркеры в истории #
Пустые коммиты можно использовать для отметки важных событий в истории проекта:
Пример: Начало спринта #
# Сегодня начало спринта #42
$ git commit --allow-empty -m "chore: начало Sprint #42"
$ git push
# История:
# 2a1b3c4 chore: начало Sprint #42
# 9f8e7d6 Исправлена ошибка в парсере
# 5c4b3a2 Добавлена новая функция
Позже, когда вы хотите узнать, когда начался спринт, вы легко можете найти этот коммит.
Пример: Вехи проекта #
# Проект достигнул версии 1.0.0
$ git tag -a v1.0.0 -m "Release version 1.0.0"
$ git commit --allow-empty -m "release: версия 1.0.0 готова к производству"
$ git push origin main --tags
# История:
# a9b8c7d release: версия 1.0.0 готова к производству
# x8y7z6w fix: исправлены критические баги
# m7n6o5p chore: подготовка к релизу
Пример: Передача проекта #
# Проект передаётся другой команде
$ git commit --allow-empty -m "chore: передача проекта команде backend-team"
$ git push
# История:
# t1a2s3k chore: передача проекта команде backend-team
# q1w2e3r Финальные оптимизации производительности
# ...
Пример: Завершение задачи в Jira #
# Завершили большой feature
$ git commit --allow-empty -m "feat: завершен PROJ-1234 - полная переработка API"
$ git push
# История содержит чистый маркер:
# h1e2l3l chore: завершен PROJ-1234
Случай 3: Тест hooks без изменений #
Если вы разрабатываете или тестируете Git hooks (pre-commit, pre-push, commit-msg), вам может понадобиться создать коммит без реальных изменений.
Пример: Тестирование commit-msg hook #
# Вы только что создали hook, который проверяет формат сообщения
$ cat .git/hooks/commit-msg
#!/bin/bash
# Сообщение должно начинаться с "feat:", "fix:", "chore:" и т.д.
if ! echo "$1" | grep -qE "^(feat|fix|chore|docs):"; then
echo "Ошибка: сообщение должно начинаться с feat:, fix:, chore: или docs:"
exit 1
fi
# Тест 1: Правильный формат
$ git commit --allow-empty -m "feat: новая фишка"
# Успех! Коммит создан ✓
# Тест 2: Неправильный формат
$ git commit --allow-empty -m "добавлена новая фишка"
# Ошибка: сообщение должно начинаться с feat:, fix:, chore: или docs:
# Хук отработал правильно! ✓
# Тест 3: Пропуск хука (если нужно)
$ git commit --allow-empty --no-verify -m "добавлена новая фишка"
# Коммит создан без проверки хука
Пример: Тестирование pre-commit hook #
$ cat .git/hooks/pre-commit
#!/bin/bash
# Проверка синтаксиса Python
python -m py_compile src/**/*.py || exit 1
# Но нам нужно только тестировать hook, без реальных изменений
$ git commit --allow-empty -m "test: проверка pre-commit hook"
# Hook сработает, даже хотя нет файлов для проверки
Случай 4: Корневой коммит для monorepo #
В монорепозиториях (когда один репозиторий содержит несколько независимых проектов) иногда нужно создать отдельную историю для каждого проекта.
# Структура monorepo:
# /
# backend/
# frontend/
# shared/
# Создаём пустой корневой коммит для backend
$ git commit --allow-empty -m "init: инициализация backend проекта"
$ git push
# Позже, когда захотите работать только с backend:
$ git log --all -- backend/ # покажет коммиты для backend
Просмотр пустых коммитов в истории #
Стандартное просмотра истории #
Пустые коммиты видны в истории как обычные:
$ git log --oneline
a9b8c7d ci: retrigger CI/CD
x8y7z6w feat: добавлена новая функция
m7n6o5p fix: исправлена ошибка
Проверка, что коммит действительно пустой #
# Показать коммит и его изменения
$ git show a9b8c7d --stat
# Вывод:
# commit a9b8c7da1b2c3d4e5f6g7h8
# Author: Ivan Petrov <[email protected]>
# Date: Fri Feb 27 10:30:00 2026 +0300
#
# ci: retrigger CI/CD
#
# (нет файлов, so no changes to display)
Поиск всех пустых коммитов #
# Найти все коммиты без изменений файлов
$ git log --all --diff-filter=M --oneline
# Или более сложный поиск через git rev-list
$ git rev-list --all | while read commit; do
if [ $(git diff --name-only $commit^..$commit | wc -l) -eq 0 ]; then
echo "Пустой коммит: $commit"
git show --oneline -s $commit
fi
done
Фильтрация пустых коммитов из логов #
Если вы хотите показать историю без пустых коммитов:
# Использовать самодельный скрипт или инструмент
# К сожалению, встроенного флага нет, но можно использовать:
$ git log --all --pretty=format:"%h %s" | grep -v "^[a-f0-9]* $"
Лучшие практики #
1. Используйте значимые сообщения #
# ❌ Плохо: неинформативное сообщение
$ git commit --allow-empty -m "Empty commit"
# ✓ Хорошо: ясно объясняет причину
$ git commit --allow-empty -m "ci: перезапуск CI для проверки непостоянного теста"
2. Используйте Conventional Commits префиксы #
# Для пустых коммитов используйте префиксы, чтобы объяснить причину:
# ci: для запуска CI/CD
$ git commit --allow-empty -m "ci: переза пуск сборки"
# chore: для административных операций
$ git commit --allow-empty -m "chore: начало Sprint #42"
# docs: для обновления документации без кода
$ git commit --allow-empty -m "docs: завершена документация API"
# test: для тестирования hooks или процессов
$ git commit --allow-empty -m "test: проверка commit-msg hook"
3. Ограничивайте использование пустых коммитов #
Пустые коммиты — это инструмент для исключительных ситуаций. Используйте их рассудительно:
# ✓ Правильное использование: редкое и с причиной
$ git commit --allow-empty -m "ci: retrigger flaky test"
# ❌ Неправильное использование: частые и без смысла
$ git commit --allow-empty -m "update"
$ git commit --allow-empty -m "changes"
4. Избегайте пустых коммитов в shared branches #
Не создавайте пустые коммиты в общих ветках (main, develop), если это может запутать коллег. Используйте их только в:
- Личных feature branches
- CI/CD automation
- Документированных маркерах версий
5. Документируйте причину #
Если вы используете пустой коммит, убедитесь, что сообщение ясно объясняет почему:
# ✓ Хорошо: понятна причина
$ git commit --allow-empty -m "ci: перезапуск CI после обновления GitHub Actions"
# ❌ Плохо: непонятна причина
$ git commit --allow-empty -m "trigger"
Связь с Conventional Commits #
Conventional Commits — это стандарт для форматирования сообщений коммитов. Для пустых коммитов рекомендуется использовать соответствующие префиксы:
<type>[optional scope]: <description>
Типы для пустых коммитов:
| Тип | Использование | Пример |
|---|---|---|
| ci | CI/CD операции, перезапуск | ci: retrigger GitHub Actions |
| chore | Административные операции, маркеры | chore: start Sprint #42 |
| docs | Документация без кода | docs: update API documentation |
| test | Тестирование процессов | test: verify pre-commit hook |
# Примеры с Conventional Commits:
$ git commit --allow-empty -m "ci: retrigger tests after GitHub Actions update"
$ git commit --allow-empty -m "chore: mark release v2.0.0"
$ git commit --allow-empty -m "docs: document monorepo structure"
FAQ #
Вопрос 1: Почему я не могу просто отправить пустой push вместо коммита?
Git не позволяет push’ить без новых коммитов. Если нужно переза пустить CI/CD, нужно создать коммит (пустой или нет). Пустой коммит — это чистый способ сделать это, он не загрязняет историю.
Вопрос 2: Есть ли флаг –allow-empty-message, который позволит пустое сообщение?
Да, git commit --allow-empty --allow-empty-message создаст коммит без сообщения. Но это очень не рекомендуется, потому что история станет невоспроизводимой. Всегда используйте -m с описанием.
# Не делайте так:
$ git commit --allow-empty --allow-empty-message
# Делайте так:
$ git commit --allow-empty -m "Описание"
Вопрос 3: Как пустой коммит влияет на git bisect?
При использовании git bisect для поиска регрессии, пустые коммиты будут включены в процесс поиска. Это может немного замедлить bisect, но не нарушает его функциональность. Если вам часто нужен bisect, минимизируйте количество пустых коммитов.
Вопрос 4: Как удалить пустой коммит из истории?
# Если это последний коммит:
$ git reset --soft HEAD~1
$ git reset HEAD
# Или:
$ git rebase -i HEAD~2 # интерактивный rebase, удалите строку с пустым коммитом
# На общей ветке (после push):
$ git revert <commit-hash>
$ git push
Вопрос 5: Можно ли использовать пустой коммит вместо git tag?
Нет, это не рекомендуется. Git tags специально предназначены для маркирования версий и выпусков. Для версионирования используйте git tag, а не пустые коммиты:
# ✓ Правильно для версий:
$ git tag -a v1.0.0 -m "Release version 1.0.0"
# Если нужен маркер в истории, то:
$ git commit --allow-empty -m "release: v1.0.0"
$ git tag v1.0.0 # обе операции вместе
Заключение #
git commit --allow-empty — это специализированный инструмент для:
- Запуска CI/CD без изменения кода
- Создания маркеров в истории проекта
- Тестирования hooks и процессов
- Специальных сценариев в monorepo
Ключевые принципы:
- Используйте только когда нужно (редко)
- Всегда пишите понятное сообщение с префиксом (ci:, chore:, docs:)
- Избегайте на общих ветках
- Документируйте причину в сообщении коммита
Не используйте для:
- Загрязнения истории без причины
- Замены нормальных коммитов
- Сообщений без содержания
Пустые коммиты — это мощный инструмент в правильных руках, но его нужно использовать осознанно и редко.
Дополнительная информация доступна в статьях /ru/git/git-commit/, /ru/git/git-hooks/ и /ru/git/conventional-commits/.