Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Питання на співбесіді з Git

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

100 питань

Хуки - виконувані скрипти, які Git запускає в певні моменти: перед комітом, після checkout, перед push. Лежать у .git/hooks/ (Git створює там приклади з суфіксом .sample) і мають бути виконуваними (chmod +x).

Клієнтські хуки, які використовують найчастіше:

Хук Коли Типове використання
pre-commit перед створенням коміту форматування, лінтер, швидкі перевірки
prepare-commit-msg перед відкриттям редактора повідомлення підставити номер задачі з назви гілки
commit-msg після введення повідомлення перевірити формат (Conventional Commits)
post-checkout після checkout/switch оновити залежності, очистити кеш
pre-push перед відправкою на сервер запустити тести

Ненульовий код виходу скасовує операцію - так pre-commit може заборонити коміт:

#!/bin/sh
# .git/hooks/pre-commit
vendor/bin/pint --test || {
    echo "Код не відформатовано. Запустіть vendor/bin/pint"
    exit 1
}

Що отримують хуки:

  • commit-msg - шлях до файла з повідомленням коміту (першим аргументом);
  • pre-push - назву й адресу віддаленого репозиторію в аргументах, а в стандартному вводі - рядки з посиланнями й SHA, які відправляються.

Важливі обмеження:

  • .git/hooks не потрапляє в репозиторій - хуки не поширюються командою автоматично (для цього - core.hooksPath чи інструменти на кшталт Husky і CaptainHook);
  • хуки легко обійти: git commit --no-verify (чи -n) пропускає pre-commit і commit-msg, git push --no-verify - pre-push. Тому хуки - зручність для розробника, а гарантію дає CI;
  • хуки мають бути швидкими: pre-commit на хвилину - і люди почнуть використовувати --no-verify постійно. Повний набір тестів - у pre-push чи CI.

Докладніше в документації: githooks

Каталог .git/ не версіонується, тож хуки, покладені в .git/hooks, живуть лише на вашій машині. Є кілька способів зробити їх спільними.

1. core.hooksPath - вбудований механізм Git:

mkdir .githooks
# покласти туди pre-commit, commit-msg... і зробити виконуваними
chmod +x .githooks/*
git config core.hooksPath .githooks

Хуки лежать у репозиторії й проходять рев'ю, але кожен розробник має один раз виконати git config. Його зручно додати в скрипт налаштування проєкту:

{
    "scripts": {
        "post-install-cmd": ["git config core.hooksPath .githooks || true"]
    }
}

2. CaptainHook - для PHP-проєктів: конфігурація в captainhook.json, хуки встановлюються командою vendor/bin/captainhook install (або автоматично через Composer-плагін):

{
    "pre-commit": {
        "enabled": true,
        "actions": [
            { "action": "vendor/bin/pint --test" },
            { "action": "vendor/bin/phpstan analyse --no-progress" }
        ]
    }
}

3. GrumPHP - інший PHP-інструмент: набір готових задач (phpcs, phpstan, phpunit, перевірка повідомлень комітів), конфігурація в grumphp.yml, хуки ставить сам.

4. Husky - якщо в проєкті є Node: npx husky init створює каталог .husky/ і через скрипт prepare у package.json налаштовує core.hooksPath при кожному npm install. Часто разом з lint-staged, що запускає інструменти лише на змінених файлах.

Як обрати: PHP-бекенд без Node - CaptainHook чи GrumPHP; є фронтенд і npm install - Husky; мінімум залежностей - core.hooksPath.

Пам'ятайте: хуки - зручність, а не гарантія. Будь-хто може їх не встановити чи пропустити через --no-verify, тому ті самі перевірки обов'язково дублюються в CI.

Докладніше в документації: git config: core.hooksPath

Laravel Pint - форматувальник коду на основі PHP CS Fixer. Корисні режими:

vendor/bin/pint                 # виправити всі файли
vendor/bin/pint --test          # лише перевірити, ненульовий код при помилках
vendor/bin/pint --dirty         # лише файли з незакоміченими змінами
vendor/bin/pint --diff=main     # лише файли, що відрізняються від гілки main
vendor/bin/pint --repair        # виправити, але повернути ненульовий код, якщо було що виправляти

Простий pre-commit хук:

#!/bin/sh
files=$(git diff --cached --name-only --diff-filter=ACMR -- '*.php')
[ -z "$files" ] && exit 0

vendor/bin/pint $files
git add $files
  • git diff --cached - лише файли, додані в індекс (тобто ті, що потраплять у коміт);
  • --diff-filter=ACMR - додані, скопійовані, змінені й перейменовані; видалені файли форматувати нема чого;
  • git add після форматування - щоб виправлення потрапили в коміт.

Пастка частково доданих файлів: якщо у файлі частина змін додана в індекс (git add -p), а частина ні, то git add $files після Pint додасть у коміт і ті зміни, які ви навмисно не додавали. Варіанти:

  • лише перевіряти, а не виправляти: vendor/bin/pint --test $files - коміт блокується, розробник сам запускає Pint;
  • використати інструмент, що вміє працювати з частковим індексом (lint-staged ховає неіндексовані зміни на час перевірки).

--dirty у хуку - зручно, але він бере файли з будь-якими незакоміченими змінами, а не лише з індексу.

Що варто знати:

  • форматування в хуку - зручність; в CI має бути pint --test, щоб неформатований код не потрапив у main через --no-verify;
  • конфігурація в pint.json - однакова для хуку, CI й редактора;
  • великий одноразовий перехід на Pint краще зробити окремим комітом і додати його SHA у .git-blame-ignore-revs, щоб git blame не показував форматування як автора всіх рядків.

Докладніше в документації: Laravel Pint: запуск

GitHub Actions - вбудований у GitHub CI/CD. Робочі процеси (workflows) описуються в YAML у .github/workflows/ і запускаються на події: push, pull request, розклад, ручний запуск.

Основні поняття:

  • workflow - файл з описом процесу;
  • event (on) - що запускає процес;
  • job - набір кроків, що виконується на окремій віртуальній машині (runner); jobs ідуть паралельно, якщо не вказано залежність needs;
  • step - команда (run) чи готова дія (uses) з Marketplace.

Мінімальний workflow для Laravel:

# .github/workflows/tests.yml
name: tests

on:
  pull_request:
  push:
    branches: [main]

jobs:
  tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7

      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.5'
          coverage: none

      - run: composer install --no-interaction --prefer-dist

      - run: cp .env.example .env && php artisan key:generate

      - run: vendor/bin/pint --test

      - run: php artisan test --compact

Що відбувається: на кожен PR і push у main GitHub піднімає чисту машину з Ubuntu, завантажує код, встановлює PHP і залежності, перевіряє стиль і запускає тести. Результат видно в PR як перевірку - зелену чи червону.

Чому це важливо:

  • те, що «працює в мене», перевіряється в чистому середовищі;
  • хуки можна пропустити, а CI - ні, особливо з обов'язковими перевірками в захисті гілки;
  • рецензент не витрачає час на код, який не проходить тести.

Корисно знати:

  • для публічних репозиторіїв стандартні runner-и безкоштовні, для приватних є місячна квота хвилин;
  • секрети (ключі API) - у Settings → Secrets і доступні як ${{ secrets.NAME }}; у PR з форків секрети за замовчуванням не передаються;
  • shivammathur/setup-php - де-факто стандарт для PHP: версії, розширення, інструменти.

Докладніше в документації: GitHub Actions: основи

Dependabot - бот GitHub, що стежить за залежностями й сам відкриває pull request-и з оновленнями. Розробнику лишається переглянути зміни, дочекатися зеленого CI і злити.

Два режими:

  • security updates - PR лише для залежностей з відомими вразливостями (на основі GitHub Advisory Database);
  • version updates - регулярні PR з новими версіями за розкладом.

Конфігурація для Laravel-проєкту:

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: composer
    directory: /
    schedule:
      interval: weekly
    groups:
      laravel:
        patterns: ["laravel/*"]
    open-pull-requests-limit: 5

  - package-ecosystem: npm
    directory: /
    schedule:
      interval: weekly

  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: monthly

Що тут налаштовано:

  • екосистеми: Composer, npm і навіть версії дій у workflow GitHub Actions;
  • groups - кілька оновлень в одному PR (усі пакети laravel/* разом), щоб не тонути в десятках дрібних PR;
  • open-pull-requests-limit - скільки PR бот тримає відкритими одночасно;
  • schedule - як часто перевіряти.

Чому це варто робити:

  • маленькі регулярні оновлення простіші за одне велике раз на рік, коли накопичилися мажорні версії й breaking changes;
  • вразливості закриваються швидко, а не після інциденту;
  • оновлення проходять той самий процес, що й код: CI, рев'ю, історія.

Без доброго набору тестів Dependabot корисний наполовину: зелений CI має реально означати «оновлення нічого не зламало». Тому тести - передумова для сміливих оновлень.

Корисні опції: ignore - пропускати певні пакети чи мажорні версії, cooldown - не пропонувати версію одразу після публікації, а почекати кілька днів (захист від зламаних чи скомпрометованих релізів).

Докладніше в документації: GitHub: Dependabot version updates

git rebase -i відкриває список комітів гілки, де кожному можна задати дію. Так історію з «wip», «fix typo», «ще фікс» перетворюють на кілька змістовних комітів.

git rebase -i main
pick a1b2c3d Add invoice model
squash d4e5f6a fix typo
pick 9f8e7d6 Send invoice email
fixup 1a2b3c4 forgot import
reword 5d6e7f8 wip

Основні дії:

  • pick - лишити коміт як є.
  • reword - змінити повідомлення.
  • squash - злити з попереднім, об'єднавши повідомлення.
  • fixup - злити з попереднім, відкинувши повідомлення.
  • edit - зупинитися на коміті, щоб змінити його чи розбити на кілька.
  • drop або видалити рядок - прибрати коміт.
  • Переставити рядки - змінити порядок комітів.

Зручний прийом - fixup-коміти:

git commit --fixup=a1b2c3d     # «виправлення до коміту a1b2c3d»
git rebase -i --autosquash main # сам поставить fixup у потрібне місце

Навіщо: рев'юеру легше читати кілька логічних комітів, ніж двадцять випадкових; git bisect і git blame працюють точніше; коміт можна відкотити цілком.

Обережно: це переписування історії. Лише для своєї гілки, а потім - git push --force-with-lease. Якщо щось пішло не так, git rebase --abort повертає все як було, а після завершення врятує git reflog.

Багато команд обходяться без цього, вливаючи PR через squash merge - тоді вся гілка стає одним комітом у main.

Докладніше в документації: git rebase: interactive mode

git bisect шукає коміт, що вніс помилку, двійковим пошуком. Ви називаєте один «поганий» коміт (де баг є) і один «хороший» (де його ще не було), а Git щоразу переходить на середину проміжку й питає, чи є там баг.

git bisect start
git bisect bad                 # поточний коміт - зламаний
git bisect good v2.3.0         # у цьому релізі все працювало

# Git перемикається на коміт посередині
# перевіряєте й кажете:
git bisect good    # або
git bisect bad

# ...через кілька кроків:
# a1b2c3d is the first bad commit

git bisect reset               # повернутися, звідки почали

Серед 1000 комітів винуватця знайдено за ~10 перевірок.

Автоматично - якщо є команда, що відповідає «добре/погано» кодом виходу:

git bisect run php artisan test --filter=InvoiceTotalTest

Код 0 - коміт хороший, 1-127 (крім 125) - поганий, 125 - пропустити (наприклад, коміт не збирається).

Що допомагає bisect:

  • Невеликі коміти, кожен з яких працює. Якщо коміт «напівготовий» і падає з іншої причини, bisect заплутається - такі коміти пропускають (git bisect skip).
  • Тест, що відтворює баг, - його пишуть першим, а потім ганяють через bisect run.

Знайшовши коміт, видно не лише рядок, а й контекст: повідомлення, задачу, автора - часто це пояснює, чому баг з'явився.

Докладніше в документації: git bisect

Звичайний git rebase main переносить усі коміти поточної гілки, яких немає в main. Але інколи потрібно перенести лише частину комітів чи змінити основу на зовсім іншу гілку. Для цього є --onto:

git rebase --onto <нова-основа> <стара-основа> <гілка>

Git бере коміти з діапазону стара-основа..гілка і відтворює їх поверх нова-основа.

Сценарій 1 - гілку створено не від тієї гілки. Гілку feature почали від develop, а треба було від main:

main ── A
         \
develop   B ── C
                \
feature          D ── E
git rebase --onto main develop feature
main ── A ── D' ── E'    (feature)

Коміти B і C з develop у feature не потрапили.

Сценарій 2 - залежні pull request. Гілка part-2 побудована поверх part-1. Після злиття part-1 через squash її коміти в main мають інші хеші, і звичайний git rebase main намагатиметься застосувати їх повторно з конфліктами:

git rebase --onto main part-1 part-2

Переноситься лише власна робота part-2.

Сценарій 3 - видалити коміти з середини гілки:

git rebase --onto HEAD~5 HEAD~3

Коміти HEAD~4 і HEAD~3 зникають, решта переноситься на HEAD~5.

Що пам'ятати:

  • як і будь-який rebase, --onto створює нові коміти з новими хешами - для вже опублікованої спільної гілки це переписування історії;
  • якщо заплуталися - git rebase --abort під час процесу чи git reflog після нього;
  • --update-refs (Git 2.38+) оновлює й проміжні гілки в ланцюжку - зручно для стопки залежних гілок.

Докладніше в документації: git rebase: перенесення гілки з --onto

Злити гілку feature у main можна трьома способами, і від вибору залежить вигляд історії.

Fast-forward - можливий, коли main не просунувся після створення feature. Git просто пересуває вказівник main на останній коміт feature, нового коміту не створюється:

до:     main ── A                після:  A ── B ── C   (main, feature)
                 \
                  B ── C (feature)

Історія лінійна, але факт існування гілки зникає: не видно, які коміти були однією задачею.

--no-ff - завжди створює коміт злиття, навіть коли fast-forward можливий:

git merge --no-ff feature
A ────────── M   (main)
 \          /
  B ── C ──      (feature)

Видно межі задачі; відкотити всю функціональність можна одним git revert -m 1 M. Ціна - більше комітів злиття в історії.

Squash - усі зміни гілки стають одним новим комітом в main:

git merge --squash feature
git commit -m "Add invoice export"

Історія main чиста: одна задача - один коміт. Але:

  • проміжні коміти гілки в main не потрапляють - деталізація для git bisect і blame втрачається;
  • Git не вважає feature злитою (git branch --merged її не покаже), а git branch -d feature відмовиться її видаляти;
  • якщо продовжити роботу в тій самій гілці, наступний squash може дати конфлікти з уже злитими змінами.

Порівняння:

Fast-forward --no-ff Squash
коміт злиття ні так ні
проміжні коміти в main так так ні
межі задачі видно ні так так (один коміт)

Налаштування: git config merge.ff only дозволяє лише fast-forward (злиття впаде, якщо воно неможливе), pull.ff only - те саме для git pull. На GitHub і GitLab спосіб злиття pull request обирається в налаштуваннях репозиторію.

Докладніше в документації: git merge: fast-forward

git blame показує для кожного рядка файлу, в якому коміті й ким він востаннє змінений:

git blame app/Services/Billing.php
git blame -L 40,60 app/Services/Billing.php    # лише рядки 40-60
a1b2c3d4 (Olena 2026-03-14 41) $total = round($subtotal * 1.2, 2);

Мета - не «кого звинуватити», а «чому так»: знайдений хеш веде до коміту з повідомленням, pull request і обговоренням, де видно причину рішення.

git show a1b2c3d4

Проблема: шумні коміти. Масове форматування (Pint, Prettier), перейменування чи перенесення коду роблять автором кожного рядка «коміт форматування», і справжня історія ховається.

Що допомагає:

Параметр Що робить
-w ігнорує зміни пробілів
-M розпізнає рядки, переміщені в межах файлу
-C розпізнає рядки, перенесені з інших файлів того самого коміту (-C -C -C - з будь-якого коміту)
--ignore-rev <хеш> пропустити конкретний коміт і показати попереднього автора

Файл ігнорованих комітів - рішення для всієї команди:

# .git-blame-ignore-revs
# Pint: форматування всього проєкту
3f9e1a2b7c...
git config blame.ignoreRevsFile .git-blame-ignore-revs

GitHub автоматично враховує файл .git-blame-ignore-revs у корені репозиторію у своєму інтерфейсі blame.

Коли рядок змінювався багато разів:

  • git log -L 40,60:app/Services/Billing.php - вся історія змін саме цього фрагмента, з diff кожного кроку;
  • git log -S "1.2" - коміти, що додали чи прибрали конкретний вираз;
  • в IDE blame вбудований («Annotate with Git Blame» у PhpStorm) з можливістю переходити до попередньої ревізії рядка.

Докладніше в документації: git blame

Після rebase чи commit --amend історія локальної гілки розходиться з віддаленою, і звичайний git push відмовляється. git push --force перезаписує віддалену гілку вашою версією безумовно.

Чим це небезпечно: якщо колега встиг відправити в цю гілку свої коміти, force push їх знищить на сервері - ви навіть не побачите, що вони там були.

--force-with-lease перезаписує гілку, лише якщо вона на сервері досі в тому стані, який ви бачили під час останнього fetch. Якщо хтось додав коміти - push відхиляється, і ви спершу інтегруєте їхні зміни.

git rebase main
git push --force-with-lease

Пастка: «той стан, що ви бачили» - це ваш origin/feature. Якщо ви зробили git fetch (чи IDE зробила його у фоні), не подивившись, що прийшло, lease вважатиме нові чужі коміти «баченими». Суворіший варіант - --force-if-includes (Git 2.30+), який вимагає, щоб віддалені коміти були інтегровані в вашу гілку.

Правила команди:

  • Force push лише у свої гілки. У main, develop, релізні гілки - ніколи.
  • Захищені гілки на GitHub/GitLab забороняють force push і вимагають pull request з рев'ю.
  • Якщо над гілкою працює кілька людей - домовитися перед переписуванням історії або обійтися merge.

Докладніше в документації: git push

GitHub Flow - найпоширеніший для веб-застосунків:

  • main завжди готовий до деплою;
  • кожна задача - коротка гілка від main;
  • pull request, рев'ю, CI → злиття в main → деплой.

Простий і добре працює з безперервним розгортанням.

Git Flow - для продуктів з версіями й релізами:

  • main - лише релізи, develop - інтеграція;
  • feature/* від develop, release/* для підготовки версії, hotfix/* від main для термінових виправлень.

Підходить, коли одночасно підтримують кілька версій (бібліотеки, коробкове ПЗ, мобільні застосунки з рев'ю в сторах). Для веб-сервісу з кількома деплоями на день - надто важкий: багато злиттів, довгоживучі гілки.

Trunk-based development - усі інтегрують зміни в головну гілку дуже часто, щодня чи кілька разів на день:

  • гілки живуть години, а не тижні (або коміт одразу в trunk);
  • незавершені фічі ховають за feature flags, а не тримають у гілці;
  • потрібні сильні автотести й CI.

Мінімум конфліктів злиття і швидкий зворотний зв'язок, але потребує дисципліни й інфраструктури.

Як обирати: веб-продукт з частими деплоями - GitHub Flow чи trunk-based. Кілька підтримуваних версій - щось ближче до Git Flow. Головне - не модель, а короткоживучі гілки: чим довше гілка живе окремо, тим болючіше її злиття.

Докладніше в документації: Робочі процеси з гілками

Worktree - додатковий робочий каталог, прив'язаний до того самого репозиторію. Кожен worktree має свою гілку й свої файли, а історія, об'єкти й налаштування спільні.

git worktree add ../app-hotfix hotfix/invoice-rounding
git worktree add -b review/pr-412 ../app-review origin/feature/export
git worktree list
git worktree remove ../app-hotfix

Сценарій: ви посеред великої задачі з десятком змінених файлів, і терміново потрібно виправити баг у продакшені.

  • через stash: сховати зміни, перемкнутися, виправити, повернутися, дістати зі stash. Каталог vendor/ і node_modules/ можуть не відповідати гілці, запущений npm run dev перезбирає не той код, IDE переіндексовує проєкт;
  • через worktree: відкрити окремий каталог з гілкою виправлення. Основна робота лишається недоторканою, можна навіть паралельно запустити тести в обох каталогах.

Коли worktree зручний:

  • термінові виправлення без переривання поточної роботи;
  • рев'ю pull request - перевірити чужу гілку локально, не чіпаючи свою;
  • порівняння поведінки двох версій поруч;
  • довгі операції (повний прогін тестів, збирання) в одній гілці, поки працюєте в іншій;
  • паралельна робота кількох агентів чи скриптів над різними гілками одного репозиторію.

Обмеження:

  • одна гілка - один worktree: не можна перемкнутися на гілку, вже відкриту в іншому worktree (Git захищає від двох незалежних змін однієї гілки);
  • ігноровані файли не спільні: vendor/, node_modules/, .env у новому каталозі відсутні - їх доведеться встановити чи скопіювати;
  • для Laravel: окремий каталог означає окремий .env; якщо обидва worktree використовують ту саму базу, міграції однієї гілки зачеплять іншу;
  • видаляйте worktree через git worktree remove, а не rm -rf - інакше лишаються записи (git worktree prune їх прибирає).

Порівняно з другим клоном worktree не дублює історію (економить місце й час) і бачить локальні гілки й коміти основного репозиторію без fetch.

Докладніше в документації: git worktree

Поки ви працюєте над задачею, main просувається. Чим довше гілка живе окремо, тим більше конфліктів і тим вищий ризик, що код, який працює в гілці, зламається після злиття. Тому гілку періодично оновлюють.

Варіант 1 - злити main у гілку:

git fetch origin
git merge origin/main
  • історія гілки не переписується - безпечно, навіть якщо в гілці працюють кілька людей;
  • push без force;
  • конфлікти розв'язуються один раз;
  • в історії з'являються коміти злиття Merge branch 'main' into feature - при squash-злитті pull request вони зникнуть.

Варіант 2 - rebase на main:

git fetch origin
git rebase origin/main
git push --force-with-lease
  • лінійна історія: гілка виглядає так, ніби її почали щойно;
  • коміти отримують нові хеші, потрібен force push;
  • конфлікти розв'язуються для кожного коміту окремо - на довгій гілці це може повторюватися (допомагає rerere);
  • небезпечно, якщо гілкою користуються інші: їхні локальні копії розійдуться з вашою.

Як обрати:

Ситуація Що краще
особиста гілка, коміти ще не рев'ювали rebase
у гілці працюють кілька людей merge
pull request уже на рев'ю merge - рецензенти бачать, що змінилося після їхніх коментарів (після rebase GitHub гірше показує різницю)
злиття в main буде через squash будь-який, історія гілки все одно зникне

Як часто: невеликими кроками - щодня чи перед кожним push, а не раз на тиждень. Конфлікт у двох файлах розв'язати легше, ніж у двадцяти.

Найкращий захист від болісного оновлення - короткоживучі гілки: задача на 1-3 дні дає значно менше розбіжностей, ніж гілка, що живе місяць.

На GitHub кнопка «Update branch» у pull request робить merge (чи rebase, якщо обрати). Branch protection з вимогою «Require branches to be up to date» змушує оновлювати гілку перед злиттям.

Докладніше в документації: git rebase

Lock-файли змінюються майже при кожній зміні залежностей, і дві гілки, що додали по пакету, гарантовано конфліктують. Розв'язувати такий конфлікт вручну, редагуючи JSON, не можна: у composer.lock є content-hash - хеш вмісту composer.json, і ручне злиття майже завжди дає невідповідність або неузгоджене дерево залежностей.

Правильний спосіб для Composer:

  1. розв'язати конфлікт у composer.json - він короткий і зрозумілий людині;
  2. взяти composer.lock з основної гілки;
  3. повторити зміни своєї гілки командою Composer:
git checkout --theirs composer.lock     # при rebase - --ours, див. нижче
composer update vendor/added-package    # лише пакети, які додала ваша гілка
# або, якщо змінювали лише composer.json без нових пакетів:
composer update --lock
git add composer.json composer.lock

composer update лише для конкретних пакетів, а не всіх: повний composer update оновить усе дерево, і pull request раптом міститиме десятки чужих оновлень.

Для npm:

git checkout --theirs package-lock.json
npm install            # перебудує lock з урахуванням вашого package.json

npm також вміє сам розв'язувати конфлікти в package-lock.json: якщо запустити npm install при конфлікті лише в lock-файлі, він об'єднує обидві версії.

Увага до --ours і --theirs при rebase: під час rebase ролі міняються місцями - --ours означає гілку, на яку переносите (тобто main), а --theirs - ваші коміти. Тому при rebase версія main - це --ours.

Як зменшити кількість конфліктів:

  • оновлювати залежності окремими невеликими pull request, а не в гілках задач;
  • автоматизовані оновлення (Dependabot, Renovate) з частим злиттям;
  • перед роботою над задачею оновити гілку з main.

Перевірка після розв'язання:

composer validate          # чи відповідає lock-файл composer.json
composer install           # чи встановлюється дерево
php artisan test

Чого не робити: додавати lock-файли в .gitignore, щоб «не конфліктували». Для застосунку lock-файл - гарантія, що продакшен, CI і колеги отримують однакові версії пакетів.

Докладніше в документації: Composer: розв'язання конфліктів злиття

Питання з реальних технічних співбесід - 100 питань у 7 темах, розібраних із відповідями. Нижче - розбивка за рівнями та темами, якщо хочете звузити підготовку.

Рівні
Junior 35 Middle 35 Senior 30

Готуєтесь до співбесіди не просто так: зараз на сайті 145 відкритих вакансій Laravel і PHP. Переглянути вакансії