Що індекс git містить ТОЧНО?


178

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


Оновлення

Дякую за всі ваші відповіді. Я знаю, що індекс виступає як область постановки, і те, що робиться, є в індексі, а не робочому дереві. Мені просто цікаво, з чого складається об'єкт індексу. Я думаю, це може бути список імені файлу / імені каталогів, SHA-1 пар, можливо, якесь віртуальне дерево?

Чи є в термінології Git якась сантехнічна команда, яку я можу використовувати, щоб перерахувати вміст індексу?



3
ви повинні читати і дивитися діаграми - дуже корисно: gitguys.com/topics/whats-the-deal-with-the-git-index
kernix

1
@kernix термін дії домену закінчився. Не дуже корисно вже.
нарендра-чодхарі

Відповіді:


162

Книга Git містить статтю про те, що включає індекс :

Індекс - це двійковий файл (як правило, зберігається в ньому .git/index), який містить відсортований список імен шляхів, кожне з дозволами та SHA1 об'єкта blob; git ls-filesможе показати вам вміст індексу:

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

Проблема Racy git дає ще кілька деталей щодо цієї структури:

Індекс є однією з найважливіших структур даних у git.
Він представляє віртуальне стан робочого дерева, записуючи список шляхів та назви їх об'єктів, і служить зоною інсценізації для запису наступного об’єкта дерева, який потрібно здійснити.
Стан є "віртуальним" в тому сенсі, що не обов'язково, а часто і не, відповідати файлам у робочому дереві.


Щоб побачити більше, пор. " git / git / Документація / технічний / 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 коментарі :

Якщо індекс - це місце, де готується наступне введення, чому 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 р.) Від Бена Піарта ( benpeart) .
Див. Комісію 252d079 (26 вересня 2018 р.) Від Nguyễn Thái Ngọc Duy ( pclouds) .
(Об’єднав Хуніо С Хамано - gitster- у комітеті e27bfaa , 19 жовтня 2018 р.)

ieot: додайте розширення таблиці зсуву введення в індекс (IEOT)

Цей патч дозволяє вирішити витрати на процесор завантаження індексу шляхом додавання додаткових даних до індексу, що дозволить нам ефективно багаторазово завантажувати та перетворювати записи кешу.

Це досягається шляхом додавання (необов'язкового) розширення індексу, що є таблицею зсувів до блоків записів кешу у файлі індексу.

Щоб зробити цю роботу для індексів V4, під час запису записів кешу він періодично "скидає" префікс-стиснення, кодуючи поточний запис так, ніби ім'я шляху для попереднього запису зовсім інше і зберігає зміщення цього запису в IEOT .
В основному, за допомогою індексів V4 він генерує зсуви в блоки записів, стиснених префіксом.

З новим параметром конфігурації index.threads зараз завантаження індексу відбувається швидше.


Як результат ( використання IEOT ), виконайте очищення 7bd9631read-cache.c load_cache_entries_threaded() функції для Git 2.23 (Q3 2019).

Див здійснювати 8373037 , здійснювати d713e88 , здійснюють d92349d , здійснюють 113c29a , здійснюють c95fc72 , здійснюють 7a2a721 , здійснюють c016579 , здійснюють be27fb7 , здійснюють 13a1781 , здійснюють 7bd9631 , здійснюють 3c1dce8 , здійснюють cf7a901 , здійснюють d64db5b , здійснюють 76a7bc0 (09 травня 2019) від Jeff King ( peff) .
(Об'єднав Хуніо С Хамано - gitster- в комітеті c0e78f7 , 13 червня 2019 р.)

read-cache: викинути невикористаний параметр з потокового навантаження

load_cache_entries_threaded()Функція приймає src_offsetпараметр , який він не використовує. Це було з моменту його створення в 77ff112 ( read-cache: записи кеш-завантаження на робочі потоки, 2018-10-10, Git v2.20.0-rc0).

Копаючись у списку розсилки, цей параметр був частиною попередньої ітерації серії , але став непотрібним, коли код перейшов на використання розширення IEOT.


6
Про важливість , якщо індекс в моделі Git, см stackoverflow.com/questions/1450348 / ...
VonC

Перше посилання вище вказує на версію git-scm, в якій немає статті про індекс. Я думаю, що наміром було вказати тут: schacon.github.io/gitbook/7_the_git_index.html
Kris Giesing

1
@KrisGiesing Дякую за посилання. Я оновив відповідь.
VonC

@VonC Якщо індекс - це місце, де готується наступна фіксація, чому "git ls-files -s" нічого не повертає після фіксації? Має бути щось більше про індекс, ніж ви вказали у своїй відповіді.
mljrg

@mljrg не впевнений, що я слідую за тобою: після фіксації етап (де готується комітет ) буде порожнім, оскільки це було зроблено, чи не так?
VonC

62

Побітний аналіз

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

Нижче наведені результати однакові для версій 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 (на звичайних об'єктах 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,.

Далі починається список записів індексів, визначених struktur cache_entry Тут у нас є лише одна. Це містить:

  • купа метаданих файлів: 8 байт ctime, 8 байт mtime, потім 4 байти: пристрій, inode, режим, 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 e81000 у шістнадцятковій мові: загальне значення для індивідуальних налаштувань користувачів.

    Усі ці метадані, більшість з яких відсутні в дерев`яних об'єктах, дозволяють 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зберігається його стан: https://stackoverflow.com/a/28657085/895245

    • 1 бітний розширений прапор Визначає, чи є розширені прапори чи ні. Повинно бути 0у версії 2, яка не має розширених прапорів.

    • 2-бітний прапор етапу, який використовується під час злиття. Етапи задокументовані у man git-merge:

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

      Під час конфлікту злиття всі етапи від 1-3 зберігаються в індексі, щоб дозволити такі операції git checkout --ours.

      Якщо ви git add, то етап 0 додається до індексу шляху, і Git дізнається, що конфлікт позначено як вирішений. TODO: перевіри це.

    • 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щодо вмісту індексу.


1
Дуже цікаво. +1. Це чудово ілюструє мою власну відповідь . Цікаво, чи змінилися б ці результати із останнім Git 2.1+.
VonC

3
@NielsBom так, це також працюватиме. При інтерпретації програм я вважаю за краще скористатися двома підходами: спочатку емпіричним, щоб побачити, які результати генерує, і лише після цього прочитати джерело. В іншому випадку можна потрапити в регістри вихідних кодів, які навіть не з’являються на простих вихідних даних. Звичайно, я дивився на джерельні структури, щоб допомогти мені керувати, і кожен TODO може вирішити моє читання, як цими структурами маніпулюють, що є важкою частиною.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: Якщо я зміню індекс у шестигранному редакторі та оновлюю його 20-байтну контрольну суму, чи існує команда оновити sha1, який зберігається в інших об'єктах? (git скаржиться sha1 підпис індексу зіпсований) . Також дані індексу зберігаються зовсім по-іншому, коли надсилаються через push-запити.
користувач2284570

1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: цілі безпеки. Просто шукаю добре відомі види атак на растрові файли зображень, застосовані до бази даних / об’єктів git. (звичайно, я знаю, що більшість впроваджених останнім часом піклується про цю перспективу, але, мабуть, не всі).  Тому я особливо шукаю бінарні структури даних, які визначають довжину масиву. (що стосується текстових буферів, то, здається, нульове припинення є нормою для визначення кількості рядків)
user2284570

1
Що стосується git addвашого, TODOви маєте рацію. Якщо у вас є записи на високому рівні індексу (конфлікт) на заданому шляху, тоді, коли ви git addпройдете цей шлях, всі записи індексу високого ступеня будуть видалені, а копія робочого каталогу буде додана на етапі 0. (Вирішення конфлікту).
Едвард Томсон

11

Індекс Git - це місце розміщення між вашим робочим каталогом та вашим сховищем. Ви можете використовувати індекс, щоб створити набір змін, які ви хочете зробити разом. Коли ви створюєте комісію, те, що здійснюється, - це те, що зараз знаходиться в цьому індексі, а не те, що є у вашому робочому каталозі.

Щоб побачити, що знаходиться всередині індексу, видайте команду:

git status

Коли ви запускаєте статус git, ви можете бачити, які файли ставляться (наразі у вашому індексі), які модифіковані, але ще не поставлені та які повністю не відслідковуються.

Ви можете прочитати це . Пошуковий пошук Google надає багато посилань, які мають бути досить самодостатніми.


7
git statusне перераховує всі файли з індексу. У ньому перераховані лише ті файли, які відрізняються між індексом та робочим каталогом. Щоб побачити всі файли в індексі, вам потрібно скористатися git ls-files.
Акаш Агравал

1
@AkashAgrawal, git status робить в списку факт індексних файлів, незалежно від того, чи відрізняються вони між вказівним і WORKDIR.
Acumenus

3
так, він перераховує ДЕЯКІ файли індексу, але він не показує вам все, що знаходиться всередині індексу, про що говорить його твердження у своїй відповіді. Це як би сказати, що всередині коробки є 2 зелених кулі та 3 червоних кулі. Щоб побачити, що всередині коробки, витягніть 2 зелених кулі. Те, що сказав Акаш, є найбільш точним, щоб побачити всі файли в індексі, використовуйте git ls-файли.
dave4jr

3
Справді. git statusперелічує файли, що знаходяться в індексі, так, але не перераховує всі файли в індексі. Пояснення, як git status насправді працює, було б корисною відповіддю на якесь питання, хоча, мабуть, не на це.
Едвард Томсон

1
git statusпоказує стан робочого дерева (різниця між робочим деревом та індексом). Він фактично не показує індекс. git-scm.com/docs/git-status
wisbucky

1

Ось що вам точно потрібно, скористайтеся цією командою.

$ 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

0

Індекс Git - це двійковий файл (як правило, зберігається в ньому .git/index), який містить відсортований список імен шляхів, кожне з дозволами та SHA1 об'єкта blob;

git ls-filesможе показати вам вміст індексу. Зверніть увагу, що слова index, stageі cacheє тим самим, що і в Git: вони використовуються взаємозамінно.

введіть тут опис зображення

Індекс Git або кеш-пам'ять Git має 3 важливі властивості:

  1. Індекс містить всю інформацію, необхідну для генерації одного (однозначно визначеного) деревного об'єкта.
  2. Індекс дозволяє швидко порівняти між об'єктом дерева, який він визначає, та робочим деревом.
  3. Він може ефективно представляти інформацію про конфлікти злиття між різними об’єктами дерева, дозволяючи кожному імені шляху бути пов’язаним з достатньою інформацією про дерева, що беруть участь, що ви можете створити тристороннє злиття між ними.

Джерело :

  1. https://mincong.io/2018/04/28/git-index/
  2. https://medium.com/hackernoon/understanding-git-index-4821a0765cf
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.