Git за межами основ: Воркфлоу, що економлять години щотижня
Interactive rebase, cherry-pick, bisect, worktrees, порятунок через reflog та стратегії гілкування, які реально працюють. Git-команди, якими я користуюся щодня, а більшість розробників не знає.
Більшість розробників вивчають п'ять Git-команд і на цьому зупиняються. add, commit, push, pull, merge. Можливо, checkout і branch, якщо почувають себе сміливо. Цього вистачає на перший рік. Потім ваша гілка має 47 комітів з повідомленнями на кшталт «fix» і «wip» і «please work», ви випадково скинули щось, чого не слід було, і витрачаєте 40 хвилин на Stack Overflow, намагаючись скасувати невдалий мердж.
Я використовую Git роками. Не побіжно — інтенсивно. Кілька гілок, кілька репозиторіїв, кілька співпрацівників, цілий день, кожен день. Далі — команди та воркфлоу, якими я реально користуюсь. Не ті, що добре виглядають у туторіалі. Ті, що економлять мені реальний час, щотижня.
Interactive Rebase: Приберіть свій хаос, поки ніхто не бачить#
Ваша гілка має дванадцять комітів. Половина з них — «fix typo». Один каже «undo previous commit». Інший — «actually fix it this time». Ви збираєтесь відкрити PR. Нікому не потрібно бачити цю історію.
Interactive rebase — це спосіб переписати історію вашої гілки перед тим, як поділитися нею. Він дозволяє об'єднувати коміти разом, переформулювати повідомлення, змінювати порядок або видаляти їх повністю.
Основна команда#
git rebase -i HEAD~5Це відкриває редактор з вашими останніми 5 комітами, від найстарішого:
pick a1b2c3d Add user authentication endpoint
pick d4e5f6g Fix typo in auth middleware
pick h7i8j9k Add rate limiting
pick l0m1n2o Fix rate limit bug
pick p3q4r5s Update auth testsКожен рядок починається з команди. Змініть pick на одну з цих:
squash(абоs) — Об'єднати цей коміт з тим, що вище, поєднати повідомленняfixup(абоf) — Те саме, що squash, але відкинути повідомлення цього комітуreword(абоr) — Зберегти коміт, але змінити його повідомленняdrop(абоd) — Видалити цей коміт повністюedit(абоe) — Зупинити rebase на цьому коміті, щоб ви могли його змінити
Реальний сеанс очищення#
Ось що я реально роблю. Та брудна історія вище перетворюється на:
pick a1b2c3d Add user authentication endpoint
fixup d4e5f6g Fix typo in auth middleware
pick h7i8j9k Add rate limiting
fixup l0m1n2o Fix rate limit bug
pick p3q4r5s Update auth testsЗбережіть і закрийте. Тепер у вас три чистих коміти замість п'яти. Виправлення помилки друку складається в коміт автентифікації. Виправлення бага rate limit складається в коміт rate limiting. Ваш ревю'ер PR бачить чистий, логічний прогрес.
Зміна порядку комітів#
Ви можете буквально переставляти рядки. Якщо коміт тестів повинен іти перед комітом rate limiting, просто перемістіть рядок:
pick a1b2c3d Add user authentication endpoint
pick p3q4r5s Update auth tests
pick h7i8j9k Add rate limitingGit переграє ваші коміти в цьому новому порядку. Якщо є конфлікти, він зупиниться і дасть вам їх вирішити.
Скорочення Autosquash#
Якщо ви знаєте, що коміт є виправленням попереднього, позначте це при коміті:
git commit --fixup=a1b2c3dЦе створює коміт з повідомленням fixup! Add user authentication endpoint. Потім при rebase:
git rebase -i --autosquash HEAD~5Git автоматично переставляє fixup-коміти прямо під їхні цілі та позначає їх як fixup. Ви просто зберігаєте і закриваєте. Без ручного редагування.
Я використовую це постійно. Це найшвидший спосіб ітерувати на гілці, зберігаючи фінальну історію чистою.
Золоте правило#
Ніколи не робіть rebase комітів, які вже запушені до спільної гілки. Якщо інші люди базували роботу на цих комітах, переписування історії спричинить реальні проблеми. Робіть rebase своїх власних feature-гілок перед мерджем. Ніколи не робіть rebase main.
Якщо ви вже запушили свою feature-гілку і потрібно зробити rebase:
git push --force-with-leaseПрапорець --force-with-lease безпечніший за --force. Він відмовляється пушити, якщо хтось інший запушив у ту ж гілку з часу вашого останнього fetch. Він не запобігає всім проблемам, але ловить найпоширенішу.
Cherry-Pick: Хірургічне перенесення комітів#
Cherry-pick бере конкретний коміт з однієї гілки та застосовує його до іншої. Не мердж. Не rebase. Просто один коміт, чисто застосований.
Коли я це реально використовую#
Найпоширеніший сценарій: я виправив баг на своїй feature-гілці, але виправлення також потрібно в main або release-гілці прямо зараз. Я не хочу мерджити всю свою feature-гілку. Я хочу лише це одне виправлення.
# Знайти хеш коміту виправлення
git log --oneline feature/user-auth
# a1b2c3d Fix null pointer in session validation
# Переключитися на main і cherry-pick
git checkout main
git cherry-pick a1b2c3dГотово. Виправлення на main як новий коміт з тими ж змінами.
Cherry-Pick без комітування#
Іноді ви хочете застосувати зміни, але не комітити їх ще. Можливо, ви хочете об'єднати кілька cherry-pick в один коміт або трохи модифікувати зміни:
git cherry-pick --no-commit a1b2c3dЗміни стейджені, але не закомічені. Ви можете їх модифікувати, додати більше змін, потім комітити, коли готові.
Cherry-Pick діапазону#
Потрібно кілька послідовних комітів? Використовуйте синтаксис діапазону:
git cherry-pick a1b2c3d..f6g7h8iЦе cherry-pick все після a1b2c3d до та включаючи f6g7h8i. Зверніть увагу, що сам a1b2c3d виключений. Якщо хочете його включити:
git cherry-pick a1b2c3d^..f6g7h8iОбробка конфліктів#
Конфлікти cherry-pick працюють як конфлікти мерджу. Коли один виникає:
# Git скаже вам, що є конфлікт
# Виправте конфліктні файли, потім:
git add .
git cherry-pick --continueАбо якщо ви передумали:
git cherry-pick --abortОдне застереження: cherry-picked коміти створюють нові хеші комітів. Якщо ви пізніше мерджите оригінальну гілку, Git зазвичай достатньо розумний, щоб обробити дублювання. Але якщо ви агресивно cherry-pick між гілками, які врешті зімерджуються, можете побачити неочікувані конфлікти. Використовуйте хірургічно, а не як стратегію мерджу.
Git Bisect: Бінарний пошук багів#
Щось зламалось. Ви знаєте, що воно працювало два тижні тому. Відтоді було 200 комітів. Який зламав?
Ви можете перевіряти кожен коміт вручну. Або можете використати git bisect, який використовує бінарний пошук для знаходження точного коміту-порушника за log2(n) кроків. Для 200 комітів це близько 7-8 перевірок замість 200.
Ручний спосіб#
# Почати bisect
git bisect start
# Позначити поточний коміт як поганий (баг існує тут)
git bisect bad
# Позначити відомий добрий коміт (баг тут не існував)
git bisect good v2.1.0Git переключає на коміт посередині між добрим і поганим. Протестуйте його. Потім:
# Якщо баг існує на цьому коміті:
git bisect bad
# Якщо баг не існує на цьому коміті:
git bisect goodGit звужує діапазон вдвічі кожен раз. Після 7-8 кроків він повідомляє:
a1b2c3d4e5f6g7h is the first bad commit
commit a1b2c3d4e5f6g7h
Author: Some Developer <dev@example.com>
Date: Tue Feb 18 14:23:01 2026 +0300
Refactor session handling to use async middlewareТепер ви знаєте точно, який коміт вніс баг. Коли закінчите:
git bisect resetЦе поверне вас туди, де ви почали.
Автоматизований спосіб (ось де справжня сила)#
Якщо у вас є тест, що може виявити баг, ви можете автоматизувати весь процес:
git bisect start
git bisect bad HEAD
git bisect good v2.1.0
git bisect run npm test -- --grep "session validation"Git автоматично переключатиме коміти, запускатиме тест і позначатиме їх як добрі або погані на основі коду виходу. Нуль означає добрий, не-нуль означає поганий. Відійдіть, поверніться, і він скаже вам точний коміт.
Ви можете використовувати будь-який скрипт:
git bisect run ./test-regression.shДе test-regression.sh це:
#!/bin/bash
npm run build 2>/dev/null || exit 125 # 125 означає "пропустити цей коміт"
npm test -- --grep "session" || exit 1 # 1 означає "поганий"
exit 0 # 0 означає "добрий"Код виходу 125 особливий — він каже bisect пропустити цей коміт (корисно, якщо коміт не компілюється). Це одна з тих можливостей, що здається нішевою, поки вона вам не знадобиться, і тоді вона зберігає вам цілий день.
Реальний сеанс Bisect#
Ось як це виглядає на практиці:
$ git bisect start
$ git bisect bad HEAD
$ git bisect good abc1234
Bisecting: 97 revisions left to test after this (roughly 7 steps)
[def5678...] Commit message here
$ npm test -- --grep "login flow"
# Тести падають
$ git bisect bad
Bisecting: 48 revisions left to test after this (roughly 6 steps)
[ghi9012...] Another commit message
$ npm test -- --grep "login flow"
# Тести проходять
$ git bisect good
Bisecting: 24 revisions left to test after this (roughly 5 steps)
...
# Після ~7 ітерацій:
abc1234def5678ghi is the first bad commitСім кроків, щоб знайти голку в стозі з 200 комітів.
Git Worktrees: Кілька гілок, нуль стешів#
Це найменш використовувана можливість Git. Я впевнений, що більшість розробників не знає про її існування.
Проблема: ви глибоко в feature-гілці. Файли змінені повсюди. Тоді хтось каже «можеш швиденько глянути цей продакшен-баг?» У вас три варіанти:
- Стешити все, переключити гілки, виправити, переключитися назад, попнути стеш. Сподіватися, що нічого не піде не так.
- Комітити свою напівготову роботу з повідомленням «wip». Некрасиво, але функціонально.
- Заклонити репозиторій ще раз в іншу директорію.
Або варіант 4: worktrees.
Що таке Worktree#
Worktree — це друга (або третя, або четверта) робоча директорія, пов'язана з тим самим репозиторієм. Кожен worktree має свою переключену гілку, свої робочі файли, свій індекс. Але вони ділять ті самі .git-дані, тож ви не дублюєте весь репозиторій.
Додавання Worktree#
# Ви на feature/user-auth, глибоко в роботі
# Потрібно виправити баг на main:
git worktree add ../hotfix-session mainЦе створює нову директорію ../hotfix-session з переключеним main. Ваша поточна директорія залишається точно такою, якою була. Нічого стешено, нічого комітнуто, нічого порушено.
cd ../hotfix-session
# Виправити баг
git add .
git commit -m "Fix null pointer in session validation"
git push origin main
cd ../my-project
# Продовжити роботу над своєю фічею, ніби нічого не трапилосьСтворення нової гілки в Worktree#
git worktree add ../hotfix-nav -b hotfix/nav-crash mainЦе створює worktree І створює нову гілку hotfix/nav-crash на основі main.
Керування Worktrees#
# Перелічити всі worktrees
git worktree list
# /home/dev/my-project abc1234 [feature/user-auth]
# /home/dev/hotfix-session def5678 [main]
# Видалити worktree, коли закінчили
git worktree remove ../hotfix-session
# Якщо директорія вже видалена:
git worktree pruneЧому це краще за стеш#
Стеш підходить для швидких переключень контексту. Але worktrees кращі для будь-чого, що займає більше п'яти хвилин:
- Ваша IDE залишається відкритою на вашій feature-гілці. Без переіндексації, без втрати позиції прокрутки.
- Ви можете запускати тести в обох директоріях одночасно.
- Немає ризику конфліктів стешу або забування, що ви стешили.
- Ви можете мати довготривалий dev-сервер в одному worktree та чисту збірку в іншому.
Зазвичай я тримаю два-три активних worktrees: мою основну feature-гілку, worktree main для швидких перевірок, і іноді worktree для ревю, де я перевіряю чийсь PR.
Одне застереження#
Ви не можете мати одну й ту ж гілку переключену в двох worktrees. Це зроблено навмисно — це запобігає конфліктним змінам однієї гілки в двох місцях. Якщо спробуєте, Git відмовить.
Reflog: Кнопка скасування для всього#
Ви зробили hard reset і втратили коміти. Видалили гілку. Зробили rebase і все пішло жахливо не так. Ви думаєте, що ваша робота зникла.
Ні. Git майже ніколи насправді нічого не видаляє. Reflog — ваша страхувальна сітка.
Що таке Reflog#
Кожного разу, коли HEAD переміщується — кожен коміт, checkout, rebase, reset, мердж — Git записує це в reflog. Це лог кожного місця, де був ваш HEAD, по порядку.
git reflogВивід:
a1b2c3d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
f4e5d6c HEAD@{1}: commit: Add payment processing
b7a8c9d HEAD@{2}: commit: Update user dashboard
e0f1g2h HEAD@{3}: commit: Fix auth token refresh
i3j4k5l HEAD@{4}: checkout: moving from feature/payments to mainКожен запис має індекс (HEAD@{0}, HEAD@{1} тощо) і опис того, що відбулося.
Відновлення після Hard Reset#
Ви випадково виконали git reset --hard HEAD~3 і втратили три коміти. Вони прямо тут, у reflog:
# Подивіться, що ви втратили
git reflog
# Коміт перед скиданням — це HEAD@{1}
git reset --hard f4e5d6cВсі три коміти повернулися. Кризу відвернуто.
Відновлення видаленої гілки#
Ви видалили гілку з незмердженою роботою:
git branch -D feature/experimental
# Ой, там було два тижні роботиКоміти все ще існують. Знайдіть їх:
git reflog | grep "feature/experimental"
# Або просто перегляньте reflog на предмет останнього коміту на тій гілці
# Знайшли. Відтворити гілку на тому коміті:
git branch feature/experimental a1b2c3dГілка повернулася з усіма своїми комітами.
Відновлення після невдалого Rebase#
Ви зробили rebase і все пішло не так. Конфлікти всюди, неправильні коміти, хаос:
# Reflog показує, де ви були до rebase
git reflog
# a1b2c3d HEAD@{0}: rebase (finish): ...
# ...
# f4e5d6c HEAD@{5}: rebase (start): checkout main
# b7a8c9d HEAD@{6}: commit: Your last good commit
# Повернутися до стану перед rebase
git reset --hard b7a8c9dВи повернулися точно туди, де були до початку rebase. Ніби його ніколи не було.
30-денна страхувальна сітка#
За замовчуванням Git зберігає записи reflog 30 днів (90 днів для досяжних комітів). Після цього вони можуть бути зібрані збирачем сміття. Отже, у вас є місяць, щоб усвідомити помилку. На практиці цього більш ніж достатньо.
Ви можете перевірити термін дії:
git config gc.reflogExpire
# за замовчуванням: 90.days.ago (для досяжних)
git config gc.reflogExpireUnreachable
# за замовчуванням: 30.days.ago (для недосяжних)Якщо ви параноїк, збільшіть:
git config --global gc.reflogExpireUnreachable "180.days.ago"Особисте правило#
Перед будь-якою деструктивною операцією — hard reset, force push, видалення гілки — я спочатку виконую git log --oneline -10. Я подумки фіксую поточний HEAD. Це займає дві секунди і вже не раз врятувало мене від паніки, якої не потрібно було.
Стеш правильно: Це не просто git stash#
Більшість людей використовують стеш так:
git stash
# робимо щось
git stash popЦе працює, але це еквівалент кидання всього в коробку з написом «барахло». Коли у вас три стеші, ви поняття не маєте, який — який.
Називайте свої стеші#
git stash push -m "WIP: user auth form validation"Тепер при переліку стешів:
git stash list
# stash@{0}: On feature/auth: WIP: user auth form validation
# stash@{1}: On main: Quick fix attempt for nav bug
# stash@{2}: On feature/payments: Experiment with Stripe webhooksВи бачите точно, що містить кожен стеш.
Включення невідстежуваних файлів#
За замовчуванням git stash стешить лише відстежувані файли. Нові файли, які ви ще не додали, залишаються:
# Стешити все, включаючи нові файли
git stash push --include-untracked -m "WIP: new auth components"
# Або навіть включити ігноровані файли (рідко потрібно)
git stash push --all -m "Full workspace snapshot"Я використовую --include-untracked майже кожного разу. Залишання нових файлів при переключенні гілок спричиняє плутанину.
Часткове стешування#
Це те, про що більшість людей не знає. Ви можете стешити конкретні файли:
# Стешити лише конкретні файли
git stash push -m "Just the auth changes" src/auth/ src/middleware.tsАбо використати patch-режим для стешування конкретних ханків всередині файлів:
git stash push --patch -m "Partial: only the validation logic"Git пройде через кожну зміну інтерактивно і запитає, чи хочете ви її стешити. y для так, n для ні, s для розділення ханку на менші частини.
Apply проти Pop#
# Pop: застосувати і видалити зі списку стешів
git stash pop stash@{2}
# Apply: застосувати, але залишити у списку стешів
git stash apply stash@{2}Я використовую apply, коли не впевнений, чи стеш застосується чисто. Якщо є конфлікт, стеш зберігається. З pop, якщо є конфлікт, стеш все одно залишається в списку (багато людей цього не знають), але я віддаю перевагу явному наміру apply.
Перегляд вмісту стешу#
# Подивитися, які файли змінились у стеші
git stash show stash@{0}
# Подивитися повний diff
git stash show -p stash@{0}Створення гілки зі стешу#
Якщо ваш стеш виріс у щось більш суттєве:
git stash branch feature/auth-validation stash@{0}Це створює нову гілку від коміту, де ви спочатку стешили, застосовує стеш і видаляє його. Чисто.
Стратегії гілкування: Яка реально працює#
Є три мейнстрімних стратегії гілкування. Кожна має контекст, де вона блищить, і контексти, де спричиняє біль.
Gitflow#
Класика. main, develop, feature/*, release/*, hotfix/*. Створена Vincent Driessen у 2010 році.
# Feature-гілка
git checkout -b feature/user-auth develop
# ... робота ...
git checkout develop
git merge --no-ff feature/user-auth
# Release-гілка
git checkout -b release/2.1.0 develop
# ... фінальні виправлення ...
git checkout main
git merge --no-ff release/2.1.0
git tag -a v2.1.0 -m "Release 2.1.0"
git checkout develop
git merge --no-ff release/2.1.0
# Hotfix
git checkout -b hotfix/session-fix main
# ... виправлення ...
git checkout main
git merge --no-ff hotfix/session-fix
git checkout develop
git merge --no-ff hotfix/session-fixКоли працює: Мобільні застосунки, десктопне ПЗ, все з іменованими версійними релізами та одночасною підтримкою кількох версій. Якщо ви випускаєте v2.1 і v3.0 і потрібно патчити обидва, Gitflow це обробляє.
Коли не працює: Веб-застосунки з безперервним деплоєм. Якщо ви деплоїте в продакшен 5 разів на день, церемонія release-гілок і develop-гілок — чистий оверхед. Більшість веб-команд, що приймають Gitflow, закінчують з develop-гілкою, яка вічно зламана, і release-гілками, які ніхто не розуміє.
GitHub Flow#
Просто. У вас є main. Ви створюєте feature-гілки. Ви відкриваєте PR. Ви мерджите в main. Ви деплоїте main.
git checkout -b feature/user-auth main
# ... робота ...
git push origin feature/user-auth
# Відкрити PR, отримати ревю, змерджити
# main завжди готовий до деплоюКоли працює: Малі та середні команди, що випускають веб-застосунки. Безперервний деплой. Якщо main завжди деплоїться, це все, що вам потрібно. Саме це використовує цей сайт.
Коли не працює: Коли потрібно підтримувати кілька release-версій, або коли є довгий цикл QA перед деплоєм. GitHub Flow припускає, що main швидко потрапляє в продакшен.
Trunk-Based Development#
Усі комітять у main («trunk») напряму або через дуже короткоживучі гілки (менше дня). Жодних довготривалих feature-гілок.
# Короткоживуча гілка (мерджиться того ж дня)
git checkout -b fix/auth-token main
# ... маленька, сфокусована зміна ...
git push origin fix/auth-token
# PR ревю'ється та мерджиться протягом годин, не днівКоли працює: Високопродуктивні команди з хорошим CI/CD, комплексними тест-сюїтами та прапорами функцій. Google, Meta та більшість великих технологічних компаній використовують trunk-based development. Це змушує робити маленькі, інкрементальні зміни та усуває пекло мерджів.
Коли не працює: Команди без хорошого тестового покриття або CI. Якщо мердж у trunk означає деплой непротестованого коду, ви будете постійно ламати продакшен. Вам також потрібні прапори функцій для будь-чого, що займає більше дня:
# Прапор функції в коді
if (featureFlags.isEnabled('new-checkout-flow')) {
renderNewCheckout();
} else {
renderLegacyCheckout();
}Моя рекомендація#
Для більшості веб-команд розробки: починайте з GitHub Flow. Це просто, це працює, і не потребує інструментарію окрім того, що GitHub/GitLab вже надає.
Якщо ваша команда виросте за 15-20 інженерів і ви деплоїте кілька разів на день, зверніть увагу на trunk-based development з прапорами функцій. Інвестиції в інфраструктуру прапорів функцій окупаються зменшенням конфліктів мерджу та швидшою ітерацією.
Якщо ви випускаєте версійне ПЗ (мобільні застосунки, CLI-інструменти, бібліотеки): Gitflow або спрощена версія. Вам дійсно потрібні ці release-гілки.
Не вибирайте стратегію, тому що якийсь блог-пост сказав, що це найкраща. Виберіть ту, що відповідає тому, як ви реально випускаєте.
Git Hooks: Автоматизуйте те, що постійно забуваєте#
Git hooks — це скрипти, що запускаються автоматично в певних точках воркфлоу Git. Вони локальні для вашої машини (не пушаться на ремоут), що означає, що вам потрібен спосіб ділитися ними з командою.
Хуки, які реально мають значення#
pre-commit — Запускається перед кожним комітом. Використовуйте для лінтингу та форматування:
#!/bin/bash
# .git/hooks/pre-commit
# Запустити ESLint лише на стейджених файлах
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|tsx)$')
if [ -n "$STAGED_FILES" ]; then
echo "Running ESLint on staged files..."
npx eslint $STAGED_FILES --quiet
if [ $? -ne 0 ]; then
echo "ESLint failed. Fix errors before committing."
exit 1
fi
fi
# Запустити Prettier на стейджених файлах
if [ -n "$STAGED_FILES" ]; then
echo "Running Prettier..."
npx prettier --check $STAGED_FILES
if [ $? -ne 0 ]; then
echo "Prettier check failed. Run 'npx prettier --write' first."
exit 1
fi
ficommit-msg — Валідує формат повідомлення коміту. Ідеально для впровадження conventional commits:
#!/bin/bash
# .git/hooks/commit-msg
COMMIT_MSG=$(cat "$1")
PATTERN="^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .{1,72}"
if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
echo "Invalid commit message format."
echo "Expected: type(scope): description"
echo "Example: feat(auth): add session refresh endpoint"
echo ""
echo "Valid types: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert"
exit 1
fipre-push — Запускається перед пушем. Використовуйте для тестів:
#!/bin/bash
# .git/hooks/pre-push
echo "Running tests before push..."
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Push aborted."
exit 1
fiHusky проти нативних хуків#
Нативні хуки живуть у .git/hooks/. Проблема: директорія .git не відстежується Git, тому ви не можете ділитися хуками через репозиторій. Кожен має налаштовувати їх вручну.
Husky вирішує це. Він зберігає конфігурації хуків у репозиторії та налаштовує .git/hooks автоматично при npm install:
npx husky initЦе створює директорію .husky/. Додавайте хуки як файли:
# .husky/pre-commit
npx lint-stagedУ поєднанні з lint-staged ви отримуєте швидкі, цілеспрямовані pre-commit перевірки:
{
"lint-staged": {
"*.{js,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.css": ["prettier --write"],
"*.json": ["prettier --write"]
}
}Це запускає ESLint і Prettier лише на файлах, які ви фактично комітите. Не на всій кодовій базі. Швидко.
Коли пропускати хуки#
Іноді потрібно комітити без запуску хуків. Термінові hotfix-и, work-in-progress коміти на вашій власній гілці:
git commit --no-verify -m "WIP: debugging production issue"Використовуйте це помірковано. Якщо ви регулярно пропускаєте хуки, ваші хуки, ймовірно, надто повільні або надто суворі.
Аліаси, що економлять час#
Мій .gitconfig еволюціонував роками. Це аліаси, що вижили — ті, якими я реально користуюсь щодня, а не ті, що я додав, бо вони виглядали розумно.
Гарний лог#
Стандартний git log багатослівний. Це дає вам чистий, кольоровий, графовий вигляд:
git config --global alias.lg "log --oneline --graph --all --decorate"Використання:
git lg
# * a1b2c3d (HEAD -> main) Fix session validation
# | * d4e5f6g (feature/payments) Add Stripe integration
# | * h7i8j9k Update payment models
# |/
# * l0m1n2o Merge PR #42
# * p3q4r5s Add user dashboardЯ запускаю це 20 разів на день. Це найшвидший спосіб зрозуміти стан вашого репозиторію.
Скасувати останній коміт#
Зберегти зміни, просто скасувати коміт:
git config --global alias.undo "reset HEAD~1 --mixed"Використання:
git undo
# Коміт зник, але всі зміни все ще у вашій робочій директоріїЯ використовую це, коли комічу занадто рано, забуваю файл або хочу реструктурувати зміни.
Зняти все зі стейджу#
git config --global alias.unstage "reset HEAD --"Використання:
git unstage src/auth/session.ts
# Файл знятий зі стейджу, але зміни збереженіПерелічити всі аліаси#
Бо ви забудете, що налаштували:
git config --global alias.aliases "config --get-regexp ^alias\\."Більше аліасів, якими я користуюсь#
# Показати, що ви збираєтесь комітити
git config --global alias.staged "diff --staged"
# Короткий статус
git config --global alias.st "status -sb"
# Amend без зміни повідомлення
git config --global alias.amend "commit --amend --no-edit"
# Показати останній коміт
git config --global alias.last "log -1 HEAD --stat"
# Pull з rebase замість мерджу
git config --global alias.up "pull --rebase --autostash"
# Видалити гілки, що змерджені в main
git config --global alias.cleanup "!git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d"Аліас up особливо хороший. pull --rebase тримає вашу історію лінійною замість створення мердж-комітів при кожному pull. --autostash автоматично стешить і відновлює ваші зміни, якщо у вас є брудні файли. Ось яким pull мав бути за замовчуванням.
Аліас cleanup видаляє локальні гілки, що змерджені в main. З часом ви накопичуєте десятки застарілих гілок. Запускайте це щотижня.
Команди, якими я користуюсь щодня#
Це не аліаси чи просунуті можливості. Це просто команди, які я постійно виконую, і про які багато розробників, здається, не знає.
Ультимативна команда логу#
git log --oneline --graph --allЦе показує кожну гілку, кожен мердж, всю топологію вашого репозиторію в компактному вигляді. Це перше, що я запускаю, коли підтягую зміни. Вона відповідає на запитання «що зараз відбувається в цьому репозиторії?»
Diff стейджених змін#
git diff --stagedЦе показує, що збирається бути комітнутим. Не те, що змінилось у вашій робочій директорії — те, що фактично стейджено. Я завжди запускаю це перед комітом. Завжди. Це ловить випадкові включення, debug-інструкції, console.log, яких не повинно бути.
# Подивитися нестейджені зміни
git diff
# Подивитися стейджені зміни
git diff --staged
# Подивитися обидва
git diff HEADПоказати конкретний коміт#
git show a1b2c3dПоказує повний diff окремого коміту. Корисно при перегляді історії, розумінні того, що коміт фактично змінив.
# Показати лише файли, що змінились
git show --stat a1b2c3d
# Показати конкретний файл на конкретному коміті
git show a1b2c3d:src/auth/session.tsОстаннє неймовірно корисне. Ви можете переглянути будь-який файл у будь-якій точці історії, не переключаючи коміт.
Blame з діапазонами рядків#
git blame -L 42,60 src/auth/session.tsПоказує, хто останнім модифікував рядки 42-60. Корисніше, ніж blame всього файлу, що зазвичай перевантажує.
# Показати повідомлення коміту теж, не лише хеш
git blame -L 42,60 --show-name src/auth/session.ts
# Ігнорувати зміни пробілів (дуже корисно)
git blame -w -L 42,60 src/auth/session.ts
# Показати коміт перед blamed (копати глибше)
git log --follow -p -- src/auth/session.tsПрапорець -w важливий. Без нього blame приписуватиме рядки тому, хто останнім переформатував файл, а це рідко та людина, яку ви шукаєте.
Пошук рядка по всій історії#
# Знайти, коли функція була додана або видалена
git log -S "validateSession" --oneline
# Знайти, коли з'явився regex-патерн
git log -G "session.*timeout" --oneline-S («кирка») знаходить коміти, де кількість входжень рядка змінилась. -G знаходить коміти, де diff відповідає regex. Обидва потужні для археології — з'ясування, коли щось було введено або видалено.
Показати, що змінилось між двома точками#
# Що змінилось між двома гілками
git diff main..feature/auth
# Що змінилось на цій гілці з моменту відгалуження від main
git diff main...feature/auth
# Перелічити лише змінені файли
git diff main...feature/auth --name-only
# Статистичний вигляд (файли + вставки/видалення)
git diff main...feature/auth --statДві крапки проти трьох крапок має значення. Дві крапки показують різницю між кінцями обох гілок. Три крапки показують, що змінилось на правій стороні з моменту відгалуження від лівої. Три крапки — це зазвичай те, що ви хочете при ревю feature-гілки.
Очищення невідстежуваних файлів#
# Подивитися, що було б видалено (пробний запуск)
git clean -n
# Видалити невідстежувані файли
git clean -f
# Видалити невідстежувані файли та директорії
git clean -fd
# Видалити невідстежувані та ігноровані файли (ядерний варіант)
git clean -fdxЗавжди запускайте з -n спочатку. git clean -fdx видалить ваші node_modules, .env, артефакти збірки — все, що не відстежується Git. Корисно для справді свіжого старту, але деструктивно.
Відновити один файл з іншої гілки#
# Отримати версію файлу з main-гілки без переключення гілок
git restore --source main -- src/config/database.tsАбо з конкретного коміту:
git restore --source a1b2c3d -- src/config/database.tsЦе чистіше, ніж старий синтаксис git checkout main -- path/to/file, і не впливає на HEAD.
Збираємо все разом: Реальний воркфлоу#
Ось як виглядає типовий день з цими інструментами:
# Ранок: перевірити, що відбувається
git lg
git fetch --all
# Почати фічу
git checkout -b feature/session-refresh main
# Працювати, комітити інкрементально
git add -p # Стейджити конкретні ханки, не цілі файли
git commit -m "Add token refresh endpoint"
git commit -m "Add refresh token rotation"
git commit -m "Fix: handle expired refresh tokens"
git commit -m "Add integration tests"
# Перервано: потрібно виправити продакшен-баг
git worktree add ../hotfix main
cd ../hotfix
# ... виправити, комітнути, запушити, PR змерджено ...
cd ../my-project
git worktree remove ../hotfix
# Назад до роботи над фічею
git commit -m "Fix edge case in token validation"
# Готовий до PR: очистити історію
git rebase -i main
# Об'єднати fix-коміти, переформулювати для ясності
# Запушити та відкрити PR
git push -u origin feature/session-refresh
# Щось зламалось на стейджингу? Знайти який коміт:
git bisect start
git bisect bad HEAD
git bisect good main
git bisect run npm test
# Ой, я скинув не те
git reflog
git reset --hard HEAD@{2}Кожна з цих команд займає секунди. Разом вони економлять години. Не гіпотетичні години — реальні години, щотижня, які я б інакше витратив на розплутування Git-месів, ручний пошук багів або втрату роботи через переключення контексту.
Git — це інструмент, що винагороджує глибину. Основи проведуть вас через день. Але команди в цій статті — це те, що розділяє «я використовую Git» від «Git реально робить мене швидшим». Вивчайте їх інкрементально. Виберіть одну нову техніку цього тижня та використовуйте її, поки вона не стане м'язовою пам'яттю. Потім виберіть іншу.
Ваше майбутнє я, що дивиться на продакшен-баг о 23:00, подякує вам за знання git bisect.