Синхронизация форка с upstream в git: 3 безопасных способа
Синхронизация форка с upstream: две команды через pull, rebase для чистой истории и кнопка Sync fork на GitHub — и починка, если форк не синхронизируется.
TL;DR: выполните git fetch upstream && git merge upstream/main && git push origin main — и ваш форк догнал проект. Это весь workflow «синхронизация форка с upstream» в одну строку: подтянуть изменения из проекта, который вы форкнули, и запушить их в свою копию. Любите линейную историю — замените merge на git rebase upstream/main и сделайте force-push. А если remote upstream вы вообще никогда не подключали, начните с шага 1 ниже: именно отсутствующий remote — причина №1, по которой форк «не синхронизируется». Всё остальное — rebase, кнопка GitHub, разошедшиеся ветки — детали поверх этих трёх команд.
Что значит синхронизировать форк с upstream?
Форк — это ваша копия чужого репозитория на GitHub. Оригинал — это upstream; ваша копия — origin. Форки на GitHub сами не обновляются: когда мейнтейнеры смержат pull request, в вашей копии остаётся вчерашний код. Синхронизировать форк — значит подтянуть новые коммиты upstream в свой форк так, чтобы ваша ветка совпадала с текущим состоянием проекта или хотя бы его содержала.
Это важно по двум причинам. Первая — контрибуции: каждый pull request из протухшего форка несёт лишний шум, и мейнтейнеры попросят обновиться перед мержем. Вторая — self-hosting и изучение кода: если вы держите форк в проде или просто читаете код, форк месячной давности — это месяц багфиксов, которых у вас нет.
Как синхронизировать форк с upstream из командной строки?
Три шага: один раз объявить upstream, забрать из него изменения, затем смержить и запушить. Настройка делается один раз навсегда — в следующий раз вы вводите только шаги 2 и 3.
Шаг 1 — добавьте remote upstream (один раз на клон).
# внутри вашего локального клона форка
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
git remote -v # проверка: origin -> ваш форк, upstream -> оригинал
Правильный URL ищите на странице оригинального репозитория — зелёная кнопка Code. Частая ошибка — направить оба remote на свой форк: тогда «синхронизация» молча ничего не делает, потому что вы фетчите из копии, столь же протухшей, как ваша собственная.
Шаг 2 — фетч и мерж ветки upstream.
git checkout main
git fetch upstream
git merge upstream/main
git push origin main
Это стандартный ответ на вопрос «как синхронизировать форк с upstream в консоли». Обычный исход — fast-forward: ваша main ничего нового не имела, она просто сдвигается к upstream/main, и merge-коммит не создаётся.
Шаг 3 — повторяйте по надобности. Запоминать нечего, кроме git fetch upstream && git merge upstream/main && git push origin main. Чтобы перед мержем увидеть, насколько вы отстали, выполните после фетча git rev-list --count main..upstream/main.
Rebase или merge при синхронизации форка?
Оба пути приводят в форк один и тот же код; различается история, которая останется после. Выберите одну политику на репозиторий и держитесь её:
| Метод | Команда | Итог в истории | Лучше всего для |
|---|---|---|---|
| Merge | git merge upstream/main |
Лишний merge-коммит на разошедшихся ветках | Фиче-веток с открытыми PR — ничего не переписывает |
| Rebase | git rebase upstream/main |
Ваши коммиты переиграны поверх — линейная история | Чистой main форка; разошедшихся форков, которые хочется сбросить |
| GitHub UI | Кнопка Sync branch / мерж PR | То же, что merge | Быстрой догонялки без открытого клона |
Вариант синхронизации через rebase:
git fetch upstream
git rebase upstream/main
git push --force-with-lease origin main
Force-push обязателен: rebase переписывает ID коммитов, и ветка на remote больше не потомок вашей локальной. Всегда предпочитайте --force-with-lease, а не --force: она откажется перезаписывать remote, если кто-то (или ваша же вторая машина) успел запушить в промежутке, — и этим превращает опасную команду в безопасную по умолчанию.
Правило, которое стоит вытатуировать на запястье: никогда не ребейзите ветку с открытым pull request, если не понимаете, что делаете — rebase меняет ID коммитов, и открытый PR может отвязаться от своих коммитов. main синхронизируйте мержем (или ребейзите до начала новой работы), а PR-ветки держите в стороне.
Почему форк не синхронизируется с upstream?
Четыре обычных подозреваемых — в порядке, в котором они встречаются в реальных терминалах:
- Нет remote
upstream—git remote -vпоказывает толькоorigin. Симптом:git fetch upstreamпадает с'upstream' does not appear to be a git repository. Лечение: шаг 1 выше. - Фетчнули, но не смержили — фетч обновляет
upstream/mainв вашем локальном репозитории, но не трогает рабочие ветки. Симптом:git logвыглядит старым после успешного фетча. Лечение:git merge upstream/main. - Разошедшаяся история — вы коммитили в
mainсвоего форка, а upstream тоже ушёл вперёд.git pullругается на unrelated histories или требует мерж. Лечение, если должен победить upstream:git reset --hard upstream/main(выбрасывает ваши локальные коммиты в main — сначала проверьтеgit stash listили подстрахуйтесь веткой; если опасный reset уже случился, путь восстановления тот же, что в git undo last commit:git reflogвсё ещё помнит старый кончик). - Push отклонён как non-fast-forward после rebase — вы ребейзнули и пушите обычным способом. Лечение:
git push --force-with-lease origin main.
Пятый, редкий случай: upstream-репозиторий переименовали или удалили, и даже URL из шага 1 отдаёт 404. GitHub редиректит переименованные репозитории, так что жёсткий отказ обычно означает удаление или уход в private — синхронизировать уже не с чем.
Можно ли синхронизировать форк с сайта GitHub?
Да. На странице вашего форка в выпадающем списке веток появляется кнопка Sync fork, когда ветка отстала; один клик — и upstream подтянут. Второй способ там же работает через pull request: откройте PR из upstream/main в main своего форка и смержите.
Ограничения кнопки объясняют, когда возвращаться к CLI: она умеет только fast-forward или merge — без rebase — и наотрез отказывается, когда ветки разошлись, предлагая выбросить коммиты или взять командную строку. И синхронизирует она только ветку по умолчанию. Для всего, что сложнее простого «догнать», инструмент — те три команды выше.
Как часто синхронизировать форк?
Честный ответ — перед каждой новой задачей: бранчеваться от свежей main, и ни один ваш PR не начинается с «это основано на версии трёхнедельной давности». Для форков, куда вы активно контрибьютите, ежедневная синхронизация main или раз за сессию стоит секунд. Для форка, который вы только читаете или деплоите, синхронизируйтесь, когда upstream выпустил что-то нужное, — подпишитесь на релизы оригинального репозитория и синхронизируйтесь на релиз. Синхронизация дешёвая именно потому, что она рутина; форк, отставший на полгода, часто требует уже хирургии, а не мержа, — вот как «синхронизируй мой форк» превращается в полдня работы.
Шпаргалка
# разовая настройка
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
Держите рутинную пару команд в мышечной памяти — и разошедшийся форк останется курьёзом, о котором вы где-то читали, а не проблемой, которую чините. Если ваш git-порядок простирается и на серверы, шпаргалка по journalctl закрывает вторую половину истории — читаемость журналов машины.