Программирование и IT
git push
Пока ты не выполнил git push, твои коммиты существуют только на твоём диске. Команда отправляет их в удалённый репозиторий и сдвигает там указатель ветки — поэтому она же чаще всего и отказывает, если кто-то успел отправить своё раньше.
В этой статье
Что уезжает на сервер#
Отправляются коммиты — те, которых на сервере ещё нет, — и новое положение
указателя ветки. Незакоммиченные правки, файлы из рабочего каталога и
содержимое индекса не уезжают никуда: сначала git commit,
потом отправка.
Сервер принимает изменение, только если оно продолжает уже имеющуюся там
историю. Такое продолжение называют перемоткой вперёд, fast-forward. Если
серверная ветка ушла вперёд или твоя история переписана, git остановится и
ничего не тронет — это главная защита от потери чужой работы.
Синтаксис и ключи#
Чаще всего источник называется origin, а ветка совпадает с текущей.
Когда у ветки есть связь с серверной (upstream), хватает короткого
git push.
| Ключ | Зачем |
|---|---|
-u, --set-upstream |
отправить и связать ветку с серверной — нужен один раз |
--force-with-lease |
переписать серверную ветку, но только если на ней нет неизвестных тебе коммитов |
-f, --force |
переписать без всяких условий, чужая работа может исчезнуть |
--tags |
отправить теги, которые обычным push не уходят |
--delete <ветка> |
удалить ветку на сервере |
-n, --dry-run |
показать, что произошло бы, но ничего не менять |
Пример: первая отправка новой ветки#
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 512 bytes | 512.00 KiB/s, done.
Total 5 (delta 2), reused 0 (delta 0)
To https://github.com/example/notes.git
* [new branch] feature/login -> feature/login
branch 'feature/login' set up to track 'origin/feature/login'.
Без -u 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 без аргументов.
Отказ non-fast-forward#
Самая частая картина: пока ты работал, в ветку на сервере попал чужой
коммит.
To https://github.com/example/notes.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'https://github.com/example/notes.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally.
Пометка бывает fetch first, а бывает non-fast-forward — вторая
появляется, когда твоя история разошлась с серверной, например после
--amend или перебазирования. Решение одно и то же: сначала забрать чужое,
потом отправить своё.
Перебазирование перенесёт твои коммиты поверх чужих, и отправка станет
обычной перемоткой. Подробности — в статье про git pull.
Отвечать на такой отказ ключом --force нельзя: он стирает с сервера
именно те коммиты, из-за которых отказ и возник.
Когда переписать всё-таки нужно#
Бывает законно: ты поправил сообщение своего последнего коммита в личной
ветке, которую никто не смотрит. Тогда вместо --force берут его
осторожного родственника:
Ключ сверяет, что серверная ветка стоит там, где ты её видел в последний
раз. Появился чужой коммит — отправка отклоняется с stale info, и ты
разбираешься, а не затираешь. В общей ветке вроде main не стоит
переписывать историю вовсе.
Как отозвать отправленное#
Коммит уже на сервере и его видели другие — безопасный путь один:
Появится новый коммит, отменяющий действие прежнего. История остаётся
непрерывной, ни у кого не ломаются копии.
Ошибочно созданную ветку убирают целиком:
А случайно отправленный тег — командой git push origin --delete v1.4.
Помни, что отправленное на общий сервер может быть уже скачано, и секрет,
попавший в коммит, считается скомпрометированным независимо от того, что ты
сделаешь с историей: пароль или токен нужно менять, а не прятать. Остальные
команды обмена перечислены в шпаргалке.
План по этапам
- Убедиться, что всё закоммиченоgit status: незакоммиченные правки на сервер не уезжают.
- Забрать чужоеgit pull --rebase, чтобы твои коммиты легли поверх серверных.
- Отправить с привязкойПервый раз git push -u origin ветка, дальше просто git push.
- Прочитать ответ сервераСтрока new branch или диапазон хешей — принято; rejected — читать подсказку.
- Исправлять отменой, а не силойgit revert для общих веток, --force-with-lease только для своих.
Начать изучать эту тему у себя
План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.
Проверь себя
1.Первая отправка новой ветки: какая команда и отправит её, и свяжет с серверной?
2.Push отклонён с пометкой non-fast-forward. Что сделать сначала?
3.Чем --force-with-lease лучше обычного --force?
Источники
-
Pro Git, книга на русскомРаздел про работу с удалёнными репозиториямибесплатно
-
Справка git pushКлючи отправки и смысл отказовбесплатно
Было полезно?