Setup and Config
Getting and Creating Projects
Basic Snapshotting
Branching and Merging
Sharing and Updating Projects
Inspection and Comparison
Patching
Debugging
External Systems
Server Admin
Guides
- gitattributes
- Command-line interface conventions
- Everyday Git
- Frequently Asked Questions (FAQ)
- Glossary
- Hooks
- gitignore
- gitmodules
- Revisions
- Submodules
- Tutorial
- Workflows
- All guides...
Administration
Plumbing Commands
-
2.53.0
2026-02-02
-
2.52.0
2025-11-17
- 2.48.1 → 2.51.2 no changes
-
2.48.0
2025-01-10
- 2.45.1 → 2.47.3 no changes
-
2.45.0
2024-04-29
- 2.44.1 → 2.44.4 no changes
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.7 no changes
-
2.43.0
2023-11-20
- 2.42.2 → 2.42.4 no changes
-
2.42.1
2023-11-02
-
2.42.0
2023-08-21
- 2.41.1 → 2.41.3 no changes
-
2.41.0
2023-06-01
- 2.40.1 → 2.40.4 no changes
-
2.40.0
2023-03-12
- 2.39.1 → 2.39.5 no changes
-
2.39.0
2022-12-12
- 2.38.1 → 2.38.5 no changes
-
2.38.0
2022-10-02
- 2.35.1 → 2.37.7 no changes
-
2.35.0
2022-01-24
- 2.33.1 → 2.34.8 no changes
-
2.33.0
2021-08-16
- 2.32.1 → 2.32.7 no changes
-
2.32.0
2021-06-06
- 2.30.1 → 2.31.8 no changes
-
2.30.0
2020-12-27
- 2.25.1 → 2.29.3 no changes
-
2.25.0
2020-01-13
- 2.23.1 → 2.24.4 no changes
-
2.23.0
2019-08-16
- 2.22.1 → 2.22.5 no changes
-
2.22.0
2019-06-07
- 2.21.1 → 2.21.4 no changes
-
2.21.0
2019-02-24
- 2.20.1 → 2.20.5 no changes
-
2.20.0
2018-12-09
- 2.18.1 → 2.19.6 no changes
-
2.18.0
2018-06-21
- 2.17.0 → 2.17.6 no changes
-
2.16.6
2019-12-06
-
2.15.4
2019-12-06
- 2.14.6 no changes
-
2.13.7
2018-05-22
-
2.12.5
2017-09-22
-
2.11.4
2017-09-22
-
2.10.5
2017-09-22
-
2.9.5
2017-07-30
-
2.8.6
2017-07-30
-
2.7.6
2017-07-30
-
2.6.7
2017-05-05
- 2.5.6 no changes
-
2.4.12
2017-05-05
-
2.3.10
2015-09-28
-
2.2.3
2015-09-04
- 2.1.4 no changes
-
2.0.5
2014-12-17
ОБЗОР
gitpush[--all|--branches|--mirror|--tags] [--follow-tags] [--atomic] [-n|--dry-run] [--receive-pack=<пакет-получения-git>] [--repo=<репозиторий>] [-f|--force] [-d|--delete] [--prune] [-q|--quiet] [-v|--verbose] [-u|--set-upstream] [-o<строка> |--push-option=<строка>] [--[no-]signed|--signed=(true|false|if-asked)] [--force-with-lease[=<имя-ссылки>[:<ожидаемое>]] [--force-if-includes]] [--no-verify] [<репозиторий> [<спецификатор-ссылки>…]]
ОПИСАНИЕ
Обновляет одну или несколько веток, меток или других ссылок во внешнем (remote) репозитории из вашего локального репозитория и отправляет все необходимые данные, которых ещё нет во внешнем репозитории.
Самый простой способ отправить изменения — git push <внешний-репозиторий> <ветка>. git push origin main отправит локальную ветку main в ветку main во внешнем репозитории с именем origin.
Аргумент <репозиторий> по умолчанию указывает на вышестоящий (upstream) репозиторий для текущей ветки или на origin, если вышестоящий репозиторий не настроен.
Чтобы решить, какие ветки, метки или другие ссылки отправлять, Git использует (в порядке приоритета):
-
Аргумент(ы) <спецификатор-ссылки> (например,
mainвgitpushoriginmain) или параметры--all,--mirrorили--tags -
Конфигурация
remote.<имя>.pushдля репозитория, в который выполняется отправка -
Конфигурация
push.default. Значение по умолчанию —push.default=simple, которое отправляет изменения в ветку с тем же именем, что и текущая ветка. См. раздел КОНФИГУРАЦИЯ ниже для получения дополнительной информации оpush.default.
git push может завершиться сбоем, если вы не установили вышестоящую (upstream) ветку для текущей ветки, в зависимости от того, на что установлен push.default. См. раздел ВЫШЕСТОЯЩИЕ ВЕТКИ ниже для получения дополнительной информации о том, как устанавливать и использовать вышестоящие ветки.
Вы можете заставить репозиторий выполнять интересные действия каждый раз, когда вы отправляете в него изменения, настроив там перехватчики (hooks). См. документацию по git-receive-pack[1].
ПАРАМЕТРЫ
- <репозиторий>
-
«Внешний» (remote) репозиторий, являющийся целью операции отправки (push). Этот параметр может быть либо URL-адресом (см. раздел URL-АДРЕСА GIT ниже), либо именем внешнего репозитория (см. раздел ВНЕШНИЕ РЕПОЗИТОРИИ ниже).
- <refspec>...
-
Указывает, какую целевую ссылку обновлять с помощью какого исходного объекта.
Формат спецификатора ссылки (refspec): [
+]<источник>[:<назначение>], напримерmain,main:otherилиHEAD^:refs/heads/main.<источник> часто является именем локальной ветки для отправки, но это может быть любое произвольное «выражение SHA-1» (см. gitrevisions[7]).
<назначение> определяет, какую ссылку обновлять на внешней стороне. Это должно быть имя ветки, метки или другой ссылки, а не произвольное выражение.
+необязателен и делает то же самое, что и--force.Вы можете написать спецификатор ссылки, используя полностью развёрнутую форму (например,
refs/heads/main:refs/heads/main), которая указывает точный источник и назначение, или более короткую форму (например,mainилиmain:other). Вот правила того, как разворачиваются спецификаторы ссылок, а также различные другие специальные формы спецификаторов ссылок:-
<источник> без
:<назначение> означает обновление той же ссылки, что и <источник>, если только конфигурацияremote.<репозиторий>.pushне указывает другое <назначение>. Например, еслиmain— это ветка, то спецификатор ссылкиmainразворачивается вmain:refs/heads/main. -
Если <назначение> однозначно ссылается на ссылку во внешнем репозитории <репозиторий>, то развернуть его в эту ссылку. Например, если
v1.0— это метка во внешнем репозитории, тоHEAD:v1.0разворачивается вHEAD:refs/tags/v1.0. -
Если <источник> преобразуется в ссылку, начинающуюся с
refs/heads/илиrefs/tags/, то добавить это префикс к <назначение>. Например, еслиmain— это ветка, тоmain:otherразворачивается вmain:refs/heads/other -
Специальный спецификатор ссылки
:(или+:для разрешения обновлений, отличных от перемотки вперёд) указывает Git отправлять «совпадающие» ветки: для каждой ветки, существующей на локальной стороне, внешняя сторона обновляется, если ветка с таким же именем уже существует на внешней стороне. -
<источник> может содержать
*для указания простого сопоставления с образцом. Это работает как glob-шаблон, который соответствует любой ссылке, подходящей под образец. В <источник> и <назначение> должен быть только один*. Он будет сопоставлять ссылки с назначением, заменяя * содержимым, соответствующим источнику. Например,refs/heads/*:refs/heads/*отправит все ветки. -
Спецификатор ссылки, начинающийся с
^, является отрицательным спецификатором ссылки. Он указывает ссылки для исключения. Ссылка будет считаться соответствующей, если она соответствует хотя бы одному положительному спецификатору ссылки и не соответствует ни одному отрицательному спецификатору ссылки. Отрицательные спецификаторы ссылок могут быть шаблонными спецификаторами ссылок. Они должны содержать только <источник>. Полностью записанные шестнадцатеричные имена объектов также не поддерживаются. Например,gitpushoriginrefs/heads/*'^refs/heads/dev-*'отправит все ветки, кроме тех, которые начинаются сdev- -
Если <источник> пуст, он удаляет ссылку <назначение> из внешнего репозитория. Например,
gitpushorigin:devудалит веткуdev. -
tag<метка> разворачивается вrefs/tags/<метка>:refs/tags/<метка>. Технически это специальный синтаксис дляgitpush, а не спецификатор ссылки, поскольку вgitpushorigintagv1.0аргументыtagиv1.0являются отдельными. -
Если спецификатор ссылки не может быть однозначно развёрнут, завершиться с ошибкой, указывающей, что было предпринято, и, в зависимости от конфигурации
advice.pushUnqualifiedRefname(см. git-config[1]), предложить, в какое пространство имён refs/ вы, возможно, хотели отправить.
-
Не все обновления разрешены: подробности см. в разделе ПРАВИЛА ОТПРАВКИ ниже.
-
--all -
--branches -
Отправить все ветки (т.е. ссылки в
refs/heads/); нельзя использовать с другими <спецификатор-ссылки>. -
--prune -
Удалить внешние ветки, у которых нет локального аналога. Например, внешняя ветка
tmpбудет удалена, если локальной ветки с таким же именем больше не существует. Это также учитывает спецификаторы ссылок, например, git push --prune внешний-репозиторий refs/heads/*:refs/tmp/* гарантирует, что внешняяrefs/tmp/fooбудет удалена, еслиrefs/heads/fooне существует. -
--mirror -
Вместо указания каждой отправляемой ссылки указывает, что все ссылки в
refs/(что включает, но не ограничиваетсяrefs/heads/,refs/remotes/иrefs/tags/) должны быть зеркально отражены во внешнем репозитории. Новые локальные ссылки будут отправлены на внешнюю сторону, локально обновлённые ссылки будут принудительно обновлены на внешней стороне, а удалённые ссылки будут удалены с внешней стороны. Это значение по умолчанию, если установлен параметр конфигурацииremote.<внешний-репозиторий>.mirror. -
-n -
--dry-run -
Сделать всё, кроме фактической отправки обновлений.
-
--porcelain -
Выдавать машиночитаемый вывод. Строка состояния вывода для каждой ссылки будет разделена табуляцией и отправлена в stdout вместо stderr. Будут предоставлены полные символические имена ссылок.
-
-d -
--delete -
Все перечисленные ссылки удаляются из внешнего репозитория. Это то же самое, что и добавление двоеточия перед всеми ссылками.
-
--tags -
Все ссылки в
refs/tagsотправляются в дополнение к спецификаторам ссылок, явно указанным в командной строке. -
--follow-tags -
Отправить все ссылки, которые были бы отправлены без этого параметра, а также отправить аннотированные метки в
refs/tags, которых нет во внешнем репозитории, но которые указывают на указатели коммитов (commit-ish), достижимые из отправляемых ссылок. Это также можно указать с помощью переменной конфигурацииpush.followTags. Для получения дополнительной информации смотритеpush.followTagsв git-config[1]. -
--signed -
--no-signed -
--signed=(true|false|if-asked) -
Подписать GPG запрос на отправку (push) для обновления ссылок на принимающей стороне, чтобы позволить перехватчикам (hooks) проверить его и/или зарегистрировать в журнале. Возможные значения:
-
false -
--no-signed -
подписание не будет предпринято.
-
true -
--signed -
отправка завершится сбоем, если сервер не поддерживает подписанные отправки.
-
if-asked -
подписывать тогда и только тогда, когда сервер поддерживает подписанные отправки. Отправка также завершится сбоем, если фактический вызов
gpg--signзавершится сбоем. Подробности о принимающей стороне смотрите в git-receive-pack[1].
-
-
--atomic -
--no-atomic -
Использовать атомарную транзакцию на внешней стороне, если доступно. Либо обновляются все ссылки, либо в случае ошибки не обновляется ни одна ссылка. Если сервер не поддерживает атомарные отправки, отправка завершится сбоем.
-
-o<параметр> -
--push-option=<option> -
Передать данную строку на сервер при обмене данными по протоколу версии 2. Данная строка не должна содержать символы NUL или LF. Если параметр
--push-option=<параметры> указан несколько раз, то все эти строки будут отправлены другой стороне в том порядке, в котором они указанном в командной строке. Если в командной строке параметр--push-option=<параметры> не задан ни разу, то вместо этого будет использовано значения переменной конфигурацииpush.pushOption. -
--receive-pack=<пакет-получения-git> -
--exec=<git-receive-pack> -
Путь к программе git-receive-pack на внешней стороне. Иногда полезно при отправке во внешний репозиторий по ssh, и у вас нет этой программы в каталоге, находящемся в стандартном
$PATH. -
--force-with-lease -
--no-force-with-lease -
--force-with-lease=<refname> -
--force-with-lease=<refname>:<expect> -
Обычно
gitpushотказывается обновлять внешнюю ссылку, которая не является предком локальной ссылки, используемой для её перезаписи.Этот параметр отменяет это ограничение, если текущее значение внешней ссылки является ожидаемым значением. В противном случае
gitpushзавершается сбоем.Представьте, что вам нужно переместить (rebase) то, что вы уже опубликовали. Вам придётся обойти правило «обязательно перемотки вперёд», чтобы заменить историю, которую вы изначально опубликовали, на перемещённую историю. Если кто-то другой основал свою работу на вашей исходной истории, пока вы перемещали, верхушка (tip) ветки во внешнем репозитории может продвинуться с их коммитом, и слепая отправка с
--forceприведёт к потере их работы.Этот параметр позволяет вам указать, что вы ожидаете, что обновляемая вами история — это та, которую вы переместили и хотите заменить. Если внешняя ссылка всё ещё указывает на указанный вами коммит, вы можете быть уверены, что никто другой не делал ничего с этой ссылкой. Это похоже на взятие «аренды» (lease) на ссылку без её явной блокировки, и внешняя ссылка обновляется, только если «аренда» всё ещё действительна.
--force-with-leaseсам по себе, без указания деталей, защитит все внешние ссылки, которые будут обновлены, требуя, чтобы их текущее значение совпадало с отслеживаемой внешней веткой (remote-tracking branch), которая у нас есть для них.--force-with-lease=<имя-ссылки>, без указания ожидаемого значения, защитит <имя-ссылки> (отдельно), если оно будет обновлено, требуя, чтобы его текущее значение совпадало с отслеживаемой внешней веткой, которая у нас есть для неё.--force-with-lease=<имя-ссылки>:<ожидаемое> защитит <имя-ссылки> (отдельно), если оно будет обновлено, требуя, чтобы его текущее значение совпадало с указанным значением <ожидаемое> (которое может отличаться от отслеживаемой внешней ветки, которая у нас есть для этого имени ссылки, или при использовании этой формы у нас может даже не быть такой отслеживаемой внешней ветки). Если <ожидаемое> — пустая строка, то указанная ссылка не должна уже существовать.Обратите внимание, что все формы, кроме
--force-with-lease=<имя-ссылки>:<ожидаемое>, которая явно указывает ожидаемое текущее значение ссылки, всё ещё являются экспериментальными, и их семантика может измениться по мере накопления опыта работы с этой функцией.--no-force-with-leaseотменяет все предыдущие--force-with-leaseв командной строке.Общее замечание по безопасности: использование этого параметра без ожидаемого значения, т.е. как
--force-with-leaseили--force-with-lease=<имя-ссылки>, очень плохо взаимодействует с любым процессом, который неявно выполняетgitfetchдля внешнего репозитория, в который выполняется отправка, в фоновом режиме, например,gitfetchoriginдля вашего репозитория в задании cron.Защита, которую он предлагает по сравнению с
--force, заключается в обеспечении того, что последующие изменения, на которых ваша работа не основывалась, не будут затёрты, но это легко нарушается, если какой-либо фоновый процесс обновляет ссылки в фоне. У нас нет ничего, кроме информации об отслеживаемых внешних ветках, чтобы использовать в качестве эвристики для ссылок, которые вы, как ожидается, видели и готовы затёрть.Если ваш редактор или какая-то другая система выполняет
gitfetchв фоне за вас, способ смягчить это — просто настроить другой внешний репозиторий:git remote add origin-push $(git config remote.origin.url) git fetch origin-push
Теперь, когда фоновый процесс выполняет
gitfetchorigin, ссылки вorigin-pushне будут обновляться, и, следовательно, такие команды, как:git push --force-with-lease origin-push
завершатся сбоем, если только вы вручную не выполните
gitfetchorigin-push. Этот метод, конечно, полностью нарушается чем-то, что выполняетgitfetch--all; в этом случае вам нужно либо отключить это, либо сделать что-то более утомительное, например:git fetch # обновить 'master' из внешнего репозитория git tag base master # отметить нашу базовую точку git rebase -i master # переписать некоторые коммиты git push --force-with-lease=master:base master:master
Т.е. создать метку
baseдля версий вышестоящего (upstream) кода, которые вы видели и готовы перезаписать, затем переписать историю и, наконец, принудительно отправить изменения вmaster, если внешняя версия всё ещё находится наbase, независимо от того, до чего была обновлена ваша локальнаяremotes/origin/masterв фоне.Кроме того, указание
--force-if-includesв качестве дополнительного параметра вместе с--force-with-lease[=<имя-ссылки>] (т.е. без указания, на какой именно коммит должна указывать ссылка на внешней стороне или какие именно ссылки на внешней стороне защищаются) во время «отправки» проверит, интегрированы ли локально обновления из отслеживаемых внешних ссылок, которые могли быть неявно обновлены в фоне, прежде чем разрешить принудительное обновление. -
-f -
--force -
Обычно
gitpushотказывается обновлять ветку, которая не является предком отправляемого коммита.Этот флаг отключает эту проверку, другие проверки безопасности в разделе ПРАВИЛА ОТПРАВКИ ниже и проверки в
--force-with-lease. Это может привести к потере коммитов во внешнем репозитории; используйте с осторожностью.Обратите внимание, что
--forceприменяется ко всем отправляемым ссылкам, поэтому использование его сpush.default, установленным вmatching, или с несколькими целевыми репозиториями отправки, настроенными с помощьюremote.<имя>.push, может перезаписать ссылки, отличные от текущей ветки (включая локальные ссылки, которые строго отстают от своих внешних аналогов). Чтобы принудительно отправить изменения только в одну ветку, используйте+перед спецификатором ссылки (например,gitpushorigin+masterдля принудительной отправки в веткуmaster). Подробности смотрите в разделе <спецификатор-ссылки>... выше. -
--force-if-includes -
--no-force-if-includes -
Принудительно выполнить обновление, только если верхушка (tip) отслеживаемой внешней ссылки была интегрирована локально.
Этот параметр включает проверку, которая определяет, достижима ли верхушка (tip) отслеживаемой внешней ссылки из одной из записей «журнала ссылок» (reflog) локальной ветки, основанной на ней, для перезаписи. Проверка гарантирует, что любые обновления из внешнего репозитория были включены локально, отклоняя принудительное обновление, если это не так.
Если параметр передан без указания
--force-with-leaseили указан вместе с--force-with-lease=<имя-ссылки>:<ожидаемое>, это «пустая операция» (no-op).Указание
--no-force-if-includesотключает это поведение. -
--repo=<repository> -
Этот параметр эквивалентен аргументу <репозиторий>. Если указаны оба, аргумент командной строки имеет приоритет.
-
-u -
--set-upstream -
Для каждой ветки, которая актуальна или успешно отправлена, добавить вышестоящую (upstream) ссылку (отслеживание), используемую git-pull[1] без аргументов и другими командами. Для получения дополнительной информации смотрите
branch.<имя>.mergeв git-config[1]. -
--thin -
--no-thin -
Эти параметры передаются в git-send-pack[1]. «Тонкая» (thin) передача значительно уменьшает объем отправляемых данных, когда у отправителя и получателя много общих объектов. Значение по умолчанию —
--thin. -
-q -
--quiet -
Подавлять весь вывод, включая список обновлённых ссылок, если не произошла ошибка. Ход выполнения не сообщается в стандартный поток ошибок.
-
-v -
--verbose -
Работать подробно (verbose).
-
--progress -
Прогресс по умолчанию направляется в стандартный поток ошибок, если этот поток подключён к терминалу, если не указан параметр
-q. Этот флаг принудительно включает отображение прогресса, даже если стандартный поток ошибок не направлен на терминал. -
--no-recurse-submodules -
--recurse-submodules=(check|on-demand|only|no) -
Может использоваться, чтобы убедиться, что все коммиты подмодулей, используемые в отправляемых редакциях, доступны в отслеживаемой внешней ветке. Возможные значения:
-
check -
Git проверит, что все коммиты подмодулей, которые изменились в отправляемых редакциях, доступны хотя бы в одном внешнем репозитории подмодуля. Если каких-либо коммитов не хватает, отправка будет прервана и завершится с ненулевым статусом.
-
on-demand -
все подмодули, которые изменились в отправляемых редакциях, будут отправлены. Если
on-demandне смог отправить все необходимые редакции, операция также будет прервана и завершится с ненулевым статусом. -
only -
все подмодули будут отправлены, в то время как суперпроект останется неотправленным.
-
no -
переопределить переменную конфигурации
push.recurseSubmodules, когда рекурсия в подмодулях не требуется. Аналогично использованию--no-recurse-submodules.
При использовании
on-demandилиonly, если у подмодуля есть конфигурацияpush.recurseSubmodules=(on-demand|only) илиsubmodule.recurse, произойдет дальнейшая рекурсия. В этом случаеonlyрассматривается какon-demand. -
-
--verify -
--no-verify -
Переключить перехватчик (hook) pre-push (см. githooks[5]). Значение по умолчанию —
--verify, дающее перехватчику шанс предотвратить отправку. С--no-verifyперехватчик полностью игнорируется. -
-4 -
--ipv4 -
Использовать только IPv4 адреса, игнорируя IPv6 адреса.
-
-6 -
--ipv6 -
Использовать только IPv6 адреса, игнорируя адреса IPv4.
|
Warning
|
Missing See original version for this content. |
ВЫВОД
Вывод «git push» зависит от используемого транспортного метода; в этом разделе описывается вывод при отправке по протоколу Git (локально или через ssh).
Статус отправки выводится в табличной форме, где каждая строка представляет статус одной ссылки. Каждая строка имеет вид:
<флаг> <сводка> <откуда> -> <куда> (<причина>)
Если используется --porcelain, то каждая строка вывода имеет следующий вид:
<флаг> \t <откуда>:<куда> \t <сводка> (<причина>)
Статус актуальных ссылок показывается, только если используется параметр --porcelain или --verbose.
- <флаг>
-
Один символ, указывающий статус ссылки:
- (пространство)
-
для успешно отправленной перемотки вперёд (fast-forward);
-
+ -
для успешного принудительного обновления;
-
- -
для успешно удалённой ссылки;
-
* -
для успешно отправленной новой ссылки;
-
! -
для ссылки, которая была отклонена или не отправлена; и
-
= -
для ссылки, которая была актуальна и не требовала отправки.
- <summary>
-
Для успешно отправленной ссылки в сводке показываются старое и новое значения ссылки в форме, подходящей для использования в качестве аргумента
gitlog(в большинстве случаев это <старое>..<новое>, а для принудительных обновлений, не являющихся перемоткой вперёд — <старое>...<новое>).Для неудачного обновления предоставляются дополнительные сведения:
- отклонено
-
Git вообще не пытался отправить ссылку, обычно потому, что это не перемотка вперёд (fast-forward) и вы не применили принудительное обновление.
- отклонено внешним репозиторием
-
Внешняя сторона отказалась от обновления. Обычно это вызвано перехватчиком (hook) на внешней стороне или тем, что во внешнем репозитории действует один из следующих параметров безопасности:
receive.denyCurrentBranch(для отправок в переключённую ветку),receive.denyNonFastForwards(для принудительных обновлений, не являющихся перемоткой вперёд),receive.denyDeletesилиreceive.denyDeleteCurrent. Смотрите git-config[1]. - сбой во внешнем репозитории
-
Внешняя сторона не сообщила об успешном обновлении ссылки, возможно, из-за временной ошибки на внешней стороне, разрыва сетевого соединения или другой преходящей ошибки.
- из
-
Имя отправляемой локальной ссылки без префикса
refs/<тип>/. В случае удаления имя локальной ссылки опускается. - в
-
Имя обновляемой внешней ссылки без префикса
refs/<тип>/. - причина
-
Пояснение, понятное человеку. В случае успешно отправленных ссылок пояснение не требуется. Для неудачной ссылки описывается причина сбоя.
ПРАВИЛА ОТПРАВКИ
В целях безопасности команда git push разрешает только определенные виды обновлений, чтобы предотвратить случайную потерю данных во внешнем репозитории.
Поскольку ветки и метки предназначены для разного использования, правила безопасности для отправки в ветку отличаются от правил для отправки в метку. В следующих правилах под «обновлением» понимаются любые изменения, кроме удалений и созданий. Удаления и создания всегда разрешены, если только они не запрещены конфигурацией или перехватчиками (hooks).
-
Если целевой объект отправки — ветка (
refs/heads/*): разрешены только обновления-перемотки вперёд (fast-forward), что означает, что целевой объект должен быть предком исходного коммита. Исходный объект должен быть коммитом. -
Если целевой объект отправки — метка (
refs/tags/*): все обновления будут отклонены. Исходным объектом может быть любой объект. -
Если целевой объект отправки не является ни веткой, ни меткой:
-
Если исходный объект — дерево или blob-объект, любые обновления будут отклонены
-
Если исходный объект — метка или коммит, разрешено любое обновление-перемотка вперёд, даже в тех случаях, когда перематывается вперёд не коммит, а объект-метка, который указывает на новый коммит, являющийся перемоткой вперёд относительно коммита, на который указывала заменяемая последняя метка (или коммит). Замена метки на совершенно другую метку также разрешена, если она указывает на тот же коммит, а также отправка «очищенной» (peeled) метки, т.е. отправка коммита, на который указывает существующий объект-метка, или нового объекта-метки, на который указывает существующий коммит.
-
Вы можете отменить эти правила, передав --force или добавив необязательный префикс + к спецификатору ссылки. Единственное исключение заключается в том, что никакое принуждение не заставит ветку принять объект, не являющийся коммитом, и принуждение не заставит внешний репозиторий принять отправку, которую он настроен отклонять.
Перехватчики (hooks) и конфигурация также могут отменять или изменять эти правила, см., например, receive.denyNonFastForwards и receive.denyDeletes в git-config[1] и pre-receive и update в githooks[5].
ПРИМЕЧАНИЕ О ПЕРЕМОТКЕ ВПЕРЁД (FAST-FORWARD)
Когда обновление изменяет ветку (или, в более общем смысле, ссылку), указывавшую на коммит A, так что она начинает указывать на другой коммит B, это называется обновлением-перемоткой вперёд (fast-forward) тогда и только тогда, когда B является потомком A.
При обновлении-перемотке вперёд с A на B набор коммитов, на которых основывался исходный коммит A, является подмножеством коммитов, на которых основывается новый коммит B. Следовательно, история не теряется.
В отличие от этого, обновление, не являющееся перемоткой вперёд, приведёт к потере истории. Например, предположим, что вы и кто-то другой начали с одного и того же коммита X, и вы построили историю, ведущую к коммиту B, в то время как другой человек построил историю, ведущую к коммиту A. История выглядит так:
B
/
---X---A
Предположим также, что другой человек уже отправил изменения, ведущие к A, обратно в исходный репозиторий, из которого вы оба получили исходный коммит X.
Отправка, выполненная другим человеком, обновила ветку, которая ранее указывала на коммит X, чтобы она указывала на коммит A. Это перемотка вперёд.
Но если вы попытаетесь отправить изменения, вы попытаетесь обновить ветку (которая теперь указывает на A) коммитом B. Это не перемотка вперёд. Если вы это сделаете, изменения, внесённые коммитом A, будут потеряны, потому что все теперь начнут основываться на B.
По умолчанию команда не разрешает обновление, не являющееся перемоткой вперёд, чтобы предотвратить такую потерю истории.
Если вы не хотите потерять свою работу (историю от X до B) или работу другого человека (историю от X до A), вам нужно сначала получить (fetch) историю из репозитория, создать историю, содержащую изменения, сделанные обеими сторонами, и отправить результат обратно.
Вы можете выполнить «git pull», разрешить потенциальные конфликты и выполнить «git push» результата. «git pull» создаст коммит слияния C между коммитами A и B.
B---C
/ /
---X---A
Обновление A полученным коммитом слияния будет перемоткой вперёд, и ваша отправка будет принята.
Кроме того, вы можете переместить (rebase) ваше изменение между X и B на основу A с помощью git pull --rebase и отправить результат обратно. Перемещение создаст новый коммит D, который строит изменение между X и B на основе A.
B D
/ /
---X---A
И снова, обновление A этим коммитом будет перемоткой вперёд, и ваша отправка будет принята.
Существует ещё одна распространённая ситуация, когда вы можете столкнуться с отклонением, не являющимся перемоткой вперёд, при попытке отправить изменения, и это возможно даже при отправке в репозиторий, в который никто больше не отправляет. После того как вы сами отправили коммит A (на первой картинке в этом разделе), вы заменяете его с помощью git commit --amend, создавая коммит B, и пытаетесь отправить его, забыв, что вы уже отправили A. В таком случае, и только если вы уверены, что никто тем временем не получил (fetch) ваш более ранний коммит A (и не начал строить на его основе), вы можете выполнить git push --force, чтобы перезаписать его. Другими словами, git push --force — это метод, предназначенный для случаев, когда вы действительно намерены потерять историю.
ПРИМЕРЫ
-
gitpush -
Работает как
gitpush<внешний-репозиторий>, где <внешний-репозиторий> — это внешний репозиторий текущей ветки (илиorigin, если для текущей ветки не настроен внешний репозиторий). -
gitpushorigin -
Без дополнительной конфигурации отправляет текущую ветку в настроенную вышестоящую (upstream) ветку (переменная конфигурации
branch.<имя>.merge), если она имеет то же имя, что и текущая ветка; в противном случае завершается с ошибкой без отправки.Поведение этой команды по умолчанию, если не указан <спецификатор-ссылки>, можно настроить, установив параметр
pushдля внешнего репозитория или переменную конфигурацииpush.default.Например, чтобы по умолчанию отправлять только текущую ветку в
origin, используйтеgitconfigremote.origin.pushHEAD. Любой допустимый <спецификатор-ссылки> (например, как в примерах ниже) можно настроить как значение по умолчанию дляgitpushorigin. -
gitpushorigin: -
Отправить «совпадающие» ветки в
origin. Смотрите <спецификатор-ссылки> в разделе ПАРАМЕТРЫ выше для описания «совпадающих» веток. -
gitpushoriginmaster -
Находит ссылку, соответствующую
master, в исходном репозитории (скорее всего, это будетrefs/heads/master) и обновляет ею ту же ссылку (например,refs/heads/master) в репозиторииorigin. Еслиmasterне существовала во внешнем репозитории, она будет создана. -
gitpushoriginHEAD -
Удобный способ отправить текущую ветку с тем же именем во внешний репозиторий.
-
gitpushmothershipmaster:satellite/masterdev:satellite/dev -
Использовать исходную ссылку, соответствующую
master(например,refs/heads/master), для обновления ссылки, соответствующейsatellite/master(скорее всего,refs/remotes/satellite/master), в репозиторииmothership; сделать то же самое дляdevиsatellite/dev.Смотрите раздел, описывающий <спецификатор-ссылки>... выше, для обсуждения семантики сопоставления.
Это нужно для эмуляции
gitfetch, выполняемого наmothership, с помощьюgitpush, который выполняется в противоположном направлении, чтобы интегрировать работу, проделанную наsatellite, и часто необходимо, когда соединение можно установить только в одну сторону (т.е. satellite может подключиться по ssh к mothership, но mothership не может инициировать соединение с satellite, потому что последний находится за брандмауэром или на нём не запущен sshd).После выполнения этого
gitpushна машинеsatelliteвы должны подключиться по ssh кmothershipи выполнить тамgitmerge, чтобы завершить эмуляциюgitpull, который был бы выполнен наmothershipдля получения (pull) изменений, сделанных наsatellite. -
gitpushoriginHEAD:master -
Отправить текущую ветку во внешнюю ссылку, соответствующую
master, в репозиторииorigin. Эта форма удобна для отправки текущей ветки без необходимости помнить её локальное имя. -
gitpushoriginmaster:refs/heads/experimental -
Создать ветку
experimentalв репозиторииorigin, скопировав текущую веткуmaster. Эта форма нужна только для создания новой ветки или метки во внешнем репозитории, когда локальное имя и внешнее имя различаются; в противном случае будет достаточно самого имени ссылки. -
gitpushorigin:experimental -
Находит ссылку, соответствующую
experimental, в репозиторииorigin(например,refs/heads/experimental) и удаляет её. -
gitpushorigin+dev:master -
Обновить ветку master в репозитории origin с помощью ветки dev, разрешая обновления, не являющиеся перемоткой вперёд. Это может привести к тому, что в репозитории origin останутся болтающиеся (dangling) коммиты без ссылок. Рассмотрим следующую ситуацию, когда перемотка вперёд невозможна:
o---o---o---A---B origin/master \ X---Y---Z dev
Вышеуказанная команда изменит репозиторий origin на
A---B (ветка без имени) / o---o---o---X---Y---Z master
Коммиты A и B больше не будут принадлежать ветке с символическим именем и, следовательно, станут недостижимыми. Таким образом, эти коммиты будут удалены командой
gitgcв репозитории origin.
БЕЗОПАСНОСТЬ
Протоколы получения (fetch) и отправки (push) не предназначены для предотвращения кражи одной стороной данных из другого репозитория, которые не предназначались для общего доступа. Если у вас есть частные данные, которые необходимо защитить от злонамеренного участника, лучший вариант — хранить их в другом репозитории. Это относится как к клиентам, так и к серверам. В частности, пространства имён на сервере неэффективны для контроля доступа на чтение; вы должны предоставлять доступ на чтение к пространству имён только тем клиентам, которым вы доверили бы доступ на чтение ко всему репозиторию.
Известные векторы атак следующие:
-
Жертва отправляет строки «have», рекламируя идентификаторы объектов, которые у неё есть и которые явно не предназначены для общего доступа, но могут использоваться для оптимизации передачи, если они также есть у участника. Злоумышленник выбирает идентификатор объекта X для кражи и отправляет ссылку на X, но не обязан отправлять содержимое X, потому что оно уже есть у жертвы. Теперь жертва считает, что у злоумышленника есть X, и позже отправляет содержимое X обратно злоумышленнику. (Эту атаку проще всего выполнить клиенту на сервере, создав ссылку на X в пространстве имён, к которому у клиента есть доступ, а затем получив её. Наиболее вероятный способ для сервера выполнить её на клиенте — «слить» X в публичную ветку и надеяться, что пользователь выполнит дополнительную работу в этой ветке и отправит её обратно на сервер, не заметив слияния.)
-
Как и в №1, злоумышленник выбирает идентификатор объекта X для кражи. Жертва отправляет объект Y, который у злоумышленника уже есть, а злоумышленник ложно заявляет, что у него есть X, а Y нет, поэтому жертва отправляет Y как дельту относительно X. Дельта раскрывает злоумышленнику области X, похожие на Y.
КОНФИГУРАЦИЯ
Дальнейшее содержание этого раздела, повторяет то, что может быть найдено в git-config[1]:
-
push.autoSetupRemote -
Если установлено в
true, подразумевать--set-upstreamпри отправке по умолчанию, когда для текущей ветки не существует вышестоящего (upstream) отслеживания; этот параметр действует с опциямиpush.defaultsimple,upstreamиcurrent. Это полезно, если по умолчанию вы хотите, чтобы новые ветки отправлялись во внешний репозиторий по умолчанию (как поведениеpush.default=current) и вы также хотите, чтобы было установлено вышестоящее отслеживание. Наиболее вероятные рабочие процессы, которые выиграют от этого параметра, — этоsimpleцентрализованные рабочие процессы, где ожидается, что все ветки будут иметь одинаковые имена во внешнем репозитории. -
push.default -
Определяет действие, которое должно выполняться
gitpush, если не указан спецификатор ссылки (будь то из командной строки, конфигурации или другого места). Разные значения хорошо подходят для конкретных рабочих процессов; например, в чисто централизованном рабочем процессе (т.е. источник получения равен цели отправки),upstream, вероятно, то, что вам нужно. Возможные значения:-
nothing -
не отправлять ничего (завершиться с ошибкой), если не указан спецификатор ссылки. Это в первую очередь предназначено для людей, которые хотят избежать ошибок, всегда действуя явно.
-
current -
отправить текущую ветку для обновления ветки с тем же именем на принимающей стороне. Работает как в централизованных, так и в нецентрализованных рабочих процессах.
-
upstream -
отправить текущую ветку обратно в ветку, чьи изменения обычно интегрируются в текущую ветку (которая называется
@{upstream}). Этот режим имеет смысл только в том случае, если вы отправляете в тот же репозиторий, из которого обычно извлекаете (pull) (т.е. централизованный рабочий процесс). -
tracking -
это устаревший синоним для
upstream. -
simple -
отправить текущую ветку с тем же именем во внешний репозиторий.
Если вы работаете по централизованному рабочему процессу (отправляете в тот же репозиторий, из которого извлекаете, обычно это
origin), то вам нужно настроить вышестоящую ветку с тем же именем.Этот режим используется по умолчанию, начиная с Git 2.0, и является самым безопасным вариантом, подходящим для новичков.
-
matching -
отправить все ветки, имеющие одинаковые имена на обоих концах. Это заставляет репозиторий, в который вы отправляете, запомнить набор веток, которые будут отправлены (например, если вы всегда отправляете туда
maintиmasterи никакие другие ветки, репозиторий, в который вы отправляете, будет иметь эти две ветки, и ваши локальныеmaintиmasterбудут туда отправлены).Чтобы эффективно использовать этот режим, вы должны убедиться, что все ветки, которые вы собираетесь отправить, готовы к отправке перед запуском
gitpush, поскольку весь смысл этого режима в том, чтобы позволить вам отправить все ветки за один раз. Если вы обычно заканчиваете работу только над одной веткой и отправляете результат, в то время как другие ветки не закончены, этот режим не для вас. Кроме того, этот режим не подходит для отправки в общий центральный репозиторий, так как другие люди могут добавлять там новые ветки или обновлять верхушки существующих веток вне вашего контроля.Раньше это было значение по умолчанию, но не начиная с Git 2.0 (
simple— новое значение по умолчанию).
-
-
push.followTags -
Если установлено в true, включить опцию
--follow-tagsпо умолчанию. Вы можете переопределить эту конфигурацию во время отправки, указав--no-follow-tags. -
push.gpgSign -
Может быть установлен в логическое значение или в строку
if-asked. Значение true заставляет все отправки подписываться с помощью GPG, как если бы--signedбыл передан в git-push[1]. Строкаif-askedзаставляет отправки подписываться, если сервер это поддерживает, как если бы--signed=if-askedбыл передан вgitpush. Значение false может переопределить значение из конфигурационного файла с более низким приоритетом. Явный флаг командной строки всегда переопределяет этот параметр конфигурации. -
push.pushOption -
Если аргумент
--push-option=<параметр> не задан в командной строке,gitpushведёт себя так, как если бы каждый <параметр> этой переменной был задан как--push-option=<параметр>.Это многозначная переменная, и пустое значение может быть использовано в конфигурационном файле с более высоким приоритетом (например,
.git/configв репозитории) для очистки значений, унаследованных из конфигурационных файлов с более низким приоритетом (например,$HOME/.gitconfig).Пример: /etc/gitconfig push.pushoption = a push.pushoption = b ~/.gitconfig push.pushoption = c repo/.git/config push.pushoption = push.pushoption = b В результате останется только b (a и c будут очищены).
-
push.recurseSubmodules -
Может быть
check,on-demand,onlyилиno, с тем же поведением, что и уpush--recurse-submodules. Если не установлено, по умолчанию используетсяno, если только не установленsubmodule.recurse(в этом случае значениеtrueозначаетon-demand). -
push.useForceIfIncludes -
Если установлено в
true, это эквивалентно указанию--force-if-includesв качестве параметра для git-push[1] в командной строке. Добавление--no-force-if-includesво время отправки переопределяет этот параметр конфигурации. -
push.negotiate -
Если установлено в
true, пытаться уменьшить размер отправляемого pack-файла с помощью раундов согласования, в которых клиент и сервер пытаются найти общие коммиты. Еслиfalse, Git будет полагаться исключительно на объявление ссылок сервера для поиска общих коммитов. -
push.useBitmaps -
Если установлено в
false, отключить использование битовых карт дляgitpush, даже еслиpack.useBitmapsимеет значениеtrue, не препятствуя использованию битовых карт другими операциями git. По умолчаниюtrue.
GIT
Является частью пакета git[1]