core code helper

Віддалені репозиторії Git: clone, fetch, pull, push, fork

Що таке remote і origin/main, різниця між fetch і pull, push нової гілки, force-with-lease, робота через fork з upstream і корисні рецепти синхронізації.

0 імпортували Імпортувати собі

Remote — це адреса з ім'ям

Віддалений репозиторій (remote) — інша копія вашого репозиторію: на GitHub, GitLab, Bitbucket, власному сервері чи навіть у сусідній папці. Щоб не писати адресу щоразу, їй дають коротке ім'я. Після git clone адреса, звідки клонували, автоматично зветься origin.

git remote -v
origin  git@github.com:olena/notes-app.git (fetch)
origin  git@github.com:olena/notes-app.git (push)
Дія Команда
додати git remote add origin git@github.com:olena/notes-app.git
змінити адресу git remote set-url origin git@github.com:olena/new-name.git
перейменувати git remote rename origin github
видалити git remote remove origin
детально (гілки, відстеження) git remote show origin

SSH чи HTTPS

SSH git@github.com:user/repo.git HTTPS https://github.com/user/repo.git
Вхід SSH-ключ, налаштовується раз токен (не пароль!) через credential helper
Через корпоративний проксі часто заблоковано (порт 22) працює майже завжди
Для CI deploy key токен у секретах CI

Перейти з HTTPS на SSH: git remote set-url origin git@github.com:user/repo.git. Налаштування ключів — у нотатці «Встановлення і налаштування Git».

Порт 22 заблоковано

GitHub приймає SSH і на порту 443. У ~/.ssh/config:

Host github.com
    HostName ssh.github.com
    Port 443
    User git

git clone

git clone git@github.com:olena/notes-app.git            # у папку notes-app
git clone git@github.com:olena/notes-app.git my-notes   # у папку my-notes
git clone -b develop git@github.com:olena/notes-app.git # одразу на гілку develop
git clone --depth 1 https://github.com/torvalds/linux.git   # лише останній коміт (швидко)
git clone --recurse-submodules <url>                    # разом із сабмодулями

Remote-tracking гілки: що таке origin/main

Після clone чи fetch у вас з'являються гілки виду origin/main. Це локальні копії стану сервера на момент останнього fetch, лише для читання. Вони не оновлюються самі: якщо колега щойно запушив коміт, ви його не побачите, поки не зробите git fetch.

Схема: локально main вказує на ваш незапушений коміт C3, origin/main — на C2, а на GitHub колега вже запушив C4; push буде відхилено, fetch забере C4

Гілка Де живе Хто рухає
main у вас ви — комітами, merge, reset
origin/main у вас, копія стану сервера лише git fetch / git pull / git push
main на GitHub на сервері git push (ваш і колег)

Зв'язок локальної гілки з віддаленою називається upstream (tracking). Саме завдяки йому git status пише «ahead 2, behind 1», а git pull і git push знають, куди йти без аргументів:

git branch -vv
* main            3a4b5c6 [origin/main: ahead 1, behind 1] Додати пошук
  feature/search  9c0d1e2 [origin/feature/search] Фільтр за тегами
  experiment      1f2e3d4 Спроба нового парсера

experiment не має upstream — її ніколи не пушили.

git fetch — подивитися, що нового, нічого не чіпаючи

git fetch               # origin
git fetch --all         # усі remote
git fetch --prune       # + прибрати origin/* гілки, видалені на сервері

fetch оновлює лише origin/*. Ваші гілки й файли не змінюються — це завжди безпечно. Далі можна подивитися, що прийшло:

git log --oneline main..origin/main     # нові коміти на сервері, яких у вас немає
git log --oneline origin/main..main     # ваші коміти, яких немає на сервері
git diff main origin/main               # різниця у файлах

git pull — забрати й влити

git pull = git fetch + вливання origin/<гілка> у поточну гілку. Як саме вливати — визначають налаштування:

Налаштування Якщо гілки розійшлися
pull.rebase = false merge-коміт «Merge branch 'main' of …»
pull.rebase = true ваші коміти переставляються поверх серверних (лінійно)
pull.ff = only помилка — вирішуйте вручну (найобережніше)

Якщо нічого не налаштовано, а гілки розійшлися, сучасний Git зупиниться:

hint: You have divergent branches and need to specify how to reconcile them.
...
fatal: Need to specify how to reconcile divergent branches.

Оберіть раз і назавжди (найпопулярніший варіант — rebase):

git config --global pull.rebase true

git push — відправити свої коміти

git push                              # поточну гілку в її upstream
git push origin main                  # явно: локальну main в origin/main
git push -u origin feature/search     # нову гілку + запам'ятати upstream

Щоб не писати -u origin <гілка> для кожної нової гілки:

git config --global push.autoSetupRemote true
git switch -c feature/export
git push                              # гілка створиться на сервері сама

Push відхилено

 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'github.com:olena/notes-app.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally.

На сервері є коміти, яких немає у вас (ситуація зі схеми вище). Не робіть --force! Заберіть зміни й повторіть:

git pull --rebase
git push

Варіант (non-fast-forward) з тим самим змістом зазвичай з'являється після того, як ви переписали власну історію (rebase, amend). Якщо гілка лише ваша — git push --force-with-lease, детальніше в нотатці «Rebase».

Видалити гілку на сервері

git push origin --delete feature/search

Теги

git push теги не відправляє:

git push origin v1.2.0      # один тег
git push --tags             # усі локальні теги

Робота через fork

Якщо прав на запис у репозиторій немає (open source або чужа команда), працюють через fork — вашу копію репозиторію на GitHub.

Схема fork-процесу: upstream — оригінал, origin — ваш fork, локальний репозиторій; fork, clone, push у fork, pull request в оригінал і fetch з upstream

# 1. На GitHub: кнопка Fork → github.com/you/project
# 2. Клонуємо свій fork
git clone git@github.com:you/project.git
cd project
# 3. Додаємо оригінал як upstream
git remote add upstream https://github.com/author/project.git
git remote -v
origin    git@github.com:you/project.git (fetch)
origin    git@github.com:you/project.git (push)
upstream  https://github.com/author/project.git (fetch)
upstream  https://github.com/author/project.git (push)

Робота над задачею:

git fetch upstream
git switch -c fix/typo-in-docs upstream/main   # гілка від свіжого оригіналу
# ... правки, коміти ...
git push -u origin fix/typo-in-docs             # у свій fork
# 4. На GitHub: Compare & pull request → в author/project

Оновити свій main із оригіналу:

git switch main
git fetch upstream
git merge --ff-only upstream/main
git push origin main

На GitHub для цього ще є кнопка Sync fork.

Не працюйте прямо в main свого fork

Тримайте main fork-а точною копією upstream/main, а кожну задачу — у своїй гілці. Тоді синхронізація завжди fast-forward і без конфліктів.

Корисні рецепти

Взяти гілку колеги:

git fetch
git switch feature/payments    # Git сам створить локальну гілку з upstream origin/feature/payments

Скинути локальну гілку до стану сервера (всі локальні коміти й зміни в ній буде втрачено!):

git fetch origin
git reset --hard origin/main

Що я ще не запушив:

git log --oneline @{u}..       # @{u} — upstream поточної гілки

Прив'язати існуючу гілку до віддаленої:

git branch -u origin/feature/search

Перейменувати master на main:

git branch -m master main
git push -u origin main
# на GitHub: Settings → Branches → default branch → main
git push origin --delete master

Перенести репозиторій на інший сервер з усією історією:

git clone --mirror git@old-server:team/app.git
cd app.git
git push --mirror git@github.com:team/app.git

Шпаргалка

Команда Що робить
git remote -v список remote
git remote add upstream <url> додати ще один remote
git fetch --all --prune оновити знання про всі сервери
git log main..origin/main що нового на сервері
git pull --rebase забрати й поставити свої коміти зверху
git push -u origin <гілка> перший push нової гілки
git push --force-with-lease push після rebase, не затираючи чужого
git push origin --delete <гілка> видалити гілку на сервері
git branch -vv гілки з upstream і ahead/behind
git reset --hard origin/main стати точно як сервер

Збережіть статтю собі

Увійдіть, щоб імпортувати її у власні нотатки, відмічати вивчене, ставити лайки й питати спільноту. Реєстрація безкоштовна: вхід через Google займає кілька секунд.

Увійти через Google Інші способи входу