core code helper

Як працює Git: коміти, гілки, HEAD

Модель, без якої команди Git здаються магією: знімки й хеші, чотири місця для коду, гілки як вказівники, HEAD і detached HEAD.

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

Навіщо Git

Git — розподілена система контролю версій. Вона:

  • пам'ятає кожну збережену версію проєкту й дозволяє повернутися до будь-якої;
  • показує, хто, коли і навіщо змінив кожен рядок;
  • дає працювати над кількома задачами паралельно (гілки) і потім поєднувати результат;
  • дозволяє команді працювати над одним кодом, не перезаписуючи роботу одне одного.

«Розподілена» означає, що кожен клон — це повна копія репозиторію з усією історією. GitHub чи GitLab — лише ще одна копія, про яку команда домовилась як про «головну». Сервер упав — історія все одно є в кожного розробника.

Актуальність

Команди в розділі працюють у Git 2.40 і новіших. Команди git switch і git restore з'явилися в Git 2.23 — у старих інструкціях замість них пишуть git checkout. Перевірити версію: git --version.

Коміт — це знімок, а не список змін

Найважливіша ідея Git: коміт зберігає знімок усього проєкту на момент збереження, а не «різницю з минулим разом». Файли, які не змінилися, не копіюються — коміт просто посилається на вже збережену версію, тому репозиторій не роздувається.

Кожен коміт містить:

Що Приклад
знімок файлів (дерево) усі файли проєкту на цей момент
батьківський коміт (або два — у merge) parent 7b2d4e1…
автор і дата Олена <olena@example.com>, 26.10.2026 14:03
повідомлення «Додати перевірку email»

Із цього вмісту рахується хеш — 40 шістнадцяткових символів (SHA-1), наприклад 4d5a6b7c0e1f…. Зазвичай досить перших 7: 4d5a6b7.

Хеш залежить від усього вмісту коміту, включно з хешем батька. Тому:

  • змінити старий коміт, не змінивши хеші всіх наступних, неможливо — так Git гарантує цілісність історії;
  • git commit --amend чи git rebase не «редагують» коміти, а створюють нові з новими хешами (про це — у нотатках «Rebase» і «Скасування змін»).

Подивитися «нутрощі» коміту:

git cat-file -p HEAD
tree 9c4a1f0e6b2d3c4a5b6c7d8e9f0a1b2c3d4e5f60
parent 7b2d4e1a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c
author Олена <olena@example.com> 1793000000 +0200
committer Олена <olena@example.com> 1793000000 +0200

Додати перевірку email

Чотири місця, де живе код

Зміна проходить шлях з вашого редактора до GitHub через чотири «кімнати»:

Схема: робоча папка, індекс, локальний і віддалений репозиторії; git add, git commit і git push переносять зміни вправо, git fetch і git pull — назад

  1. Робоча папка (working tree) — звичайні файли на диску, які ви редагуєте.
  2. Індекс (staging area, index) — «чернетка» наступного коміту. Сюди ви кладете саме ті зміни, які мають увійти в коміт. Можна змінити 5 файлів, а закомітити 2.
  3. Локальний репозиторій — база комітів у прихованій папці .git.
  4. Віддалений репозиторій (remote) — копія на GitHub, GitLab чи своєму сервері.

Повний цикл на прикладі:

echo "print('hi')" > app.py   # 1. файл з'явився в робочій папці
git add app.py                # 2. зміни в індексі
git commit -m "Додати app.py" # 3. коміт у локальній історії
git push                      # 4. коміт на GitHub
Коміт — ще не на сервері

Поки не зроблено git push, коміт існує лише на вашому комп'ютері. Колеги його не бачать, а якщо диск помре — коміт зникне разом з ним.

Гілки — це просто вказівники

Гілка в Git — це не копія файлів, а файл із хешем одного коміту. Тому створити гілку можна миттєво навіть у гігантському проєкті.

Схема: ланцюжок комітів, гілки main і feature/login як вказівники на коміти та HEAD, що вказує на main

Переконайтеся самі:

cat .git/refs/heads/main
# 4d5a6b7c0e1f2a3b4c5d6e7f8091a2b3c4d5e6f7

Коли ви робите коміт, Git записує новий коміт, у якого батько — поточний, і пересуває поточну гілку на нього. Інші гілки лишаються на місці.

Якщо файлу немає

Git інколи пакує посилання в один файл .git/packed-refs. Надійніше дивитися так: git rev-parse main.

HEAD — «ви тут»

HEAD — це вказівник на те, що зараз розгорнуто у робочій папці. Зазвичай він вказує не на коміт напряму, а на гілку:

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

git switch feature/login просто переписує цей файл на ref: refs/heads/feature/login і оновлює файли в робочій папці під знімок того коміту.

Як послатися на коміт

Майже кожна команда Git приймає «посилання на коміт». Їх можна писати по-різному:

Запис Що означає
4d5a6b7 коміт за (скороченим) хешем
main, feature/login останній коміт гілки
HEAD поточний коміт
HEAD~1 або HEAD~ батько поточного коміту
HEAD~3 три коміти назад по першому батьку
HEAD^2 другий батько merge-коміту (гілка, яку влили)
origin/main де була main на сервері під час останнього git fetch
v1.2.0 коміт, позначений тегом
HEAD@{2} де був HEAD два переміщення тому (див. git reflog)
main@{yesterday} де була main учора (за локальним журналом)
main..feature коміти, які є у feature, але немає в main

Приклади:

git show HEAD~2              # що змінив коміт двома кроками раніше
git diff HEAD~3 HEAD         # усі зміни за останні три коміти
git log main..feature        # що принесе злиття feature у main

Detached HEAD — «відірвана голова»

Якщо перейти не на гілку, а прямо на коміт чи тег, HEAD вказуватиме на коміт, а не на гілку:

git switch --detach 7b2d4e1     # або: git checkout v1.0.0
HEAD is now at 7b2d4e1 README
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them...

Це нормальний режим, щоб подивитися, як проєкт виглядав колись, або зібрати старий реліз. Небезпека одна: коміти, зроблені в цьому стані, не належать жодній гілці. Щойно ви перейдете кудись іще, їх стане важко знайти.

Що робити:

git switch -c experiment     # зробили коміти — збережіть їх у нову гілку
git switch main              # просто подивились — повертайтеся
Коміти вже «загубились»?

git reflog покаже всі місця, де був HEAD, з хешами. Знайдіть потрібний і виконайте git branch rescue <хеш>.

Що всередині папки .git

.git/
├── HEAD           # на що вказує HEAD
├── config         # налаштування цього репозиторію (remote, гілки)
├── index          # індекс — бінарний файл
├── objects/       # усі коміти, дерева, файли (стиснуті)
├── refs/
│   ├── heads/     # локальні гілки
│   ├── remotes/   # origin/main і т. д.
│   └── tags/      # теги
├── logs/          # reflog — журнал переміщень
└── hooks/         # скрипти-хуки (pre-commit тощо)
Не видаляйте .git

Уся історія живе саме тут. Видалите .git — залишаться лише поточні файли, а проєкт перестане бути репозиторієм. Руками там теж краще нічого не правити.

Чотири типи об'єктів (для допитливих)

Git — це по суті база даних «ключ → значення», де ключ — хеш:

Об'єкт Що зберігає
blob вміст одного файлу (без імені!)
tree вміст папки: імена файлів, права, посилання на blob-и й вкладені tree
commit посилання на кореневе tree, батьків, автора, повідомлення
tag анотований тег: посилання на коміт, автор, опис

Пройдіть ланцюжок самі:

git cat-file -p HEAD            # коміт → бачимо tree
git cat-file -p 'HEAD^{tree}'   # дерево → бачимо файли й їхні blob-и
git cat-file -p HEAD:README.md  # вміст файлу з коміту

Через те що blob не знає свого імені, перейменування файлу нічого не копіює: нове дерево просто посилається на той самий blob під іншим ім'ям.

Коротко

  • Коміт — незмінний знімок з хешем; «редагування» створює нові коміти.
  • Зміни йдуть: робоча папка → git add → індекс → git commit → локальна історія → git push → сервер.
  • Гілка — вказівник на коміт, HEAD — вказівник на поточну гілку.
  • Detached HEAD безпечний для перегляду; для роботи створіть гілку.
  • Майже все «втрачене» можна знайти через git reflog.

Збережіть статтю собі

Увійдіть, щоб імпортувати її у власні нотатки, відмічати вивчене, ставити лайки й питати спільноту. Реєстрація безкоштовна: вхід через Google займає кілька секунд.

Увійти через Google Інші способи входу