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

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

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

100 питань

У Git файл проходить три місця:

Місце Що там Команда, що переносить далі
робочий каталог файли, які ви редагуєте git add
індекс (staging area) знімок, яким буде наступний коміт git commit
репозиторій збережені коміти -

Індекс - це чернетка наступного коміту. git commit записує не «всі змінені файли», а саме те, що лежить в індексі.

git add app/Models/User.php      # додати файл в індекс
git add .                        # усі зміни в поточному каталозі
git status                       # що в індексі, що змінено, що не відстежується
git commit -m "Add email verification"

Навіщо цей проміжний крок:

  • логічні коміти: за день змінено десять файлів, але це дві різні задачі. В індекс додаються файли першої задачі - коміт, потім другої - ще один коміт;
  • контроль: перед комітом видно, що саме потрапить в історію (git diff --staged), і випадковий dd() чи налагоджувальний файл не проскочать;
  • частини файлу: git add -p додає в індекс лише вибрані фрагменти змін.

Важлива деталь: індекс зберігає вміст файлу на момент git add. Якщо після add файл змінити ще раз, у коміт піде стара версія, а нові зміни залишаться в робочому каталозі - git status покаже файл одночасно в двох секціях.

Прибрати з індексу, не втрачаючи змін у файлі:

git restore --staged app/Models/User.php

git commit -a додає в індекс усі зміни вже відстежуваних файлів і комітить їх одним кроком. Нові файли він не підхоплює - їх треба додати через git add явно.

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

.gitignore перелічує шаблони файлів, які Git не повинен відстежувати: залежності, кеші, логи, локальні налаштування.

Синтаксис шаблонів:

# коментар
.env              # файл .env у будь-якому каталозі
/.env             # лише в корені репозиторію
storage/logs/     # каталог (слеш у кінці - лише каталоги)
*.log             # усі файли з розширенням .log
**/cache/*.php    # cache/*.php на будь-якій глибині
!.env.example     # заперечення: цей файл НЕ ігнорувати

Правила, що часто дивують:

  • слеш на початку чи всередині прив'язує шаблон до каталогу, де лежить .gitignore; без слеша шаблон спрацьовує на будь-якому рівні;
  • останнє правило перемагає: порядок має значення, ! скасовує попередній збіг;
  • ! не працює, якщо проігноровано батьківський каталог. Git не заходить у проігнорований каталог, тож файл усередині повернути не вийде:
storage/*          # ігнорувати вміст, але не сам каталог
!storage/.gitkeep  # тепер працює
  • .gitignore може бути в будь-якому підкаталозі - його правила діють відносно цього каталогу (так зроблено в Laravel: storage/framework/cache/.gitignore).

Де ще задаються виключення:

Файл Для чого
.gitignore у репозиторії спільне для команди: vendor/, node_modules/, .env
.git/info/exclude лише для вас у цьому репозиторії, не комітиться
глобальний файл (core.excludesFile) ваші персональні файли для всіх проєктів: .DS_Store, .idea/
git config --global core.excludesFile ~/.gitignore_global

Файли редактора й ОС краще тримати в глобальному списку, а не в .gitignore кожного проєкту.

Перевірити, яке правило спрацювало:

git check-ignore -v storage/logs/laravel.log
# storage/logs/.gitignore:1:*   storage/logs/laravel.log

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

git status показує стан файлів відносно індексу й останнього коміту:

On branch main
Changes to be committed:            ← в індексі, піде в коміт
  modified:   app/Models/User.php

Changes not staged for commit:      ← змінено, але не додано
  modified:   routes/web.php

Untracked files:                    ← нові, Git їх ще не відстежує
  app/Actions/SendInvite.php

Компактний формат зручніший для щоденної роботи:

git status -sb
# ## main...origin/main [ahead 1]
# M  app/Models/User.php      ← ліва колонка: індекс
#  M routes/web.php           ← права колонка: робочий каталог
# MM config/app.php           ← змінено і в індексі, і після нього
# ?? app/Actions/SendInvite.php

Три порівняння git diff:

Команда Що з чим порівнює
git diff робочий каталог з індексом - те, що ще не додано
git diff --staged (--cached) індекс з останнім комітом - що піде в коміт
git diff HEAD робочий каталог з останнім комітом - усі зміни разом

Типова плутанина: після git add команда git diff «нічого не показує». Зміни нікуди не зникли - вони в індексі, і їх видно через git diff --staged.

Корисні варіанти:

git diff --stat                 # лише список файлів і кількість рядків
git diff --word-diff            # зміни по словах - зручно для тексту й документації
git diff main..feature -- app/  # між гілками, лише каталог app
git diff -w                     # ігнорувати зміни пробілів

Перед кожним комітом корисна звичка - переглянути git diff --staged: саме цей вивід побачать рецензенти.

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

Повідомлення коміту читають через місяці: у git log, git blame, при пошуку помилки. «fix», «wip», «правки» нічого не пояснюють.

Структура доброго повідомлення:

Limit login attempts per email and IP          ← заголовок до ~50-72 символів

Brute force attempts were spread across IPs,   ← порожній рядок, потім тіло
so the per-IP limiter alone did not stop them.
Key the limiter by email and IP together.

Fixes #142                                     ← посилання на задачу

Правила:

  • заголовок - коротко, у наказовому способі («Add», «Fix», а не «Added»), без крапки в кінці;
  • тіло пояснює чому і що саме, а не «як» - як видно з diff;
  • один коміт - одна логічна зміна: якщо в повідомлення проситься «і ще», комітів має бути два.

Conventional Commits - угода про формат заголовка:

<тип>(<область>): <опис>

feat(auth): add two-factor authentication
fix(billing): round VAT before summing invoice lines
refactor(orders): extract shipping calculator
docs: describe queue configuration
feat(api)!: remove v1 endpoints

Основні типи: feat (нова можливість), fix (виправлення), docs, refactor, test, chore, perf, ci, build. ! після типу чи рядок BREAKING CHANGE: у футері позначають несумісну зміну.

Що дає формат:

  • автоматичний changelog і примітки до релізу (release-please, semantic-release);
  • семантичне версіювання: fix - patch, feat - minor, breaking change - major;
  • історію легко фільтрувати: git log --oneline --grep '^feat'.

Перевірка формату - commitlint у хуку commit-msg чи в CI. Головне - щоб угоду дотримувалась уся команда, а не окремі люди.

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

git stash відкладає незакомічені зміни й повертає робочий каталог до стану останнього коміту. Типова ситуація: ви посеред задачі, а треба терміново перемкнутися на іншу гілку й виправити помилку.

git stash push -m "half-done invoice export"   # відкласти
git switch hotfix                              # працювати деінде
git switch feature/export
git stash pop                                  # повернути зміни

Що потрапляє в stash за замовчуванням:

  • зміни у відстежуваних файлах (і в індексі, і в робочому каталозі);
  • нові невідстежувані файли - ні. Для них -u (--include-untracked), для проігнорованих теж - -a (--all).
git stash -u

Робота зі списком:

git stash list
# stash@{0}: On feature/export: half-done invoice export
# stash@{1}: WIP on main: 4f2a1c3 Fix typo

git stash show -p stash@{1}   # що всередині
git stash drop stash@{1}      # видалити

apply проти pop:

git stash apply git stash pop
застосовує зміни так так
видаляє запис зі списку ні так, якщо застосування пройшло без конфліктів
  • apply зручний, коли ті самі зміни треба застосувати в кількох гілках;
  • pop - звичайний випадок «відклав і повернув»;
  • при конфлікті pop запис не видаляє - після розв'язання конфлікту його треба прибрати вручну через git stash drop.

Корисне:

  • git stash push -- app/Models/User.php - відкласти лише вказані файли;
  • --staged - відкласти лише те, що в індексі;
  • git stash branch new-branch - створити гілку від коміту, на якому зроблено stash, і застосувати зміни там. Рятує, коли stash не накладається на поточний код.

Не перетворюйте stash на сховище: записи без опису через тиждень неможливо зрозуміти. Довгу незавершену роботу краще закомітити в окрему гілку.

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

Каталог .git - це і є репозиторій. Робочий каталог лише показує одну з версій. Скопіюйте .git - і отримаєте всю історію; видаліть - і залишаться тільки поточні файли без історії.

.git/
├── HEAD            ← на що зараз вказує HEAD (зазвичай ref: refs/heads/main)
├── config          ← налаштування цього репозиторію, remotes, гілки
├── index           ← індекс (staging area), бінарний файл
├── objects/        ← база об'єктів: blob, tree, commit, tag
│   ├── 1a/2485...  ← окремі стиснені об'єкти (loose objects)
│   └── pack/       ← упаковані об'єкти (packfiles)
├── refs/
│   ├── heads/      ← локальні гілки
│   ├── remotes/    ← віддалені гілки (origin/main)
│   └── tags/       ← теги
├── packed-refs     ← багато ref-ів одним файлом
├── logs/           ← reflog: історія переміщень HEAD і гілок
├── hooks/          ← скрипти хуків (*.sample - приклади)
└── info/exclude    ← персональні ігноровані шаблони

Найважливіше:

  • objects/ - увесь вміст: кожна версія кожного файлу, кожен каталог, кожен коміт. Імена файлів - хеші вмісту, перші два символи хешу - назва підкаталогу;
  • refs/ і packed-refs - імена: гілки й теги - це лише файли з хешем коміту;
  • HEAD - де ви зараз;
  • index - що піде в наступний коміт;
  • logs/ - страховка: звідси git reflog відновлює «втрачені» коміти.

Що можна побачити самостійно:

cat .git/HEAD
cat .git/refs/heads/main          # хеш останнього коміту (якщо не упаковано)
find .git/objects -type f | head
git count-objects -vH             # скільки об'єктів і скільки вони займають

Чого не робити:

  • не редагувати файли в .git вручну без розуміння - для цього є команди (git update-ref, git config);
  • не комітити .git іншого репозиторію в свій (вкладені репозиторії - через підмодулі);
  • не синхронізувати .git через Dropbox чи iCloud - одночасний запис з двох машин псує репозиторій.

git worktree і підмодулі використовують файл .git замість каталогу - у ньому лише шлях до справжнього каталогу репозиторію.

Докладніше в документації: Pro Git: plumbing і porcelain

Перемикання гілки (git switch чи git checkout) - це три кроки:

  1. порівняти дерева: Git бере tree поточного коміту й tree цільового коміту і визначає, які файли відрізняються;
  2. оновити індекс і робочий каталог: змінені файли переписуються, відсутні в цільовій гілці - видаляються, нові - створюються. Однакові файли не чіпаються взагалі - саме тому перемикання між схожими гілками миттєве навіть у великому проєкті;
  3. оновити HEAD: записати ref: refs/heads/<гілка>.

Незакомічені зміни переносяться разом з вами. Якщо ви змінили файл, а в цільовій гілці цей файл такий самий, як у поточній, - Git просто залишить вашу зміну. Тому «я почав роботу не в тій гілці» виправляється простим git switch -c правильна-гілка - зміни перейдуть.

Коли Git відмовляється:

error: Your local changes to the following files would be overwritten by checkout:
	config/services.php
Please commit your changes or stash them before you switch branches.
Aborting

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

Те саме для невідстежуваних файлів:

error: The following untracked working tree files would be overwritten by checkout:
	app/Actions/Export.php

У цільовій гілці є файл з таким шляхом, а у вас лежить невідстежуваний файл з тим самим іменем.

Варіанти:

  • закомітити зміни (можна тимчасовий коміт в поточній гілці);
  • git stash (з -u для невідстежуваних), перемкнутися, потім git stash pop там, де потрібно;
  • git switch -m гілка - спробувати злити ваші зміни з версією цільової гілки (можуть виникнути конфлікти);
  • відкинути зміни - git restore, якщо вони не потрібні.

Чого не варто робити - git checkout -f / git switch --discard-changes без розуміння: це перемикання з безповоротним знищенням незакомічених змін.

Невідстежувані й проігноровані файли (vendor/, .env) переживають перемикання - Git їх не чіпає. Тому після переходу на стару гілку vendor/ може не відповідати її composer.lock: потрібен composer install.

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

Git відстежує вміст файлів, а не каталоги. Каталог існує в репозиторії лише як tree-об'єкт, і tree створюється тільки тоді, коли в ньому є хоча б один файл. Порожній каталог нічого не додає до дерева - тому git add empty/ нічого не робить, а після клонування його немає.

Як зберегти порожній каталог - покласти в нього файл:

touch storage/logs/.gitkeep

.gitkeep - лише угода, а не особливий файл для Git. Laravel використовує інший прийом - .gitignore всередині каталогу:

# storage/logs/.gitignore
*
!.gitignore

Каталог існує в репозиторії (завдяки цьому файлу), а його вміст ігнорується.

Права файлів - лише кілька режимів. Tree зберігає для кожного запису режим, ім'я і хеш:

git ls-tree HEAD
# 100644 blob 7898192...   a.txt       ← звичайний файл
# 100755 blob 1a24852...   run.sh      ← виконуваний файл
# 120000 blob 8d14cbf...   link        ← символьне посилання
# 040000 tree 3c4e9cd...   app         ← каталог
# 160000 commit 9f2b1e0... vendor/pkg  ← підмодуль (gitlink)
Режим Значення
100644 звичайний файл
100755 виконуваний файл
120000 symlink - blob містить шлях, на який він вказує
040000 каталог (tree)
160000 підмодуль - посилання на коміт іншого репозиторію

Що Git не зберігає: власника, групу, права на запис для групи чи інших, дату зміни. Після клонування файли отримують власника й поточну дату, а права - за umask системи.

Типова проблема - «змінений» файл без змін у вмісті:

old mode 100644
new mode 100755

Хтось виконав chmod +x, або файлова система (Windows, змонтований диск) не підтримує біт виконання. Якщо зміни прав не мають значення для проєкту:

git config core.fileMode false

А щоб справді зробити скрипт виконуваним у репозиторії на системі без підтримки прав - git update-index --chmod=+x deploy.sh.

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

Хеш коміту обчислюється з усього вмісту коміту:

git cat-file -p HEAD
# tree 3c4e9cd789d88d8d89c1073707c3585e41b0e614
# parent 84ba0356e6199a1cb8a555fef6d09aebe1c203f1
# author Olena <olena@example.com> 1759500000 +0300
# committer Olena <olena@example.com> 1759500000 +0300
#
# Add invoice export

У нього входять хеш дерева (знімок усіх файлів) і хеш батьківського коміту. А хеш батька, у свою чергу, залежить від його батька - і так до першого коміту.

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

  • один хеш гарантує всю історію: якщо у вас і в колеги main вказує на той самий хеш, у вас ідентичні всі файли й уся історія до цього моменту;
  • непомітно підмінити старий коміт чи файл неможливо - зміниться хеш, і це видно;
  • переписування історії (rebase, commit --amend) завжди створює нові коміти з новими хешами - звідси конфлікти з колегами, які вже мають старі.

Чому коміти з однаковим вмістом мають різні хеші: у коміті є час і автор. Два однакові git commit з різницею в секунду - різні коміти. Тому cherry-pick одного коміту у дві гілки дає два різні хеші.

Перевірка цілісності - git fsck:

git fsck
git fsck --full --strict

Перевіряє, що кожен об'єкт відповідає своєму хешу, всі посилання (з коміту на tree, з tree на blob-и) ведуть на існуючі об'єкти, і повідомляє про пошкоджені, відсутні й недосяжні об'єкти.

Де це корисно:

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

Обмеження: хеш захищає від випадкових пошкоджень і непомітної підміни, але не доводить авторство - ім'я й пошту в коміті може вписати будь-хто. Для цього існують підписані коміти.

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

Кожен коміт зберігає посилання на батьківські коміти. Разом вони утворюють спрямований ациклічний граф (DAG):

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

Скільки батьків може мати коміт:

Батьків Що це
0 кореневий коміт - перший у репозиторії
1 звичайний коміт
2 merge-коміт - результат злиття двох гілок
3+ octopus merge - злиття кількох гілок одночасно (рідко)
git cat-file -p HEAD   # merge-коміт
# tree ...
# parent 99fe6a1...     ← перший батько: гілка, в яку зливали (main)
# parent 5b8c2d0...     ← другий батько: гілка, яку зливали (feature)

Порядок батьків має значення: перший батько - це «основна лінія». git log --first-parent показує історію main лише з merge-комітів, без внутрішніх комітів кожної гілки - зручно бачити, які фічі й коли потрапили в основну гілку.

Подивитися граф:

git log --graph --oneline --all
# *   23933de Merge branch 'feature'
# |\
# | * 5b8c2d0 Add export
# * | 99fe6a1 Fix typo
# |/
# * 84ba035 Init

Що випливає з графової моделі:

  • гілка - лише вказівник на одну вершину графа; «вміст гілки» - усі коміти, досяжні з неї по батьках;
  • спільний предок (merge base) двох гілок - найближча вершина, досяжна з обох: від неї Git рахує зміни при злитті (git merge-base main feature);
  • «чи злито гілку» = чи досяжний її коміт з main (git branch --merged);
  • merge-коміт не містить «різниці» - як і будь-який коміт, він зберігає повний знімок, а зміни Git показує, порівнюючи з батьками.

Докладніше в документації: Pro Git: розгалуження й злиття

Pull request (у GitLab - merge request) - це пропозиція влити зміни з однієї гілки в іншу. Навколо неї відбувається все обговорення: рев'ю коду, коментарі до рядків, результати CI, затвердження. Сам Git про pull request нічого не знає - це функція платформи (GitHub, GitLab, Bitbucket).

Навіщо потрібен опис: рев'юер бачить диф, але не бачить, навіщо зміна зроблена, які варіанти відкинуто і як її перевірити. Добрий опис економить кілька раундів запитань.

Шаблон опису:

## Що і навіщо
Додає експорт вакансій у CSV для адмінки. Менеджери зараз копіюють
таблицю вручну.

Closes #412

## Як зроблено
- `VacancyExport` формує файл потоково, щоб не тримати 50k рядків у пам'яті
- експорт іде в черзі, посилання приходить листом

## Як перевірити
1. Адмінка → Вакансії → «Експорт»
2. Дочекатися листа, відкрити файл

## На що звернути увагу
Не впевнений щодо формату дат - зараз ISO 8601.

Що робить опис добрим:

  • проблема, а не перелік файлів - «що змінилося» видно в дифі, а «чому» - ні;
  • посилання на задачу (Closes #412) - контекст і автоматичне закриття задачі;
  • інструкція з перевірки - рев'юер може відтворити поведінку;
  • скріншоти чи відео для змін інтерфейсу;
  • ризики й відкриті питання - куди дивитися уважніше;
  • заголовок як у доброго коміту - коротко про суть: «Експорт вакансій у CSV», а не «fix» чи «updates».

Шаблон для всієї команди - файл .github/pull_request_template.md: GitHub підставляє його в кожен новий pull request, і структура опису стає однаковою.

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

Великий pull request рев'ю не проходить - він проходить «апрув». На 50 рядках рев'юер знаходить проблеми, на 2000 - гортає й пише «LGTM». Якість рев'ю падає разом з розміром.

Чому маленькі PR кращі:

  • швидше рев'ю: 15 хвилин легко знайти між задачами, дві години - ні. Великі PR лежать днями;
  • якісніше рев'ю: у фокусі одна ідея, помилки помітніші;
  • менше конфліктів: гілка живе годину чи день, а не тиждень;
  • простіший відкат: якщо щось зламалося, відкочується одна невелика зміна;
  • зрозуміла історія: кожен PR - окремий логічний крок.

Орієнтир: до кількох сотень рядків змістовних змін. Згенеровані файли, lock-файли й міграції з даними рахуються окремо.

Як розбивати велику задачу:

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

Чого уникати:

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

Якщо PR все ж великий - напишіть в описі, з чого почати читання, і проведіть рев'юера за ключовими файлами.

Докладніше в документації: GitHub: як допомогти рев'юерам

Draft (чернетка) - стан pull request, який означає «ще не готово до рев'ю». Чернетку видно команді, на неї працює CI, її можна коментувати, але:

  • влити її не можна, доки автор не позначить її готовою (Ready for review);
  • власників коду (CODEOWNERS) не запитують на рев'ю автоматично - запит надходить, коли PR стає готовим.
gh pr create --draft --title "Експорт вакансій у CSV"
gh pr ready 412        # позначити готовим до рев'ю

Коли відкривати draft:

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

Етикет:

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

Альтернатива у старих процесах - префікс WIP: у заголовку. Draft кращий: це стан, який платформа розуміє й поважає (блокує злиття, не тривожить рев'юерів), а не домовленість, яку легко пропустити.

Докладніше в документації: GitHub: draft pull requests

GitHub розпізнає ключові слова в описі pull request (і в повідомленнях комітів) і пов'язує PR із задачею:

Closes #412
Fixes #418, resolves #420
Fixes acme/api#77

Ключові слова: close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved. Регістр не важливий, двокрапка після слова допускається.

Що відбувається:

  • задача показує, що над нею працюють, і містить посилання на PR;
  • після злиття PR задача закривається автоматично;
  • можна вказати задачу з іншого репозиторію: owner/repo#номер.

Важливий нюанс: ключові слова працюють, лише якщо PR спрямовано в гілку за замовчуванням (зазвичай main). PR у develop чи релізну гілку з Closes #412 не створить зв'язку й не закриє задачу. Для таких випадків зв'язок створюють вручну на бічній панелі PR (розділ Development).

Згадка без закриття: просто #412 чи «див. #412» створює перехресне посилання, але задачу не закриває. Це доречно, коли PR лише частина роботи:

Частина #412: міграція й модель. Інтерфейс - окремим PR.

Практичні поради:

  • одна задача - одна причина PR: якщо PR закриває п'ять задач, це, мабуть, кілька різних змін;
  • для задач з трекера поза GitHub (Jira, Linear) - номер задачі в назві гілки чи заголовку (ABC-123), а інтеграція трекера підхопить зв'язок;
  • автопосилання (Settings → Autolink references) перетворюють ABC-123 у тексті на посилання на зовнішній трекер.

Докладніше в документації: GitHub: зв'язок pull request із задачею

Рев'ю на GitHub - це набір коментарів, які відправляються разом з підсумковим рішенням. Поки рев'ю не відправлене, коментарі видно лише вам.

Три варіанти завершення рев'ю:

Рішення Що означає
Comment загальний відгук без схвалення чи блокування
Approve зміни можна вливати
Request changes є проблеми, які треба виправити до злиття

Якщо в репозиторії налаштовано обов'язкове схвалення, Request changes блокує злиття, доки рецензент не змінить рішення чи рев'ю не відхилять (dismiss).

Коментарі до рядків прив'язуються до конкретного місця дифу - можна виділити кілька рядків і прокоментувати весь фрагмент.

Suggestion - запропонувати готову правку:

```suggestion
$vacancies = Vacancy::query()->with('company')->latest()->paginate(20);
```

Автор бачить диф пропозиції й натискає Commit suggestion - правка стає комітом у гілці PR. Кілька пропозицій можна застосувати одним комітом через Add suggestion to batch.

Коли suggestion доречний: друкарська помилка, перейменування, очевидний однорядковий фікс. Для складніших змін краще пояснити ідею словами - автор знає контекст краще.

Корисні звички:

  • збирати коментарі в одне рев'ю (Start a review), а не відправляти по одному - автор отримує одне сповіщення, а не двадцять;
  • позначати Viewed переглянуті файли - при оновленні PR GitHub покаже, які з них змінилися;
  • Resolve conversation - коли питання закрите; зазвичай це робить той, хто його відкрив, або автор після виправлення;
  • повторний запит рев'ю (Re-request review) після виправлень - рецензент отримає сповіщення.

Докладніше в документації: GitHub: рев'ю pull request

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

Рівні
Junior 35 Middle 35 Senior 30

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