Что в git index содержится ТОЧНО?

Что именно содержит индекс Git и какую команду я могу использовать для просмотра содержимого индекса?


Обновить

Спасибо за все ваши ответы. Я знаю, что индекс действует как промежуточная область, и то, что фиксируется, находится в индексе, а не в рабочем дереве. Мне просто интересно, из чего состоит индексный объект. Я предполагаю, что это может быть список имен файлов / каталогов, пар SHA-1, что-то вроде виртуального дерева?

Есть ли в терминологии Git какая-либо сантехническая команда, которую я могу использовать для просмотра содержимого индекса?

7 ответов

Решение

Книга Git содержит статью о том, что включает в себя индекс:

Индекс представляет собой двоичный файл (обычно хранится в .git/index) содержащий отсортированный список имен путей, каждое с правами доступа и SHA1 объекта BLOB-объекта; git ls-files может показать вам содержимое индекса:

$ git ls-files --stage
100644 63c918c667fa005ff12ad89437f2fdc80926e21c 0   .gitignore
100644 5529b198e8d14decbe4ad99db3f7fb632de0439d 0   .mailmap

Проблема Racy git дает более подробную информацию об этой структуре:

Индекс является одной из самых важных структур данных в git.
Он представляет состояние виртуального рабочего дерева путем записи списка путей и имен их объектов и служит промежуточной областью для записи следующего объекта дерева, который будет зафиксирован.
Состояние является "виртуальным" в том смысле, что оно не обязательно должно и часто не совпадает с файлами в рабочем дереве.


Чтобы увидеть больше, ср. " https://github.com/git/git/blob/master/Documentation/technical/index-format.txt ":

Индексный файл Git имеет следующий формат

Все двоичные числа расположены в сетевом порядке байтов.
Версия 2 описана здесь, если не указано иное.

  • 12-байтовый заголовок, состоящий из:
    • 4-байтовая подпись:
      Подпись {' D ',' I ',' R ',' C '} (расшифровывается как " dircache ")
    • 4-байтовый номер версии:
      В настоящее время поддерживаются версии 2, 3 и 4.
    • 32-битное количество записей индекса.
  • Количество отсортированных записей индекса.
  • Расширения:
    Расширения идентифицируются по подписи.
    Необязательные расширения можно игнорировать, если Git их не понимает.
    Git в настоящее время поддерживает кэшированное дерево и разрешает отмену расширений.
    • 4-байтовая подпись расширения. Если первый байт A '..' Z "расширение является необязательным и может быть проигнорировано.
    • 32-битный размер расширения
    • Данные расширения
  • 160-битный SHA-1 поверх содержимого индексного файла до этой контрольной суммы.

mljrg mljrg:

Если индекс - это место, где готовится следующий коммит, почему бы и нет? git ls-files -s "ничего не вернуть после коммита?

Поскольку индекс представляет то, что отслеживается, и сразу после принятия то, что отслеживается, идентично последнему подтверждению (git diff --cached ничего не возвращает).

Так git ls-files -s перечисляет все отслеживаемые файлы (имя объекта, биты режима и номер этапа в выходных данных).

Этот список (отслеживаемых элементов) инициализируется содержимым коммита.
Когда вы переключаете ветку, содержимое индекса сбрасывается до коммита, на который ссылается ветка, на которую вы только что переключились.


Git 2.20 (Q4 2018) добавляет таблицу смещения записи индекса (IEOT):

См. Коммит 77ff112, коммит 3255089, коммит abb4bb8, коммит c780b9c, коммит 3b1d9e0, коммит 371ed0d (10 октября 2018 г.) от Ben Peart ( benpeart )
См. Коммит 252d079 (26 сентября 2018 г.) Нгуен Тай Нгук Дуй ( pclouds )
(Объединено Юнио С Хамано - gitster - в комм. е27бфаа, 19 октября 2018 г.)

ieot: добавить расширение таблицы смещения записи индекса (IEOT)

Этот патч позволяет учесть стоимость загрузки индекса процессором, добавив к нему дополнительные данные, что позволит нам эффективно выполнять многопоточную загрузку и преобразование записей кэша.

Это достигается путем добавления (необязательного) расширения индекса, которое представляет собой таблицу смещений, к блокам записей кэша в файле индекса.

Чтобы это работало для индексов V4, при записи записей в кэш он периодически "сбрасывает" сжатие префиксов, кодируя текущую запись, как будто имя пути для предыдущей записи полностью отличается, и сохраняет смещение этой записи в IEOT.,
В основном, с индексами V4, он генерирует смещения в блоки сжатых префиксами записей.

С новым параметром конфигурации index.threads загрузка индекса теперь быстрее.

Побитовый анализ

Я решил сделать небольшое тестирование, чтобы лучше понять формат и исследовать некоторые области более подробно.

Результаты ниже одинаковы для версий Git 1.8.5.2 а также 2.3,

Я отметил точки, которые я не уверен / не нашел с TODOПожалуйста, не стесняйтесь дополнять эти пункты.

Как уже упоминалось, индекс хранится в .git/indexне как стандартный объект дерева, и его формат является двоичным и задокументирован по адресу: https://github.com/git/git/blob/master/Documentation/technical/index-format.txt

Основные структуры, определяющие индекс, находятся в cache.h, потому что индекс является кешем для создания коммитов.

Настроить

Когда мы запускаем тестовое хранилище с:

git init
echo a > b
git add b
tree --charset=ascii

.git каталог выглядит так:

.git/objects/
|-- 78
|   `-- 981922613b2afb6025042ff6bd878ac1994e85
|-- info
`-- pack

И если мы получим содержимое единственного объекта:

git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85

Мы получаем a, Это указывает на то, что:

  • index указывает на содержимое файла, так как git add b создал объект BLOB-объекта
  • он хранит метаданные в индексном файле, а не в объекте дерева, поскольку был только один объект: BLOB-объект (в обычных объектах Git метаданные BLOB-объектов хранятся в дереве)

анализ HD

Теперь давайте посмотрим на сам индекс:

hd .git/index

дает:

00000000  44 49 52 43 00 00 00 02  00 00 00 01 54 09 76 e6  |DIRC.... ....T.v.|
00000010  1d 81 6f c6 54 09 76 e6  1d 81 6f c6 00 00 08 05  |..o.T.v. ..o.....|
00000020  00 e4 2e 76 00 00 81 a4  00 00 03 e8 00 00 03 e8  |...v.... ........|
00000030  00 00 00 02 78 98 19 22  61 3b 2a fb 60 25 04 2f  |....x.." a;*.`%./|
00000040  f6 bd 87 8a c1 99 4e 85  00 01 62 00 ee 33 c0 3a  |......N. ..b..3.:|
00000050  be 41 4b 1f d7 1d 33 a9  da d4 93 9a 09 ab 49 94  |.AK...3. ......I.|
00000060

Далее мы сделаем вывод:

  | 0           | 4            | 8           | C              |
  |-------------|--------------|-------------|----------------|
0 | DIRC        | Version      | File count  | ctime       ...| 0
  | ...         | mtime                      | device         |
2 | inode       | mode         | UID         | GID            | 2
  | File size   | Entry SHA-1                              ...|
4 | ...                        | Flags       | Index SHA-1 ...| 4
  | ...                                                       |

Сначала идет заголовок, определенный в: struct cache_header:

  • 44 49 52 43: DIRC, ТОДО: зачем это нужно?

  • 00 00 00 02: версия формата: 2. Формат индекса развивался со временем. В настоящее время существует версия до 4. Формат индекса не должен быть проблемой при совместной работе между различными компьютерами на GitHub, поскольку голые репозитории не хранят индекс: он создается во время клонирования.

  • 00 00 00 01: количество файлов в индексе: только один, b,

Далее начинается список записей индекса, определенных struct cache_entry. Здесь у нас есть только один. Это содержит:

  • набор метаданных файла: 8 байт ctime8 байт mtimeзатем 4 байта: устройство, индекс, режим, UID и GID.

    Обратите внимание, как:

    • ctime а также mtime подобные (54 09 76 e6 1d 81 6f c6) как и ожидалось, так как мы не изменили файл

      Первые байты являются секундами после EPOCH в гексе:

      date --date="@$(printf "%x" "540976e6")"
      

      дает:

      Fri Sep  5 10:40:06 CEST 2014
      

      Который, когда я сделал этот пример.

      Вторые 4 байта являются наносекундами.

    • UID и GID являются 00 00 03 e8, 1000 в шестнадцатеричном формате: общее значение для однопользовательских настроек.

    Все эти метаданные, большинство из которых отсутствуют в древовидных объектах, позволяют Git проверять, быстро ли изменился файл, не сравнивая все содержимое.

  • в начале строки 30: 00 00 00 02: размер файла: 2 байта (a а также \n от echo)

  • 78 98 19 22 ... c1 99 4e 85: 20 байт SHA-1 поверх предыдущего содержимого записи. Обратите внимание, что согласно моим экспериментам с предполагаемым допустимым флагом, флаги, которые следуют за ним, не рассматриваются в этом SHA-1.

  • 2-байтовые флаги: 00 01

    • 1 бит: принять допустимый флаг. Мои исследования показывают, что этот плохо названный флаг git update-index --assume-unchanged сохраняет свое состояние: /questions/40521727/kuda-git-update-index-assume-neizmenennyij-fajl-fakticheski-sohranyaet-etu-informatsiyu/40521730#40521730

    • 1-битовый расширенный флаг. Определяет, присутствуют ли расширенные флаги или нет. Должно быть 0 на версии 2, которая не имеет расширенных флагов.

    • 2-битный флаг этапа, используемый во время слияния. Этапы документированы в man git-merge:

      • 0: обычный файл, нет конфликта слияния
      • 1: база
      • 2: наш
      • 3: их

      Во время конфликта слияния все этапы 1-3 сохраняются в индексе, чтобы разрешить такие операции, как git checkout --ours,

      если ты git addзатем этап 0 добавляется в индекс для пути, и Git будет знать, что конфликт помечен как разрешенный. ТОДО: проверь это.

    • 12-битная длина пути, который будет следовать: 0 01: Только 1 байт, поскольку путь был b

  • 2-байтовые расширенные флаги. Имеет смысл только в том случае, если на базовых флагах был установлен "расширенный флаг". СДЕЛАТЬ.

  • 62 (ASCII b): путь переменной длины. Длина определяется в предыдущих флагах, здесь всего 1 байт, b,

Затем приходит 00: 1-8 байт заполнения нулями, чтобы путь заканчивался нулем и индекс заканчивался кратным 8 байтам. Это происходит только до версии 4 индекса.

Расширения не использовались. Git знает об этом, потому что в файле не хватит места для контрольной суммы.

Наконец, есть 20-байтовая контрольная сумма ee 33 c0 3a .. 09 ab 49 94 по содержанию индекса.

Индекс Git является промежуточной областью между вашим рабочим каталогом и вашим хранилищем. Вы можете использовать индекс для создания набора изменений, которые вы хотите зафиксировать вместе. Когда вы создаете коммит, то, что фиксируется, это то, что в данный момент находится в этом индексе, а не то, что находится в вашем рабочем каталоге.

Чтобы увидеть, что находится внутри индекса, введите команду:

git status

Когда вы запускаете git status, вы можете видеть, какие файлы размещены (в данный момент в вашем индексе), которые изменены, но еще не подготовлены, а какие полностью не отслежены.

Вы можете прочитать это. Поиск Google выдает много ссылок, которые должны быть достаточно самодостаточными.

Индекс Git - это двоичный файл (обычно хранящийся в .git/index), содержащий отсортированный список имен путей, каждое с разрешениями и SHA1 объекта blob;

git ls-filesможет показать вам содержимое указателя. Обратите внимание, что словаindex, stage, а также cache в Git одно и то же: они взаимозаменяемы.

Git index или Git cache имеет 3 важных свойства:

  1. Индекс содержит всю информацию, необходимую для создания единого (однозначно определенного) древовидного объекта.
  2. Индекс позволяет быстро сравнивать определяемый им объект дерева и рабочее дерево.
  3. Он может эффективно представлять информацию о конфликтах слияния между различными объектами дерева, позволяя связывать каждый путь с достаточной информацией об участвующих деревьях, чтобы вы могли создать трехстороннее слияние между ними.

Источник:

  1. https://mincong.io/2018/04/28/git-index/
  2. https://medium.com/hackernoon/understanding-git-index-4821a0765cf

В ответ на @ciro-santilli-%e9%83%9d%e6%b5%b7%e4%b8%9c%e5%86%a0%e7%8a%b6%e7%97%85%e5%85%ad%e5%9b%9b%e4%ba%8b%e4%bb%b6%e6%b3%95%e8%bd%ae%e5%8a%9f подробно рассмотрим индекс, поделюсь результатами для одного в TODO.

"Если вы git add, то к индексу пути будет добавлен этап 0, и Git будет знать, что конфликт отмечен как решенный. ЗАДАЧИ: проверьте это".

И, в частности, разные этапы слияния.

  • 0: обычный файл, не в конфликте слияния
  • 1: база
  • 2: наш
  • 3: их

Подробная информация о числовом представлении различных этапов, в данном случае файл с конфликтом.

$ git ls-files -s
100644 f72d68f0d10f6efdb8adc8553a1df9c0444a0bec 0       vars/buildComponent.groovy

$ git stash list
stash@{0}: WIP on master: c40172e turn off notifications, temporarily

$ git stash apply
Auto-merging vars/commonUtils.groovy
Auto-merging vars/buildComponent.groovy
CONFLICT (content): Merge conflict in vars/buildComponent.groovy

$ git ls-files -s
100644 bc48727339d36f5d54e14081f8357a0168f4c665 1       vars/buildComponent.groovy
100644 f72d68f0d10f6efdb8adc8553a1df9c0444a0bec 2       vars/buildComponent.groovy
100644 24dd5be1783633bbb049b35fc01e8e88facb20e2 3       vars/buildComponent.groovy

Вот что именно вам нужно, используйте эту команду.

$ binwalk index

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1717          0x6B5           Unix path: /company/user/user/delete.php
1813          0x715           Unix path: /company/user/user/get.php
1909          0x775           Unix path: /company/user/user/post.php
2005          0x7D5           Unix path: /company/user/user/put.php
3373          0xD2D           Unix path: /urban-airship/channel/channel/post.php
3789          0xECD           Unix path: /urban-airship/named-user/named-user/post.php
3901          0xF3D           Unix path: /user/categories/categories/delete.php
4005          0xFA5           Unix path: /user/categories/categories/get.php
4109          0x100D          Unix path: /user/categories/categories/put.php
4309          0x10D5          Unix path: /user/favorites/favorites/delete.php

Просто хотел поставить git ls-tree в кольцо.

Индекс - одна из самых важных структур данных в git.
Он представляет состояние виртуального рабочего дерева путем записи списка путей и имен их объектов и служит промежуточной областью для записи следующего объекта дерева, который необходимо зафиксировать.
Состояние является «виртуальным» в том смысле, что оно не обязательно должно и часто не соответствует файлам в рабочем дереве.

Можно ли сказать, что git ls-tree точно сообщает мне, какие рабочие файлы / объекты должны присутствовать, если я проверил специальный коммит? О каком дереве мы говорим в контексте ls-tree?

Примеры

      git ls-tree -r -l HEAD
git ls-tree -r -l commit-hash

Кстати: ls-tree работает также для репозиториев, клонированных без проверки (-n), где ls-files ничего не возвращает.

/questions/48343145/chto-imenno-delaet-git-ls-files-i-kak-myi-mozhem-udalit-iz-nego-fajl/48343159#48343159

https://stackoverflow.com/a/67567058/2623045

Другие вопросы по тегам