Хеш коміту обчислюється з усього вмісту коміту:
git cat-file -p HEAD
# tree 3c4e9cd789d88d8d89c1073707c3585e41b0e614
# parent 84ba0356e6199a1cb8a555fef6d09aebe1c203f1
# author Olena <olena@example.com> 1759500000 +0300
# committer Olena <olena@example.com> 1759500000 +0300
#
# Add invoice export
У нього входять хеш дерева (знімок усіх файлів) і хеш батьківського коміту. А хеш батька, у свою чергу, залежить від його батька - і так до першого коміту.
Наслідок - ланцюжок, як у блокчейні: зміна будь-чого в старому коміті (файлу, повідомлення, автора, навіть дати) дає новий хеш цього коміту, отже нові хеші всіх його нащадків. Тому:
- один хеш гарантує всю історію: якщо у вас і в колеги
mainвказує на той самий хеш, у вас ідентичні всі файли й уся історія до цього моменту; - непомітно підмінити старий коміт чи файл неможливо - зміниться хеш, і це видно;
- переписування історії (
rebase,commit --amend) завжди створює нові коміти з новими хешами - звідси конфлікти з колегами, які вже мають старі.
Чому коміти з однаковим вмістом мають різні хеші: у коміті є час і автор. Два однакові git commit з різницею в секунду - різні коміти. Тому cherry-pick одного коміту у дві гілки дає два різні хеші.
Перевірка цілісності - git fsck:
git fsck
git fsck --full --strict
Перевіряє, що кожен об'єкт відповідає своєму хешу, всі посилання (з коміту на tree, з tree на blob-и) ведуть на існуючі об'єкти, і повідомляє про пошкоджені, відсутні й недосяжні об'єкти.
Де це корисно:
- після збою диска чи синхронізації
.gitчерез хмарні сервіси; fetchіcloneперевіряють об'єкти автоматично (transfer.fsckObjectsвмикає повнішу перевірку), тож пошкоджені дані з сервера не потраплять у ваш репозиторій непомітно.
Обмеження: хеш захищає від випадкових пошкоджень і непомітної підміни, але не доводить авторство - ім'я й пошту в коміті може вписати будь-хто. Для цього існують підписані коміти.