Перейти к содержанию

4. Удалённые репозитории и синхронизация

Цель темы: уверенно работать с удалённым репозиторием (remote): добавлять его, настраивать upstream для веток, синхронизировать историю через fetch, push и pull и разрешать типичные ситуации при расхождении истории.


Определения терминов

Remote (удалённый репозиторий)

Remote — именованная ссылка на другой репозиторий (обычно на сервере: GitHub, GitLab, корпоративный сервер). По умолчанию после git clone создаётся remote с именем origin, указывающий на клонированный URL. С ним вы обмениваетесь коммитами через git fetch, git push, git pull.

Remote-tracking ветка

Remote-tracking branch — локальная ссылка на состояние ветки на remote в момент последнего git fetch или git pull. Имена вида origin/main, origin/feature/login. Вы не коммитите в них напрямую; они обновляются только при fetch/pull. Ваша локальная ветка может «отслеживать» такую ветку (см. upstream).

Upstream (восходящая ветка)

Upstream — связь локальной ветки с веткой на remote (чаще всего с remote-tracking веткой, например origin/main). Задав upstream, вы можете вызывать git push и git pull без указания имени remote и ветки; Git знает, куда пушить и откуда подтягивать.

Fetch

Fetch — загрузка новых коммитов и обновление ссылок на ветки с remote (например, origin/main) без слияния их в вашу текущую ветку. Рабочая директория и текущая ветка не меняются. После fetch вы можете вручную сделать merge или rebase.

Pull

Pull — по сути fetch + merge (или fetch + rebase при git pull --rebase). Загружает изменения с remote и вливает их в текущую ветку. Удобно для быстрой синхронизации, но важно понимать, что под капотом делается merge (или rebase).

Push

Push — отправка ваших коммитов в удалённый репозиторий. Обновляет ветку на remote и соответствующие remote-tracking ветки у вас локально (после того как сервер примет push).


Добавление и настройка remote

Посмотреть список remote

git remote -v
# origin  https://github.com/user/repo.git (fetch)
# origin  https://github.com/user/repo.git (push)

Добавить remote

git remote add origin https://github.com/user/repo.git

Имя origin — соглашение по умолчанию; можно использовать другое (например, upstream для оригинального репозитория при работе с форком).

Изменить URL remote

git remote set-url origin https://gitlab.com/team/repo.git

Несколько remote (форк + оригинал)

git remote add upstream https://github.com/original/repo.git
git fetch upstream
git merge upstream/main   # подтянуть изменения из оригинального репозитория

Fetch: обновление ссылок без слияния

Загрузить все изменения с remote и обновить remote-tracking ветки (origin/main, origin/feature/x и т.д.):

git fetch origin
git fetch --all          # все настроенные remote
git fetch -p              # после fetch удалить ссылки на удалённые ветки (prune)

После fetch ваши локальные ветки не меняются; вы решаете, как влить изменения: merge или rebase (см. ниже).

Практика

Перед началом работы полезно выполнить git fetch origin (или git pull), чтобы видеть актуальное состояние remote и избежать лишних конфликтов при push.


Push: отправка коммитов на remote

Первая отправка ветки (с настройкой upstream)

git push -u origin main
# или для feature-ветки:
git push -u origin feature/login

Опция -u (или --set-upstream) запоминает связь текущей ветки с origin/main (или origin/feature/login). Дальше можно вызывать просто git push и git pull без указания remote и имени ветки.

Последующие push (upstream уже задан)

git push

Отправить ветку под другим именем на remote

git push origin local-branch:remote-branch
# пример: локальная feature/foo → на origin как feature/bar
git push origin feature/foo:feature/bar

Удалить ветку на remote

git push origin --delete feature/old

Настройка upstream для существующей ветки

Если ветка уже есть на remote и вы клонировали репозиторий или создали ветку локально и хотите связать её с origin/...:

git branch --set-upstream-to=origin/feature/login feature/login
# или короче (текущая ветка):
git branch -u origin/feature/login

После этого git status может показывать «ahead/behind» относительно remote, а git push и git pull будут использовать этот upstream.


Pull: подтянуть и влить изменения

git pull origin main     # fetch + merge origin/main в текущую ветку
git pull                # если upstream задан — подтянуть оттуда
git pull --rebase       # подтянуть и влить через rebase вместо merge

Внимание

git pull без аргументов использует upstream. Если upstream не задан, Git может выдать ошибку или спросить, откуда тянуть. Задайте upstream через -u при первом push или через git branch --set-upstream-to.


Rejected push: расхождение истории

Если на remote появились новые коммиты, которых у вас нет, push будет отклонён:

! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to '...'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.

Нужно сначала подтянуть изменения с remote и только потом пушить.

Вариант 1: pull (fetch + merge), затем push

git pull origin main   # подтянуть и смержить
# разрешить конфликты при необходимости
git push origin main

Вариант 2: pull --rebase, затем push

git pull --rebase origin main
git push origin main

Ваши локальные коммиты «переедут» поверх актуального origin/main; история останется линейной.

Force push

git push --force перезаписывает ветку на remote. Используйте только в личных или согласованных сценариях (например, после локального rebase своей feature-ветки). Не делайте force push в общие ветки (main, develop) — это ломает историю у всех.


Паттерны использования

Паттерн Описание
Задавать upstream при первом push Всегда использовать git push -u origin <ветка>, чтобы потом вызывать git push и git pull без аргументов.
Перед работой — fetch/pull Регулярно подтягивать изменения с origin, чтобы не накапливать расхождения и конфликты.
Pull с rebase при личной ветке git pull --rebase даёт линейную историю без лишних merge-коммитов.
Проверять статус перед push git status покажет «ahead/behind»; при «behind» сначала pull, потом push.

Антипаттерны

Антипаттерн Почему плохо Что делать
Force push в общие ветки Стирает коммиты на remote, ломает клоны и CI у всей команды. В общих ветках только обычный push после merge/pull.
Игнорировать rejected push Повторный push без подтягивания не сработает; нужен осознанный pull/rebase. Выполнить git pull (или git pull --rebase), разрешить конфликты, затем push.
Не настраивать upstream Приходится каждый раз указывать origin и имя ветки; легко ошибиться. Использовать -u при первом push или git branch --set-upstream-to.
Долго не подтягивать с remote Большое расхождение ведёт к тяжёлым конфликтам при следующем pull/merge. Регулярно делать fetch/pull, особенно перед началом новой задачи.

Примеры из production

CI/CD и remote

Пайплайн клонирует репозиторий (git clone или git fetch), собирает артефакт из указанной ветки или коммита и иногда пушит теги или служебные коммиты. Понимание remote и push помогает настраивать права и триггеры (например, сборка только при push в main или в release/*).

Защищённые ветки

На GitHub/GitLab для main включают защиту: запрет прямого push, обязательный merge через pull request, прохождение CI. В такой модели вы всегда пушите в свою ветку, а в main вливаете через merge request; расхождения с main вы решаете у себя через pull (rebase или merge) из origin/main.

Синхронизация через pull request

Фича разрабатывается в ветке feature/x; вы пушите в origin/feature/x. Перед созданием pull request подтягиваете актуальный main: git fetch origin && git merge origin/main (или rebase). Так MR содержит актуальную разницу и меньше конфликтов при слиянии.


Дополнительные материалы