Кожен коміт зберігає посилання на батьківські коміти. Разом вони утворюють спрямований ациклічний граф (DAG):
- спрямований - посилання йдуть лише від нащадка до предка, коміт не знає своїх дітей;
- ациклічний - неможливо, рухаючись по батьках, повернутися до того самого коміту (батька створено раніше за нащадка, а хеш нащадка містить хеш батька).
Скільки батьків може мати коміт:
| Батьків | Що це |
|---|---|
| 0 | кореневий коміт - перший у репозиторії |
| 1 | звичайний коміт |
| 2 | merge-коміт - результат злиття двох гілок |
| 3+ | octopus merge - злиття кількох гілок одночасно (рідко) |
git cat-file -p HEAD # merge-коміт
# tree ...
# parent 99fe6a1... ← перший батько: гілка, в яку зливали (main)
# parent 5b8c2d0... ← другий батько: гілка, яку зливали (feature)
Порядок батьків має значення: перший батько - це «основна лінія». git log --first-parent показує історію main лише з merge-комітів, без внутрішніх комітів кожної гілки - зручно бачити, які фічі й коли потрапили в основну гілку.
Подивитися граф:
git log --graph --oneline --all
# * 23933de Merge branch 'feature'
# |\
# | * 5b8c2d0 Add export
# * | 99fe6a1 Fix typo
# |/
# * 84ba035 Init
Що випливає з графової моделі:
- гілка - лише вказівник на одну вершину графа; «вміст гілки» - усі коміти, досяжні з неї по батьках;
- спільний предок (merge base) двох гілок - найближча вершина, досяжна з обох: від неї Git рахує зміни при злитті (
git merge-base main feature); - «чи злито гілку» = чи досяжний її коміт з
main(git branch --merged); - merge-коміт не містить «різниці» - як і будь-який коміт, він зберігає повний знімок, а зміни Git показує, порівнюючи з батьками.