Junior: питання на співбесіді з теми «Командна робота»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
5 питань
git fetchзавантажує нові коміти й гілки з віддаленого репозиторію і оновлює віддалені гілки (origin/main). Ваші локальні гілки й робочі файли не змінюються.git pull=fetch+ інтеграція змін у поточну гілку (за замовчуваннямmerge, абоrebase, якщо так налаштовано).
git fetch
git log main..origin/main # що нового на сервері, ще до злиття
git diff main origin/main # які саме зміни
git merge origin/main # або git rebase origin/main
Чому fetch корисний: спершу подивитися, що змінилося, і лише потім вирішити, як інтегрувати. pull робить усе одразу, і при конфлікті ви опиняєтеся посеред злиття без попередження.
Налаштування pull, яке варто знати:
git config --global pull.rebase true # pull через rebase - без зайвих комітів злиття
git config --global pull.ff only # або: лише перемотування, інакше помилка
Без явного налаштування сучасний Git при розбіжності гілок відмовляється робити pull і просить обрати стратегію.
Типова ситуація: «у мене не той код, що на сервері» - часто просто не зроблено fetch, і origin/main у вас застарілий.
Конфлікт виникає, коли обидві гілки змінили ті самі рядки (або одна змінила файл, а інша - видалила). Git не знає, яка версія правильна, і зупиняє злиття.
git merge feature
# CONFLICT (content): Merge conflict in app/Services/Billing.php
git status # список файлів з конфліктами
У файлі з'являються маркери:
<<<<<<< HEAD
$total = $subtotal * 1.2;
=======
$total = $subtotal + $this->tax($subtotal);
>>>>>>> feature
Що робити:
- Відредагувати файл: залишити потрібну версію, поєднати обидві чи написати третю. Прибрати всі маркери.
- Перевірити, що код працює: тести, запуск.
- Позначити конфлікт розв'язаним і завершити:
git add app/Services/Billing.php
git commit # для rebase: git rebase --continue
Передумали - повернути все як до злиття: git merge --abort (чи git rebase --abort).
Корисне:
git config --global merge.conflictStyle zdiff3- маркери показують ще й спільного предка: видно не лише «що в кожній гілці», а й «що було до обох змін». Розв'язувати значно легше.- IDE (PhpStorm, VS Code) мають тристоронній редактор конфліктів.
- Для файлів, які генеруються (
composer.lock,package-lock.json), руками не мержать: беруть одну версію й заново виконують команду, що її створила.
Як конфліктів менше: короткоживучі гілки, часта інтеграція з main, невеликі pull request.
Докладніше в документації: git merge: розв'язання конфліктів
У Git три види гілок, і їх часто плутають:
| Що | Приклад | Хто змінює |
|---|---|---|
| локальна гілка | main, feature/export |
ви, комітами |
| віддалена гілка (remote-tracking) | origin/main |
лише git fetch/pull/push - це «знімок» стану сервера на момент останньої синхронізації |
| гілка на сервері | main у репозиторії на GitHub |
інші учасники через push |
Upstream (відстежувана гілка) - зв'язок локальної гілки з віддаленою. Він дозволяє писати просто git push і git pull без параметрів і показує розбіжність:
git status
# Your branch is ahead of 'origin/main' by 2 commits.
Нова локальна гілка upstream не має - тому перший git push відповідає:
fatal: The current branch feature/export has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin feature/export
git push -u origin feature/export # -u = --set-upstream
Після цього git push і git pull працюють без аргументів.
Автоматизація: з git config --global push.autoSetupRemote true перший git push сам створює гілку на сервері й налаштовує upstream.
Корисні команди:
git branch -vv # усі гілки з їхнім upstream і розбіжністю
git branch -u origin/main # задати upstream для поточної гілки
git switch feature/export # якщо локальної гілки немає, а origin/feature/export є -
# Git створить її з upstream автоматично
git fetch --prune # прибрати origin/* гілки, видалені на сервері
Типова плутанина: origin/main не оновлюється сам. Якщо git status каже «up to date with 'origin/main'», це означає «збігається з тим, що ви бачили під час останнього fetch», а не з поточним станом сервера.
Форк - ваша копія чужого репозиторію на GitHub. Через форк вносять зміни в проєкти, куди немає прав на запис: так працює більшість open source, включно з Laravel.
Схема з двома віддаленими репозиторіями:
git clone git@github.com:olena/framework.git # ваш форк - це origin
cd framework
git remote add upstream https://github.com/laravel/framework.git
git remote -v
| Remote | Що це | Права |
|---|---|---|
origin |
ваш форк | читання й запис |
upstream |
оригінальний репозиторій | лише читання |
Робочий цикл:
git fetch upstream
git switch -c fix/route-cache upstream/13.x # гілка від актуального стану оригіналу
# ... зміни, коміти ...
git push -u origin fix/route-cache # у свій форк
Далі на GitHub - pull request з olena:fix/route-cache у laravel:13.x.
Синхронізація форку:
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main
Або кнопка «Sync fork» на сторінці форку на GitHub, або gh repo sync.
Правила, що позбавляють проблем:
- не комітьте в
mainфорку - тримайте його точною копієюupstream/main, а кожну зміну робіть в окремій гілці. Тоді синхронізація завжди fast-forward; - гілку для pull request створюйте від свіжого
upstream/<цільова гілка>, а не від застарілогоmainфорку; - якщо оригінал просунувся під час рев'ю -
git fetch upstream && git rebase upstream/13.xіgit push --force-with-lease; - цільова гілка має значення: у Laravel виправлення йдуть у гілку поточної версії, а нові можливості - в
master; це описано в правилах внеску.
Дозвіл супровідникам («Allow edits by maintainers») на pull request дає їм змогу дописати дрібні виправлення прямо у вашу гілку.
Ситуація: ви зробили коміт у main, а колега тим часом відправив свій. Тепер у вас є коміт, якого немає на сервері, а на сервері - коміт, якого немає у вас. Гілки розійшлися:
C (ваш)
/
A ── B
\
D (origin/main)
Сучасний Git при git pull у такому разі не обирає спосіб сам, а просить вирішити:
hint: You have divergent branches and need to specify how to reconcile them.
fatal: Need to specify how to reconcile divergent branches.
Три варіанти:
| Налаштування | Що відбувається | Результат |
|---|---|---|
pull.rebase false |
злиття | коміт злиття Merge branch 'main' of ... |
pull.rebase true |
rebase | ваш коміт C переноситься поверх D, історія лінійна |
pull.ff only |
лише fast-forward | при розбіжності pull відмовляється, і ви вирішуєте вручну |
git config --global pull.rebase true
# або разово
git pull --rebase
Що обрати для локальних комітів у спільній гілці - зазвичай rebase:
- ваші ще не відправлені коміти просто «перебудовуються» поверх свіжих змін;
- історія не засмічується безглуздими комітами
Merge branch 'main' of github.com:..., які нічого не означають, крім «ми з колегою працювали одночасно».
Коли rebase при pull не підходить:
- ваші локальні коміти - це злиття іншої гілки (rebase їх розгорне, якщо не вказати
--rebase=merges); - конфліктів дуже багато: rebase розв'язує їх коміт за комітом, злиття - один раз.
Корисно разом з rebase: git config --global rebase.autoStash true - незакомічені зміни автоматично ховаються в stash перед rebase й повертаються після.
Якщо щось пішло не так: git rebase --abort під час rebase, git reflog - після.