Синхронизация форка с upstream — три безопасных способа
fetch, merge, push: полная рутина, вариант с rebase и force-with-lease, четыре подозреваемых «форка, который не синхронизируется» и кнопка GitHub как страховка.
■ space · прозаическая полоса
git fetch upstream && git merge upstream/main && git push origin main — вот и вся синхронизация.
Любите линейную историю? Замените merge на git rebase upstream/main + push --force-with-lease.
Форк «не синхронизируется»? Missing upstream remote — причина №1 — подключите один раз, ниже.
КОНВЕЙЕР
Синхронизация всегда едет в одну сторону — upstream → ваш локальный main → origin. Ничто из форка не течёт назад в upstream; для этого существуют pull request'ы.
origin = ваш форк · upstream = проект, который вы форкнули — частая ошибка: направить оба remote на свой форк; тогда «синхронизация» тихо ничего не делает, потому что вы сделали fetch из копии, такой же черствой, как ваша собственная
ШАГ 1 — ПОДКЛЮЧИТЬ REMOTE (ОДИН РАЗ НА КЛОН)
# внутри вашего локального клона форка
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
git remote -v # подтвердить: origin -> ваш форк, upstream -> оригинал
Найдите правильный URL на странице оригинального репозитория, под зелёной кнопкой Code. Подключение постоянное — всё, что ниже, это то, что вы наберёте в следующий раз.
ШАГ 2 — FETCH, MERGE, PUSH
git checkout main
git fetch upstream
git merge upstream/main
git push origin main
проверка: git rev-list --count main..upstream/main → 12 до merge → 0 после
Fast-forward — нормальный исход: ваш main не имел ничего нового, он просто съезжает вперёд на upstream/main, и merge-коммит не создаётся. Чтобы увидеть отставание до слияния: git rev-list --count main..upstream/main после fetch. Вот и вся рутина; шаг 3 — помнить, что она существует: git fetch upstream && git merge upstream/main && git push origin main.
MERGE ИЛИ REBASE?
Оба приводят один и тот же код в ваш форк; различается история, которую они оставляют. Выберите одну политику на репозиторий и держитесь её:
| Метод | Команда | Итог в истории | Лучше всего для |
|---|---|---|---|
| Merge | git merge upstream/main | Лишний merge-коммит на разошедшихся ветках | Фичевые ветки с открытыми PR — ничего не переписывает |
| Rebase | git rebase upstream/main | Ваши коммиты переиграны сверху, линейная история | Keeping your fork's форка чистым; разошедшиеся форки, которые хотите сбросить clean; diverged forks you want to reset |
| UI GitHub | Кнопка Sync fork / merge PR | Same as merge | Быстро догнать без открытого клона |
# вариант с rebase, линейная история:
git fetch upstream
git rebase upstream/main
git push --force-with-lease origin main
Force push обязателен, потому что rebase переписывает ID коммитов — удалённая ветка форка больше не происходит от локальной. Всегда предпочитайте --force-with-lease over --force : он отказывается перезаписывать remote, если кто-то (или другая ваша машина) успел запушить, что делает опасную команду безопасной по умолчанию. И золотое правило: never rebase a branch that has an open pull request unless you know what you are doing — rebasing changes commit IDs, which can detach an open PR from its commits. Sync main синхронизируйте merge'ем, PR-ветки держите вне этого.
«МОЙ ФОРК НЕ СИНХРОНИЗИРУЕТСЯ» — ЧЕТЫРЕ ОБЫЧНЫХ ПОДОЗРЕВАЕМЫХ
- Нет remote'а
upstream: —git remote -vshows onlyorigin. Симптом:git fetch upstreamfails with'upstream' does not appear to be a git repository. Fix: step 1. - Сделали fetch, но не merge — fetch обновляет
upstream/mainлокально, но не трогает ни одну рабочую ветку. Симптом:git logвыглядит старым после успешного fetch. Лечение:git merge upstream/main. - Разошедшаяся история — you committed to your fork's
mainи upstream тоже сдвинулся. Лечение, если должен победить upstream:git reset --hard upstream/main— выбрасывает ваши коммиты, существующие только в локальном main, так что сначала подстрахуйтесь веткой; если плохой reset уже случился,git reflogвсё ещё помнит старый кончик. - Push отклонён как non-fast-forward после rebase — you rebased but pushed normally. Fix:
git push --force-with-lease origin main.
Пятый, редкий случай: репозиторий upstream переименован или удалён, так что даже URL из шага 1 отдаёт 404. GitHub редиректит переименованные репозитории, значит жёсткий сбой обычно означает удаление или приватность — синхронизироваться больше не с чем.
КНОПКА
Да, сайт умеет: на странице вашего форка в выпадающем списке веток появляется кнопка Sync fork button whenever your branch is behind; one click pulls upstream in. Below the fold, the same thing works as a pull request from каждый раз, когда ваша ветка отстаёт; один клик затягивает upstream. Ниже — то же самое работает как pull request из into your fork's main. Ограничения кнопки объясняют, когда возвращаться к CLI: она делает только fast-forward или merge — rebase не умеет, и наотрез отказывается, когда ветки разошлись, предлагая выбросить коммиты или перейти в командную строку. И синхронизирует только ветку по умолчанию. Для всего, что сложнее простого догона, три команды — инструмент.
КАК ЧАСТО?
Перед каждым новым куском работы — честный ответ: ветвьтесь от свежего main, и ни один открываемый PR не начинается с «это основано на версии трёхнедельной давности». Для форков, куда вы активно вносите вклад, ежедневная или посессионная синхронизация main стоит секунд. Для форка, который вы только читаете или деплоите, синхронизируйтесь, когда upstream выпускает что-то нужное — подпишитесь на релизы оригинального репозитория и синхронизируйтесь на релизе. Синхронизация дешева именно потому, что это рутина; форк с отставанием в полгода часто требует хирургии, а не merge — вот как «синхронизируй мой форк» превращается в целый день.
08ШПАРГАЛКА
# настройка один раз
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
# рутинная синхронизация (политика merge)
git fetch upstream && git merge upstream/main && git push origin main
# рутинная синхронизация (политика rebase, линейная история)
git fetch upstream && git rebase upstream/main && git push --force-with-lease origin main
# насколько я отстал?
git fetch upstream && git rev-list --count main..upstream/main
# разошёлся без надежды — сделать main идентичным upstream (разрушительно)
git fetch upstream && git reset --hard upstream/main && git push --force-with-lease origin main
Держите рутинные две строки в мышечной памяти — и разошедшийся форк останется диковинкой, о которой читают, а не проблемой, которую чинят.
конец страницы синхронизации · ничего не скачано · всё локально