n1ro°
RU

Компьютеры · Инструкция

git push --atomic: как отправить несколько refs по принципу «все или ничего»

git push --atomic нужен, когда несколько ссылок Git должны попасть на удалённый сервер одной логической операцией.

Редакция N1RO · Проверено

Короткий ответ

Используйте `git push --atomic <remote> <refspec1> <refspec2> ..`, если несколько веток или тегов должны обновиться согласованно. Команда завершится ошибкой, если хотя бы один ref нельзя обновить или удалённый сервер не поддерживает атомарные push-транзакции.

Когда атомарный push действительно нужен

Обычный `git push` может отправлять сразу несколько refs, но бизнес-условие «они должны измениться вместе» из этого само по себе не следует. Типичный пример — релиз, где ветка `main` и тег версии должны указывать на совместимый набор коммитов, или публикация нескольких связанных release-веток. Если один ref защищён политикой сервера, содержит non-fast-forward изменение или не проходит hook, частично выполненная операция способна оставить удалённый репозиторий в состоянии, которое команда не ожидала. Опция `--atomic` меняет именно семантику группы обновлений: сервер должен применить все заявленные изменения как одну транзакцию либо не применить ни одного. Это не делает опасный ref допустимым и не обходит branch protection; она лишь не позволяет остальным refs «проскочить» отдельно. Поэтому сначала определите, действительно ли refs связаны одним инвариантом, а не включайте atomic механически для любого push.

Совет: Если требуется только защитить одну переписываемую ветку от чужих изменений, это другой интент: обычно смотрят на `--force-with-lease`, а не на `--atomic`.

Как выполнить atomic push и проверить результат

  1. 1: Обновите локальные сведения об удалённом репозитории: выполните `git fetch <remote>` и убедитесь, что базируетесь на актуальном состоянии. Это особенно важно, если среди refs есть ветки, где возможен non-fast-forward отказ.
  2. 2: Просмотрите, что именно собираетесь отправить. Для веток полезны `git log --oneline --decorate --graph <remote>/<branch>.<branch>` и `git diff`; для тегов — `git show <tag>`.
  3. 3: Сформируйте явный набор refs, например `git push --atomic origin main release/2.4 v2.4.0`. Явный список легче проверить, чем полагаться на широкий push refspec из конфигурации.
  4. 4: Если сервер отклонил один из refs, прочитайте причину и исправьте её: права, protected branch, hook, non-fast-forward или отсутствующий объект. Не разбивайте операцию на отдельные push, если согласованность этих refs была причиной выбора atomic.
  5. 5: После успешной отправки выполните `git ls-remote <remote>` или откройте удалённый репозиторий и проверьте целевые refs. Локальный код возврата команды также должен быть успешным.

Важно: Атомарность гарантирует совместное применение заявленных ref-обновлений, но не заменяет проверку того, что вы перечислили правильные refs.

Что происходит при отказе одного ref

Представим, что вы одновременно отправляете `main` и `v2.4.0`, но `main` защищена и прямые push запрещены. В atomic-режиме это не означает «тег всё равно создастся»: вся группа должна быть отклонена. Такой результат полезнее тихой частичной публикации, потому что следующий шаг CI/CD не увидит новый тег при старой ветке. Аналогично, если один ref требует non-fast-forward обновления, Git не превращает его автоматически в force push. Сначала устраните конфликт истории или выберите осознанную стратегию для этого ref. Учитывайте и серверную сторону: документация Git прямо оговаривает, что запрос `--atomic` завершается ошибкой, если сервер атомарную отправку не поддерживает. Это надо проверить до критического релизного окна, а не впервые во время публикации.

Примеры команд для разных сценариев

  • Две связанные ветки. git push --atomic origin main release/2.4. Обе ветки обновятся вместе или обе останутся как были.
  • Ветка и аннотированный тег. git push --atomic origin main v2.4.0. Не возникнет состояния «тег опубликован, ветка отклонена».
  • Явные refspec. git push --atomic origin refs/heads/main:refs/heads/main refs/tags/v2.4.0:refs/tags/v2.4.0. Максимально явно задаёт источник и назначение каждого ref.

Совет: Перед релизом прогоните такую команду на тестовом remote с тем же типом сервера и политиками. Так вы заранее узнаете, поддерживается ли atomic и какие server-side checks срабатывают.

Частые ошибки и границы --atomic

Не путайте атомарность с откатом содержимого репозитория. Если push уже успешно завершился, `--atomic` не даёт отдельной команды «rollback»; обратное изменение выполняется новым корректным обновлением refs. Не стоит также добавлять `--force` только ради того, чтобы группа прошла: force меняет правила допустимости обновления, а atomic — правила совместного применения, это независимые свойства. В автоматизации проверяйте ненулевой exit code и не запускайте публикацию артефактов после неуспешного push. Если pipeline формирует список refs динамически, логируйте этот список до выполнения команды: иначе при ошибке трудно понять, какой именно ref заблокировал транзакцию. Для защищённых веток учитывайте правила GitHub или другого хостинга отдельно — локальная опция Git не отменяет политики репозитория.

Atomic push в CI/CD: что логировать

В CI полезно сохранять не только stdout `git push`, но и точный список refs и SHA, которые pipeline собирался обновить. Тогда при общем отказе видно, какой набор должен был быть транзакцией и какой ref требовал исправления. Не запускайте release-публикацию по факту создания локального тега: триггер должен зависеть от успешного завершения удалённого atomic push и, при критичном процессе, от последующей проверки remote. Если теги или ветки формируются автоматически, валидируйте пустые значения и неожиданные wildcard ещё до команды. Такой контроль не расширяет гарантии Git, но не даёт скрипту ошибочно трактовать отказ транзакции как частичный успех.

Как встроить atomic push в релиз без ложного успеха

Для релизного скрипта полезно заранее сформировать список удалённых refs и ожидаемых локальных SHA, вывести их в лог, а затем выполнить одну команду `git push --atomic`. После неё проверяйте именно exit code Git: сообщение о созданном локальном теге ещё ничего не говорит о состоянии remote. Если push отклонён из-за одной защищённой ветки или server-side hook, не запускайте публикацию пакетов, создание GitHub Release или деплой из предположения, что остальные refs уже ушли. Исправьте причину отказа и повторите всю транзакцию тем же набором refs. Для ветки и тега релиза это особенно важно: тег, указывающий на коммит, которого нет в ожидаемой ветке remote, способен запустить автоматизацию в несогласованном состоянии. После успешной команды можно сделать контрольный `git ls-remote origin refs/heads/main refs/tags/v2.4.0` и сопоставить полученные SHA с теми, которые логировал pipeline. Такая проверка не заменяет атомарность, но подтверждает, что сценарий отправил именно тот набор, который вы собирались публиковать.

Что учитывать

Условия меняются. Страница отражает состояние на 2026-09-20; при расхождении с официальной документацией приоритет у первоисточника.

Источники и проверка

Фактическая часть сверена по первичным источникам (в т.ч. git-push Documentation). Пример и формулировки — редакция N1RO на 2026-09-20.