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

Питання на співбесіді: Основи й щоденна робота

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

14 питань

У 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 читає конфігурацію з кількох файлів. Пізніший рівень перекриває раніший:

Рівень Файл Прапорець
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 config: умовні включення

Буває, що в одному файлі змішалися дві задачі: виправлення помилки й рефакторинг. 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 add: інтерактивний режим

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.

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

.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 rm

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.

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

Зазвичай HEAD вказує на гілку, а гілка - на коміт:

cat .git/HEAD
# ref: refs/heads/main

Новий коміт пересуває гілку main, а HEAD іде слідом.

Detached HEAD - HEAD вказує напряму на коміт, оминаючи гілку:

git switch --detach v2.4.0     # чи git checkout v2.4.0, git checkout a1b2c3d
cat .git/HEAD
# 9fceb02d0ae598e95dc970b74767f19372d61af8

Коли це відбувається:

  • перехід на тег чи конкретний коміт, щоб подивитися старий стан;
  • git bisect перемикає коміти саме так;
  • під час rebase з зупинками й розв'язання конфліктів;
  • CI зазвичай клонує конкретний коміт у detached HEAD;
  • підмодулі - завжди на конкретному коміті.

Небезпека: у цьому стані можна комітити, але на нові коміти не вказує жодна гілка. Після перемикання на main вони стають недосяжними:

Warning: you are leaving 2 commits behind, not connected to
any of your branches:
  3e1f2a4 Try new cache driver

Через якийсь час (за замовчуванням недосяжні записи reflog живуть 30 днів) git gc їх видалить.

Як зберегти роботу:

# ще в detached HEAD - створити гілку на поточному коміті
git switch -c experiment/cache-driver

# уже перемкнулися - знайти коміт і створити гілку
git reflog
git branch experiment/cache-driver 3e1f2a4

Як помітити стан: git status пише HEAD detached at v2.4.0, а більшість промптів оболонки показують хеш замість назви гілки.

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

  • для експериментів зі старою версією одразу створюйте гілку: git switch -c try-fix v2.4.0;
  • git switch без --detach не перейде на тег - захист від випадкового detached HEAD;
  • у скриптах CI, які щось комітять (наприклад, оновлення changelog), явно створюйте чи перемикайте гілку перед комітом, інакше git push не матиме що відправити.

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

~ і ^ рухаються по батьках коміту, але по-різному:

  • ~n - n кроків назад по першому батькові: HEAD~1 - батько, HEAD~3 - прапрадід;
  • ^n - n-й батько коміту. Має сенс для merge-комітів, у яких батьків два: HEAD^1 - гілка, у яку зливали, HEAD^2 - гілка, яку зливали.
        D---E  (feature)
       /     \
  A---B---C---M  (main, HEAD)

HEAD~1 = HEAD^ = HEAD^1 = C
HEAD^2 = E
HEAD~2 = B
HEAD^2~1 = D

Для звичайного коміту з одним батьком HEAD~1 і HEAD^ однакові - різниця видна лише на merge-комітах.

Інші способи назвати коміт:

main@{yesterday}       # де була main вчора (за reflog)
@{-1}                  # попередня гілка
@{u}                   # upstream поточної гілки
HEAD^{tree}            # дерево коміту
:/fix invoice          # останній коміт з таким текстом у повідомленні
v2.4.0^{commit}        # коміт, на який вказує тег

Діапазони:

Запис Що означає
A..B коміти, досяжні з B, але не з A
A...B коміти, досяжні з A або B, але не з обох (симетрична різниця)
^A B те саме, що A..B
git log main..feature          # що є у feature і ще не злито в main
git log feature..main          # що з'явилося в main, поки ви працювали
git log --left-right --oneline main...feature   # обидві сторони з позначками < і >
git log origin/main..HEAD      # що ви ще не запушили

Пастка: .. і ... у git diff означають інше:

  • git diff A..B - те саме, що git diff A B: порівняння двох знімків;
  • git diff A...B - зміни в B від спільного предка з A. Саме так GitHub показує diff pull request-у: лише зміни гілки, без того, що за цей час з'явилося в main.

Тому git diff main...feature - правильний спосіб побачити «що змінює моя гілка», а git diff main feature покаже ще й чужі зміни в main з протилежним знаком.

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

Запис stash - це звичайні коміти, на які вказує ref refs/stash, а список stash@{n} - це reflog цього ref-а.

Структура одного запису:

      .----W    ← робочий каталог (сам запис stash@{0})
     /    /|
    H----I |    H - HEAD на момент stash, I - стан індексу
           U    U - невідстежувані файли (лише з -u чи -a)
  • W - merge-коміт з батьками H, I і, якщо був -u, - U;
  • окремий коміт для індексу дозволяє git stash apply --index відновити, що саме було в індексі.
git cat-file -p stash@{0}
# tree ...
# parent 84ba035...   ← H
# parent 48c2a34...   ← I
# parent 84d625d...   ← U (untracked files on main)
git show stash@{0}^3   # невідстежувані файли зі stash

Що з цього випливає:

  • git stash drop і успішний pop видаляють лише запис у reflog refs/stash. Самі коміти лишаються в базі об'єктів, доки їх не прибере git gc;
  • до stash можна звертатися як до будь-якого коміту: git diff stash@{0}^1 stash@{0}, git restore --source=stash@{0} -- file.php.

Відновлення видаленого stash:

Якщо щойно виконали pop чи drop, Git друкує хеш:

Dropped refs/stash@{0} (5c3e8a7f...)
git stash apply 5c3e8a7f

Якщо хеш загублено - шукати недосяжні коміти-сироти:

git fsck --no-reflog --unreachable | awk '/commit/ {print $3}' \
  | xargs git log --no-walk --merges --format='%h %ci %s' | grep 'WIP on\|On '

Коміти stash - merge-коміти з повідомленнями «WIP on main» чи «On main: опис». Знайдений хеш - git stash apply <хеш> чи git branch rescue <хеш>.

Обмеження: після git gc (Git запускає його й автоматично) недосяжні об'єкти старші за gc.pruneExpire (за замовчуванням 2 тижні) видаляються остаточно.

git stash branch name stash@{1} - корисний для старих записів: створює гілку від коміту H, застосовує stash і видаляє запис, тож конфліктів з новим кодом не буде.

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

Псевдоніми (aliases) скорочують часті команди:

# ~/.gitconfig
[alias]
    st = status -sb
    co = switch
    lg = log --graph --oneline --decorate --all
    last = log -1 HEAD --stat
    unstage = restore --staged
    amend = commit --amend --no-edit
    fixup = "!f() { git commit --fixup=$1 && GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash $1~1; }; f"
    gone = "!git fetch -p && git branch -vv | awk '/: gone]/ {print $1}' | xargs -r git branch -D"
  • звичайний псевдонім підставляє аргументи команди git;
  • ! на початку - виконати команду оболонки, з функцією для аргументів. Такі команди виконуються з кореня репозиторію;
  • git gone вище видаляє локальні гілки, чиї віддалені версії вже видалено.

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

# ~/bin/git-pr-checkout
#!/bin/sh
git fetch origin "pull/$1/head:pr-$1" && git switch "pr-$1"

Налаштування, що заощаджують час:

[pull]
    rebase = true              # pull без merge-комітів
[push]
    autoSetupRemote = true     # перший push сам створює upstream
[rebase]
    autoStash = true           # stash/unstash навколо rebase
    autoSquash = true          # fixup! коміти автоматично стають на місце
    updateRefs = true          # оновлювати залежні гілки в стеку
[rerere]
    enabled = true             # пам'ятати розв'язання конфліктів
[fetch]
    prune = true               # прибирати видалені віддалені гілки
[diff]
    algorithm = histogram      # зрозуміліші diff-и
    colorMoved = default       # підсвічувати переміщені рядки
[merge]
    conflictStyle = zdiff3     # показувати базову версію в конфліктах
[branch]
    sort = -committerdate      # свіжі гілки першими
[help]
    autocorrect = prompt       # пропонувати виправлення опечаток

Що враховувати:

  • псевдоніми й налаштування персональні: в інструкціях для команди і в скриптах CI використовуйте повні стандартні команди;
  • zdiff3, updateRefs, autoSetupRemote з'явилися у відносно нових версіях Git - перевірте версію на всіх машинах команди;
  • dotfiles-репозиторій з ~/.gitconfig дає однакове середовище на всіх ваших машинах.

Докладніше в документації: Pro Git: псевдоніми