git push: как отправить изменения в удалённый репозиторий
git push отправляет локальные коммиты текущей ветки в удалённый репозиторий и сдвигает там указатель ветки. Первый раз ветку публикуют командой git push -u origin имя-ветки, дальше достаточно git push. Если на сервере есть чужие коммиты, сначала нужно забрать их через git pull, а не делать force push.
Что делает git push
Команда git push берёт коммиты из вашей локальной ветки, которых ещё нет на сервере, передаёт их в удалённый репозиторий (обычно он называется origin) и передвигает там указатель ветки на ваш последний коммит. Сами файлы рабочей папки и незакоммиченные изменения никуда не уходят: отправляется только история, то есть коммиты.
Важно понимать, что push — это не «синхронизация». Он работает в одну сторону: из локального репозитория в удалённый. Чтобы получить чужие изменения, нужны git fetch или git pull. Если путать эти направления, появляются почти все проблемы, с которыми новички приходят к наставнику.
Ещё одно правило Git: по умолчанию push разрешён только как «перемотка вперёд» (fast-forward). Сервер примет ваши коммиты, если они продолжают ту историю, которая уже есть на сервере. Если кто-то успел отправить свои коммиты раньше, ваш push будет отклонён — и это защита, а не ошибка.
Синтаксис команды
git push [<remote>] [<локальная-ветка>[:<удалённая-ветка>]]
Если вызвать git push без аргументов, Git возьмёт текущую ветку и отправит её в ветку, указанную как upstream (отслеживаемую). Явная форма полезна, когда upstream ещё не настроен или вы хотите отправить ветку под другим именем:
git push origin main # отправить локальную main в origin/main
git push origin feature/login # отправить ветку feature/login
git push origin fix:hotfix-123 # локальную fix отправить как hotfix-123 на сервере
git push origin HEAD # отправить текущую ветку под тем же именем
Как отправить изменения в первый раз
Типичный путь от нового проекта до кода на GitHub или GitLab выглядит так. Сначала вы создаёте пустой репозиторий на сервере, затем связываете с ним локальный и отправляете ветку.
git init
git add .
git commit -m "Первый коммит"
git branch -M main
git remote add origin git@github.com:user/project.git
git push -u origin main
Флаг -u (полная форма --set-upstream) связывает локальную ветку main с удалённой origin/main. После этого в ветке можно писать просто git push и git pull, а git status начнёт показывать, на сколько коммитов вы впереди или позади сервера.
Проверить, куда смотрит remote, можно командой git remote -v. Если адрес указан неверно, исправьте его через git remote set-url origin <новый-адрес>, а не удаляя и создавая репозиторий заново.
Как отправить новую ветку
Вы создали ветку для задачи, сделали коммиты и пишете git push. В ответ Git сообщает:
fatal: The current branch feature/login has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin feature/login
Это не ошибка, а подсказка: у ветки ещё нет пары на сервере. Выполните предложенную команду или короткую форму git push -u origin feature/login. Чтобы Git делал это автоматически для всех новых веток, включите настройку (доступна с Git 2.37):
git config --global push.autoSetupRemote true
Почему git push отклонён: rejected, non-fast-forward
Самая частая ситуация в командной работе:
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'github.com:user/project.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally.
Коллега отправил свои коммиты раньше вас. Ваша история и история на сервере разошлись, и если бы Git принял ваш push, коммиты коллеги потерялись бы. Правильное решение — сначала забрать изменения и встроить в них свои:
git pull --rebase # забрать чужие коммиты и переставить свои поверх
# при конфликтах: исправить файлы, git add, git rebase --continue
git push
Вместо --rebase можно сделать обычный git pull — тогда появится коммит слияния. Оба варианта корректны; в большинстве команд для своих локальных коммитов предпочитают rebase, чтобы история была линейной. Главное — не «решать» отказ через --force.
git push --force и --force-with-lease
Принудительная отправка нужна, когда вы осознанно переписали историю своей ветки: сделали git commit --amend, git rebase или объединили коммиты перед ревью. Обычный push такую ветку не примет, потому что старые коммиты на сервере больше не являются предками новых.
git push --force-with-lease
--force-with-lease перезапишет ветку на сервере, только если она находится там же, где её последний раз видел ваш локальный Git (по ссылке origin/<ветка>). Если коллега успел что-то запушить, команда откажет, и вы не сотрёте его работу. Обычный --force (-f) такой проверки не делает и перезаписывает всё молча.
Есть нюанс: если перед этим выполнить git fetch, ссылка origin/<ветка> обновится, и защита перестанет работать — Git решит, что вы «видели» чужие коммиты. Поэтому не делайте fetch прямо перед force push, не посмотрев, что пришло.
| Команда | Что делает | Когда использовать |
|---|---|---|
git push | Только fast-forward | Всегда по умолчанию |
git push --force-with-lease | Перезапись с проверкой | Своя ветка после rebase или amend |
git push --force | Перезапись без проверок | Почти никогда; никогда в общие ветки |
В общие ветки (main, develop) принудительно пушить нельзя: у всех, кто уже забрал старую историю, она разойдётся с серверной. Обычно такие ветки ещё и защищены настройками репозитория, и сервер вернёт protected branch hook declined.
Как отправить теги
Обычный git push теги не отправляет. Их нужно передать явно:
git tag -a v1.2.0 -m "Релиз 1.2.0"
git push origin v1.2.0 # один тег
git push --tags # все локальные теги
git push --follow-tags # коммиты и аннотированные теги, которые на них указывают
--follow-tags удобнее --tags: он не отправит случайные локальные лёгкие теги, только аннотированные и только достижимые из отправляемых коммитов.
Как удалить ветку на сервере
Удаление тоже делается через push:
git push origin --delete feature/login
# старый синтаксис, делает то же самое:
git push origin :feature/login
Локальная ветка при этом остаётся, удалить её можно командой git branch -d feature/login. А у коллег ещё будет висеть ссылка origin/feature/login, пока они не выполнят git fetch --prune.
Полезные флаги git push
| Флаг | Назначение |
|---|---|
-u, --set-upstream | Запомнить удалённую ветку как upstream |
-n, --dry-run | Показать, что будет отправлено, ничего не отправляя |
--all | Отправить все локальные ветки |
--tags / --follow-tags | Отправить теги |
-d, --delete | Удалить ветку или тег на сервере |
--force-with-lease | Безопасная перезапись истории |
-v, --verbose | Подробный вывод |
--no-verify | Пропустить хук pre-push (использовать осознанно) |
Частые ошибки при git push и их решение
Permission denied (publickey)
Сервер не принял ваш SSH-ключ. Проверьте, что ключ существует (ls ~/.ssh), что публичная часть добавлена в аккаунт и что соединение работает: ssh -T git@github.com. Если remote указан по HTTPS, Git будет спрашивать логин и токен, а не ключ — посмотрите git remote -v.
Authentication failed по HTTPS
GitHub и многие другие сервисы давно не принимают пароль аккаунта при работе через HTTPS. Нужен персональный токен доступа или переход на SSH. Сохранить токен поможет credential helper: git config --global credential.helper store (хранит в открытом виде) или менеджер учётных данных вашей ОС.
src refspec main does not match any
Ветки с таким именем у вас нет. Чаще всего в пустом репозитории ещё не сделан ни один коммит или ветка называется master. Проверьте git branch и сделайте коммит либо переименуйте ветку: git branch -M main.
Everything up-to-date, хотя изменения есть
Вы забыли закоммитить. git push отправляет коммиты, а не файлы. Выполните git status, затем git add и git commit. Второй вариант — вы находитесь не в той ветке, которую ожидаете увидеть на сервере.
Файл слишком большой
Сервисы ограничивают размер файла (на GitHub — 100 МБ). Если такой файл уже попал в историю, недостаточно удалить его новым коммитом: нужно переписать историю или убрать его из ещё не отправленных коммитов (git reset --soft, затем коммит заново). Для больших бинарных файлов используют Git LFS.
Рабочий цикл с git push
git switch -c feature/x— ветка под задачу.- Коммиты небольшими логическими шагами.
git fetchиgit rebase origin/main— подтянуть свежую основную ветку.git push -u origin feature/x— опубликовать ветку.- Открыть pull request, после ревью — дополнительные коммиты и обычный
git push. - Если пришлось переписать историю —
git push --force-with-lease.
Перед отправкой полезно посмотреть, что именно уйдёт на сервер: git log origin/main..HEAD --oneline покажет коммиты, которых на сервере ещё нет.
Что настроить один раз
Несколько глобальных настроек избавляют от большинства сюрпризов при отправке. push.default определяет, что отправляет git push без аргументов. Значение по умолчанию в современных версиях — simple: отправляется только текущая ветка и только в одноимённую upstream-ветку. Менять его обычно не нужно, но стоит проверить, что в старом конфиге не осталось matching, который отправляет все совпадающие по имени ветки сразу.
git config --global push.default simple
git config --global push.autoSetupRemote true
git config --global push.followTags true
git config --global pull.rebase true
push.followTags делает --follow-tags поведением по умолчанию, а pull.rebase избавляет от лишних коммитов слияния, когда push отклонён и нужно сначала забрать чужие изменения.
Хук pre-push
Файл .git/hooks/pre-push выполняется перед отправкой. Если он завершится с ненулевым кодом, push не произойдёт. Команды часто запускают в нём тесты или линтер, чтобы сломанный код не уходил на сервер. Обходить хук через --no-verify стоит только тогда, когда вы точно понимаете, почему он падает.
Итог
git push публикует ваши коммиты в удалённом репозитории и работает только в одну сторону. Первую отправку ветки делайте с -u, при отказе сначала забирайте чужие изменения через pull, а переписанную историю своей ветки отправляйте только через --force-with-lease. Работа с удалёнными репозиториями, push, pull и SSH-ключами разобрана на практике в курсе по Git.
Частые вопросы
Отправляет ли git push незакоммиченные изменения?
Нет. Push передаёт только коммиты; изменения в рабочей папке и в индексе остаются локально, пока вы их не закоммитите.
Как отменить git push?
В своей ветке можно откатить коммит локально (git reset) и отправить через git push --force-with-lease. В общей ветке безопаснее создать обратный коммит через git revert и сделать обычный push.
Можно ли отправить только один коммит?
Да, указав его хеш: git push origin abc1234:main отправит всю историю до этого коммита включительно, но не более поздние коммиты. Отправить коммит без его предков нельзя.
Чем git push отличается от git push origin main?
Без аргументов Git использует настроенный upstream текущей ветки, а явная форма указывает remote и ветку напрямую и работает даже без настроенного upstream.
Как запушить в два репозитория сразу?
Добавьте второй remote и отправляйте в оба по имени, либо добавьте origin два адреса отправки командой git remote set-url --add --push origin адрес (выполнить для обоих адресов, включая исходный, иначе push пойдёт только во второй).
Эта тема подробно разобрана с практикой в курсе «Git с нуля до уверенного разработчика».
Перейти к курсу