В open-source чаще всего работают через fork. Сценарий:
github.com/original-project/awesome ← оригинал, ты в нём не пишешь
github.com/me/awesome ← твой fork, ты в нём пишешь
Локально удобно настроить два remote:
# При clone'е своего форка
git clone git@github.com:me/awesome.git
cd awesome
# Добавляем оригинал как upstream
git remote add upstream git@github.com:original-project/awesome.git
git fetch upstream
Теперь:
origin- твой fork. Сюда пушишь свои ветки.upstream- оригинал. Отсюда тянешь чужие обновления.
Зачем оба нужны
Без upstream ты получаешь обновления только через GitHub UI: «Sync
fork» в браузере. Это работает, но цикл медленный и не подходит
для скриптов/CI.
С upstream цикл «синхронизироваться с оригиналом» - две команды:
git fetch upstream
git switch main
git rebase upstream/main # или git merge upstream/main
git push origin main # обновить main в своём fork'e
Никакой UI не нужен, работает из терминала, повторяемо.
Workflow для нового PR
# 1. Подтянуть оригинал
git fetch upstream
# 2. Создать фича-ветку от свежей upstream/main, не от origin/main
git switch -c feat/my-fix upstream/main
# 3. ... коммиты ...
# 4. Запушить в свой fork (origin), не в upstream
git push -u origin feat/my-fix
# 5. На GitHub открыть PR: from me:feat/my-fix → original-project:main
Ключевой момент шага 2 - ветвиться от upstream/main, не от
origin/main. Иначе твой fork может быть на день отставать, и в
PR попадёт куча устаревших коммитов.
Это просто имена
Git ничего не знает про «оригинал» и «fork». Это конвенция, ничего
больше. Можно назвать их mine и theirs, работать будет
одинаково:
git remote rename origin mine
git remote rename upstream theirs
Но в команде проще говорить общими словами, чтобы инструкции «git fetch upstream && git rebase upstream/main» работали у всех.
Когда upstream не нужен
Если у тебя нет fork'а, а ты пушишь напрямую в основной репо
(член команды, owner) - upstream не нужен. Один origin,
стандартный flow.
Подводные камни
- Случайный push в upstream. Если у тебя есть права на запись в
upstream (например, ты maintainer оригинала и твой fork - для
экспериментов), можно по ошибке
git push upstream mainи обновить main оригинала. Спасают branch-protection правила. - Расхождение origin/main и upstream/main. Если в свой fork
кто-то запушил отдельно (другой контрибьютор, копия), main в нём
и main в upstream разойдутся. Решение - синхронизировать через
git push origin upstream/main:main(или просто пересоздать fork). - При forge-смене (GitHub → GitLab) забывают переключить upstream.
Если оригинал переехал - обнови
git remote set-url upstream <new>.