.git/index - бінарний файл, що описує знімок для наступного коміту. Для кожного файлу він зберігає:
- шлях, режим і хеш blob-а вмісту;
- дані
statз файлової системи: розмір, час зміни (mtime, ctime), inode, пристрій, uid/gid; - номер стадії (stage) - для конфліктів злиття.
git ls-files --stage
# 100644 1f7a7a4... 0 composer.json
# 100644 e9c3d2b... 0 app/Models/User.php
git ls-files --debug app/Models/User.php # разом з даними stat
Як git status працює швидко. Обчислювати хеш кожного файлу в проєкті з десятками тисяч файлів було б повільно. Тому Git спершу порівнює дані stat:
- якщо розмір і час зміни файлу збігаються з тими, що в індексі, - файл вважається незмінним без читання вмісту;
- лише для файлів з іншими
statGit читає вміст, хешує й порівнює з blob-ом в індексі; - якщо вміст той самий (наприклад, файл перезбережено без змін), Git оновлює дані
statв індексі, щоб наступного разу не перевіряти.
«Racy git» - файл змінено в ту саму секунду, що й записано індекс: час збігається, хоча вміст інший. Git розпізнає цей випадок і перевіряє такі файли за вмістом.
Стадії при конфлікті: для конфліктного файлу індекс містить до трьох записів - стадія 1 (спільний предок), 2 (наша версія), 3 (їхня). git add після розв'язання замінює їх одним записом стадії 0.
git ls-files -u # конфліктні записи
git show :2:config/app.php # наша версія
git show :3:config/app.php # їхня версія
Прапорці в індексі:
git update-index --assume-unchanged file- обіцянка Git не перевіряти файл (оптимізація для повільних файлових систем);git update-index --skip-worktree file- ігнорувати локальні зміни відстежуваного файлу (локальна конфігурація). Обидва - локальні й не передаються іншим;git ls-files -vпоказує такі файли малими літерами.
Для великих репозиторіїв: core.untrackedCache, core.fsmonitor і index.version=4 (стиснення шляхів) зменшують час status з секунд до мілісекунд.
Пошкоджений індекс («index file corrupt») не означає втрату історії: rm .git/index && git reset відтворить його з HEAD, зберігши файли робочого каталогу.