core code helper

Щоденна робота з Git: status, add, commit, diff, log, .gitignore

Стани файлів, вибіркове додавання змін (add -p), хороші повідомлення комітів, усі види diff, пошук в історії через log і правила .gitignore.

0 імпортували Імпортувати собі

Цикл одного коміту

90 % роботи з Git — це повторення п'яти кроків:

git status                 # 1. що змінилося?
git diff                   # 2. що саме змінилося?
git add src/login.py       # 3. обрати зміни для коміту
git commit -m "Додати перевірку пароля при вході"   # 4. зберегти
git push                   # 5. відправити на сервер

Стани файлу

Схема станів файлу: новий, збережений, змінений, в індексі; переходи через редагування, git add, git commit, git restore, git restore --staged і git rm --cached

Стан Що означає Як потрапити далі
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=short
4d5a6b7 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 Інші способи входу