Middle: питання на співбесіді з теми «Основи й щоденна робота»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
5 питань
Git читає конфігурацію з кількох файлів. Пізніший рівень перекриває раніший:
| Рівень | Файл | Прапорець |
|---|---|---|
| system | /etc/gitconfig (чи в каталозі встановлення) |
--system |
| global | ~/.gitconfig чи ~/.config/git/config |
--global |
| local | .git/config репозиторію |
--local (за замовчуванням) |
| worktree | .git/config.worktree |
--worktree |
| команда | git -c key=value ... |
- |
git config --global user.name "Olena Kovalenko"
git config user.email olena@company.com # лише цей репозиторій
git config --list --show-origin # усі значення і звідки вони
git config --show-origin --get user.email
--show-origin - перший інструмент, коли «налаштування не працює»: видно, який файл перекрив значення.
Умовні включення - різні налаштування для роботи й особистих проєктів:
# ~/.gitconfig
[user]
name = Olena Kovalenko
email = olena@personal.dev
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
# ~/.gitconfig-work
[user]
email = olena@company.com
signingkey = ~/.ssh/work_ed25519.pub
Усі репозиторії в ~/work/ автоматично отримують робочу пошту - більше ніяких комітів з особистою адресою в корпоративному репозиторії.
Умови includeIf:
gitdir:- шлях до репозиторію (gitdir/i:- без урахування регістру);onbranch:- поточна гілка;hasconfig:remote.*.url:- адреса віддаленого репозиторію, наприклад усі репозиторії зgithub.com/company/**.
Що важливо:
- слеш у кінці
gitdir:~/work/означає «цей каталог і все всередині»; .git/configне комітиться і не поширюється через клон - спільні налаштування команди передаються інакше (документація, скрипт налаштування,.gitattributesі.editorconfigу репозиторії);- у CI змінні оточення
GIT_AUTHOR_NAME,GIT_COMMITTER_EMAILперекривають конфігурацію.
Буває, що в одному файлі змішалися дві задачі: виправлення помилки й рефакторинг. git add -p (--patch) дозволяє додати в індекс лише окремі фрагменти (hunks) змін і зробити з них два чисті коміти.
git add -p app/Services/InvoiceService.php
Git показує кожен фрагмент і питає, що з ним робити:
@@ -42,7 +42,7 @@ public function total(): int
- return $this->lines->sum('price');
+ return $this->lines->sum(fn ($line) => $line->price * $line->quantity);
(1/3) Stage this hunk [y,n,q,a,d,s,e,?]?
Основні відповіді:
| Клавіша | Дія |
|---|---|
y / n |
додати / пропустити фрагмент |
s |
розбити фрагмент на менші (якщо між змінами є незмінені рядки) |
e |
відредагувати фрагмент вручну - для змін у сусідніх рядках |
a / d |
додати / пропустити всі решта фрагменти файлу |
q |
вийти |
Типовий процес:
git add -p # обрати фрагменти виправлення
git diff --staged # перевірити, що в індексі
git commit -m "Fix invoice total for multiple quantities"
git add -p # тепер рефакторинг
git commit -m "Extract line total calculation"
Той самий режим є в інших командах:
git restore -p- відкинути частину змін у робочому каталозі;git restore --staged -p- прибрати частину з індексу;git stash push -p- відкласти лише вибрані фрагменти;git commit -p- обрати фрагменти й одразу закомітити.
Про що пам'ятати:
- нові файли
add -pне показує, бо Git їх ще не відстежує. Спершуgit add -N файл(intent-to-add) - тоді вміст з'явиться як фрагменти; - проміжний стан може не працювати: закомічена половина змін не перевірялася окремо. Перед пушем корисно прогнати тести на кожному коміті чи хоча б на останньому;
- IDE (PhpStorm, VS Code) дають той самий механізм через галочки біля рядків - під капотом те саме часткове додавання в індекс.
git checkout історично робить дві принципово різні речі:
git checkout feature # перемкнути гілку
git checkout -- config.php # відкинути зміни у файлі (безповоротно!)
Одна команда і для безпечної операції, і для руйнівної. git checkout name перемкне гілку, якщо гілка name існує, а якщо ні, але є такий файл - мовчки перезапише файл. Саме через це в Git 2.23 з'явилися дві вузькі команди.
git switch - лише гілки:
git switch main
git switch -c feature/export # створити й перемкнутися
git switch -c fix origin/fix # нова локальна гілка від віддаленої
git switch - # повернутися на попередню гілку
git switch --detach v2.4.0 # явно перейти в detached HEAD
git restore - лише файли:
git restore config.php # відкинути зміни в робочому каталозі
git restore --staged config.php # прибрати з індексу, зміни лишаються
git restore --source=HEAD~3 config.php # взяти версію файлу з іншого коміту
git restore --staged --worktree . # повністю повернути все до HEAD
Відповідність старих і нових команд:
| Було | Стало |
|---|---|
git checkout branch |
git switch branch |
git checkout -b new |
git switch -c new |
git checkout -- file |
git restore file |
git reset HEAD file |
git restore --staged file |
git checkout abc123 -- file |
git restore --source=abc123 file |
Чому це важливо:
- намір явний:
switchніколи не чіпає незакомічені зміни у файлах без потреби, аrestoreніколи не перемикає гілку; - detached HEAD не трапляється випадково:
git switch v2.4.0відмовиться працювати з тегом без--detach, тоді якcheckoutмовчки перейде в detached HEAD; git statusсам підказує нові команди («use git restore...»).
git checkout нікуди не дівся і працює, як раніше, - у скриптах і старих інструкціях він зустрічатиметься ще довго. Але для щоденної роботи switch і restore безпечніші.
Обережно: git restore файл так само безповоротно відкидає незакомічені зміни, як і checkout --. Їх немає ні в reflog, ні в stash.
.gitignore діє лише на невідстежувані файли. Якщо файл уже закомічено, Git продовжує відстежувати його зміни, хоч би що було написано в .gitignore.
Типова ситуація: .env чи .idea/ випадково потрапили в репозиторій, потім їх додали в .gitignore - а git status все одно показує зміни.
Рішення - прибрати файл з індексу, не видаляючи з диска:
git rm --cached .env
git rm -r --cached .idea/
git commit -m "Stop tracking local environment files"
--cachedвидаляє файл лише з індексу - на диску він лишається;- після коміту файл стає невідстежуваним, і тепер
.gitignoreна нього діє.
Пастка для команди: у колег після git pull цей файл буде видалено з диска, бо для Git коміт означає «файл видалено». Їхній локальний .env зникне. Попередьте команду або попросіть зберегти копію перед оновленням.
Чим відрізняються варіанти:
| Команда | Індекс | Диск |
|---|---|---|
git rm file |
видаляє | видаляє |
git rm --cached file |
видаляє | залишає |
rm file |
залишає (до git add) |
видаляє |
Масово привести репозиторій у відповідність з .gitignore:
git rm -r --cached .
git add .
git commit -m "Apply .gitignore"
Перед комітом обов'язково перегляньте git status - так можна випадково прибрати потрібні файли.
Перейменування - git mv:
git mv app/Helpers.php app/Support/Helpers.php
Це те саме, що mv + git rm старого + git add нового. Git не зберігає факт перейменування - він визначає його при порівнянні за схожістю вмісту.
Якщо файл містив секрет - git rm --cached прибирає його лише з наступних комітів. В історії він лишається, і секрет треба вважати скомпрометованим: змінити ключі, а історію чистити окремими інструментами.
git clean видаляє з робочого каталогу файли, які Git не відстежує: тимчасові файли, результати збирання, згенерований код, залишки експериментів.
Головне - ці файли не можна відновити засобами Git. Їх немає в жодному коміті, reflog чи stash. Тому git clean за замовчуванням навіть відмовляється працювати без явного прапорця (clean.requireForce=true).
Безпечний порядок - спершу подивитися:
git clean -n # dry run: що буде видалено
git clean -nd # разом з невідстежуваними каталогами
git clean -f # видалити файли
git clean -fd # файли й каталоги
Прапорці:
| Прапорець | Що робить |
|---|---|
-n |
лише показати (dry run) |
-f |
справді видалити |
-d |
включно з каталогами |
-x |
також проігноровані файли (.env, vendor/, node_modules/) |
-X |
лише проігноровані файли |
-i |
інтерактивний вибір |
-e <шаблон> |
додатково виключити шаблон |
-x - найнебезпечніший прапорець. git clean -fdx у Laravel-проєкті видалить .env, vendor/, node_modules/, storage/*.key, локальну базу SQLite - усе, що ігнорується. Корисно для «чистого» збирання в CI, але вдома варто запускати лише після -n.
git clean -fdx -e .env -n # усе, окрім .env, - спершу перевірка
Інтерактивний режим зручний, коли більшість файлів треба видалити, а кілька - залишити:
git clean -id
Типові сценарії:
- повернути репозиторій до стану щойно клонованого:
git restore --staged --worktree .(відстежувані) +git clean -fd(невідстежувані); - прибрати лише результати збирання, не чіпаючи нові вихідні файли:
git clean -fX; - CI на повторно використовуваному runner-і -
git clean -ffdxперед збиранням (подвійний-fвидаляє й вкладені репозиторії).
Альтернатива без ризику: якщо не впевнені, git stash -u прибере невідстежувані файли, але збереже їх у stash.