Щоденна робота з Git: status, add, commit, diff, log, .gitignore
Стани файлів, вибіркове додавання змін (add -p), хороші повідомлення комітів, усі види diff, пошук в історії через log і правила .gitignore.
Цикл одного коміту
90 % роботи з Git — це повторення п'яти кроків:
git status # 1. що змінилося?
git diff # 2. що саме змінилося?
git add src/login.py # 3. обрати зміни для коміту
git commit -m "Додати перевірку пароля при вході" # 4. зберегти
git push # 5. відправити на серверСтани файлу
| Стан | Що означає | Як потрапити далі |
|---|---|---|
| untracked | Git бачить файл, але не стежить за ним | git add |
| unmodified | файл такий самий, як в останньому коміті | редагування |
| modified | змінений, але зміни не в індексі | git add або git restore |
| staged | зміни в індексі, підуть у наступний коміт | git commit або git restore --staged |
git status — читаємо вивід
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: src/login.py
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
notes.txtЧитаємо знизу вгору: notes.txt — новий, README.md змінено, але не додано, src/login.py готовий до коміту. А ще є 1 коміт, якого немає на сервері. Git навіть підказує команди в дужках.
Короткий формат — зручно, коли файлів багато:
git status -sb## main...origin/main [ahead 1]
M src/login.py
M README.md
MM src/api.py
?? notes.txtЛіва колонка — індекс, права — робоча папка: M — у індексі, M — змінено, не додано, MM — частина змін в індексі, частина ні, ?? — новий файл, A — новий файл в індексі, D — видалений.
git add — вибираємо, що піде в коміт
git add file.txt # один файл
git add src/ # папку цілком
git add '*.py' # за шаблоном (лапки, щоб розкрив Git, а не shell)
git add . # усе в поточній папці і нижче
git add -A # усі зміни в репозиторії, включно з видаленнями
git add -u # лише вже відстежувані файли (нові не чіпає)git add -p — найкорисніша команда, про яку мало хто знає
Часто в одному файлі змішано дві різні зміни: виправлення бага і випадковий рефакторинг. -p (patch) показує зміни шматками й питає про кожен:
git add -p src/login.py@@ -10,6 +10,9 @@ def login(user, password):
if not user:
raise ValueError("user is empty")
+ if len(password) < 8:
+ raise ValueError("password too short")
+
return check(user, password)
(1/2) Stage this hunk [y,n,q,a,d,s,e,?]?| Клавіша | Дія |
|---|---|
y / n |
додати / пропустити цей шматок |
s |
розбити шматок на менші |
e |
відредагувати шматок вручну |
q |
вийти (вже вибране лишається в індексі) |
a / d |
додати / пропустити всі шматки, що лишились у файлі |
Так з однієї «каші» змін виходять два акуратні коміти.
git commit
git commit -m "Додати перевірку довжини пароля" # коротке повідомлення
git commit # відкриє редактор для довгого
git commit -v # у редакторі ще й diff — видно, що комітите
git commit -am "Оновити залежності" # add + commit для вже відстежуваних файлівcommit -a не бачить нових файлів
-aдодає лише зміни у файлах, які Git уже відстежує. Новий файл треба один раз додати черезgit add.
Як писати повідомлення
Повідомлення читають через місяці — вами ж, коли шукатимете, звідки взявся баг.
Обмежити кількість спроб входу до 5 за хвилину
Боти перебирали паролі на /login. Тепер після 5 невдалих спроб
з однієї IP-адреси сервер 60 секунд відповідає 429.
Closes #142Правила:
- Перший рядок — до ~50–72 символів, у наказовому способі: «Додати», «Виправити», «Прибрати». Без крапки в кінці.
- Порожній рядок, далі — тіло: навіщо зміна і що вона ламає чи змінює. «Що» видно з diff, а «навіщо» — ні.
- Один коміт — одна логічна зміна. «Виправити баг і оновити залежності й перейменувати змінні» — це три коміти.
| Погано | Добре |
|---|---|
fix |
Виправити падіння на порожньому кошику |
wip |
Додати чернетку сторінки оплати (без валідації) |
зміни |
Перейти з requests на httpx |
fixed bug from yesterday |
Не дублювати email при повторній реєстрації |
У командах часто домовляються про формат Conventional Commits (feat:, fix: …) — про нього в нотатці «Git у команді».
git diff — що саме змінилося
| Команда | Порівнює |
|---|---|
git diff |
робоча папка ↔ індекс (ще не додане) |
git diff --staged |
індекс ↔ останній коміт (що піде в коміт) |
git diff HEAD |
робоча папка ↔ останній коміт (усе разом) |
git diff main feature |
дві гілки (кінцеві стани) |
git diff main...feature |
що змінилося у feature від точки відгалуження |
git diff HEAD~3 -- src/ |
останні 3 коміти, лише папка src/ |
Корисні прапорці:
git diff --stat # лише список файлів і кількість рядків
git diff --name-only # лише імена файлів
git diff --word-diff # різниця по словах — зручно для текстів і документації
git diff -w # ігнорувати зміни пробілівПриклад виводу --stat:
src/login.py | 12 ++++++++----
tests/login.py | 30 ++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+), 4 deletions(-)git log — історія
git log # повний формат
git log --oneline # один рядок на коміт
git log --oneline --graph --all # дерево всіх гілок
git log -5 # останні 5
git log -p # з diff кожного коміту
git log --stat # зі списком змінених файлівВласний формат:
git log --pretty=format:"%h %ad %an %s" --date=short4d5a6b7 2026-10-26 Олена Додати тести для входу
c9e8f02 2026-10-25 Тарас Додати API користувачів
7b2d4e1 2026-10-24 Олена Описати проєкт у README%h — короткий хеш, %an — автор, %ad — дата, %ar — «2 дні тому», %s — заголовок.
Пошук в історії
| Завдання | Команда |
|---|---|
| коміти певного автора | git log --author="Олена" |
| за період | git log --since="2 weeks ago" --until="yesterday" |
| за словом у повідомленні | git log --grep="оплат" -i |
| що змінювало файл | git log --oneline -- src/login.py |
| історія файлу після перейменування | git log --follow -- src/auth/login.py |
| коли з'явився чи зник рядок коду | git log -S "MAX_RETRIES" --oneline |
| коли змінювався рядок за регуляркою | git log -G "timeout\s*=" --oneline |
| що є в feature, але не в main | git log --oneline main..feature |
| злиття (merge-коміти) | git log --merges --oneline |
Звідки взялося число 30?У конфігу таймаут раптом 30 замість 10.
git log -S "timeout = 30" -pзнайде коміт, де цей рядок з'явився, разом з автором і поясненням.
git show — один коміт
git show 4d5a6b7 # повідомлення + diff
git show --stat HEAD # лише файли
git show HEAD~2:src/config.py # файл, яким він був два коміти тому
git show main:README.md > old.md # зберегти стару версію файлуВидалити і перейменувати файл
git rm old.txt # видалити з диска і з Git
git rm --cached secrets.env # перестати відстежувати, але лишити на диску
git rm -r --cached build/ # те саме для папки
git mv old.py new.py # перейменувати (= mv + git add)Git не зберігає «перейменування» окремо: він помічає, що вміст майже однаковий, і показує renamed. Тому краще не змішувати перейменування і великі правки в одному коміті.
.gitignore — що не потрапляє в репозиторій
Не комітимо: залежності, результати збірки, логи, локальні налаштування IDE і секрети. Файл .gitignore у корені проєкту:
# Залежності та збірка
node_modules/
.venv/
dist/
build/
__pycache__/
*.pyc
# Логи й тимчасове
*.log
*.tmp
.cache/
# Секрети та локальні налаштування
.env
.env.*
!.env.example
*.pem
*.key
# IDE і ОС
.idea/
.vscode/
.DS_Store
Thumbs.db
# Terraform
.terraform/
*.tfstate
*.tfstate.*Синтаксис шаблонів:
| Шаблон | Що ігнорує |
|---|---|
*.log |
усі .log файли в будь-якій папці |
build/ |
папку build будь-де (лише папки) |
/build |
лише build у корені репозиторію |
doc/*.txt |
.txt прямо в doc/, але не в doc/sub/ |
doc/**/*.txt |
.txt у doc/ на будь-якій глибині |
!.env.example |
виняток: цей файл не ігнорувати |
# коментар |
коментар |
Виняток не працює всередині ігнорованої папкиЯкщо проігноровано
logs/, то!logs/keep.logне спрацює: Git навіть не заходить у таку папку. Пишітьlogs/*і потім!logs/keep.log.
Чому файл ігнорується (або ні)?
git check-ignore -v config/local.yml
# .gitignore:14:*.yml config/local.ymlВидно файл і номер рядка правила.
Файл уже в репозиторії — .gitignore не допомагає
.gitignore діє лише на нові файли. Якщо .env уже закомічено:
echo ".env" >> .gitignore
git rm --cached .env
git commit -m "Перестати відстежувати .env"Файл лишиться на диску, але зникне з наступних комітів. В історії він лишається — якщо там був секрет, дивіться нотатку «Скасування змін», розділ про секрети.
Глобальний і локальний ignore
-
Глобальний — для сміття вашої ОС і редактора в усіх проєктах, щоб не засмічувати
.gitignoreкоманди:git config --global core.excludesFile ~/.gitignore_global echo -e ".DS_Store\n.idea/\n*.swp" >> ~/.gitignore_global -
Локальний, некомітний —
.git/info/exclude: та сама мова шаблонів, але правила бачите лише ви.
Порожня папка
Git зберігає файли, а не папки — порожню папку закомітити не можна. Покладіть у неї порожній .gitkeep (назва — домовленість, не магія).
Шпаргалка
| Команда | Що робить |
|---|---|
git status -sb |
коротко: що змінено і на скільки комітів ви попереду/позаду |
git add -p |
додати зміни частинами |
git commit -v |
коміт з переглядом diff у редакторі |
git diff / --staged |
не додане / додане |
git log --oneline --graph --all |
дерево історії |
git log -S "текст" |
коміти, що додали чи прибрали текст |
git show HEAD~1:file |
файл з попереднього коміту |
git rm --cached file |
перестати відстежувати |
git check-ignore -v file |
яке правило ігнорує файл |
Збережіть статтю собі
Увійдіть, щоб імпортувати її у власні нотатки, відмічати вивчене, ставити лайки й питати спільноту. Реєстрація безкоштовна: вхід через Google займає кілька секунд.
Увійти через Google Інші способи входу