Programming

What does the git index contain EXACTLY

19 September 2026 · 15 min read

What does the git index contain EXACTLY

Understanding the inner workings of Git can be a daunting task, especially when diving into the intricacies of the staging area, more formally known as the git index. The git index is not just some vague temporary storage; it’s a crucial component that acts as a bridge between your working directory and the Git repository. Often described as the “staging area,” it meticulously tracks changes you intend to include in your next commit. This allows developers to selectively add, remove, and modify files before permanently recording them in the project’s history. This article will explore exactly what the git index contains, its purpose, and how it contributes to the efficient management of your codebase. It’s more than just a list of files; it’s a structured data store that underpins Git’s powerful version control capabilities.

The Core Purpose of the Git Index

At its heart, the git index serves as an intermediary staging area where changes are prepared for a commit. It allows you to construct commits that consist of only specific modifications from your working directory. Without the index, every change you make would be automatically included in the next commit, leading to potentially messy and less organized version history. The index provides a flexible way to curate your changes, ensuring that each commit represents a logical and coherent unit of work. Think of it as a pre-packaging area where you carefully select and arrange the items (changes) before shipping them off (committing). The index also enhances performance. Instead of Git having to scan your entire working directory for changes every time you commit, it only needs to look at the index, which is a much smaller and more manageable data structure. This dramatically speeds up the commit process, particularly in large projects with numerous files.

The git index also stores metadata about each file it tracks, including timestamps, file modes, and object IDs (SHA-1 hashes) of the file’s content. This metadata is crucial for Git to efficiently determine whether a file has been modified and needs to be updated in the index. This ability to track file metadata makes Git extremely efficient at identifying and managing changes across your project. For example, if you modify a file in your working directory, Git can quickly compare the timestamp and file size of the file in the index with the file in your working directory. If they are different, Git knows that the file has been changed and needs to be staged again. This selective staging is a key feature that distinguishes Git from simpler version control systems. According to the Pro Git book [^1^], understanding the index is fundamental to mastering Git’s workflows.

Consider a scenario where you’re working on a new feature that spans multiple files. You might be simultaneously fixing bugs and adding new functionality. With the git index, you can stage only the bug fixes for one commit and the new feature code for a separate commit, keeping your commit history clean and understandable. This is a prime example of how the git index facilitates organized and manageable software development. The ability to selectively stage changes is especially useful when collaborating with others, as it allows you to isolate your contributions and avoid accidentally committing unrelated changes. You can even use Git’s interactive staging features (like git add -p) to stage only specific parts of a file, further refining your commits.

What the Git Index Actually Contains

The git index is not just a simple list of filenames; it’s a binary file that stores a wealth of information about each tracked file. It holds metadata such as the file’s mode (executable, read-only, etc.), object ID (SHA-1 hash of the file’s content), stage number (used for merge conflicts), timestamps, and file size. This metadata allows Git to quickly and efficiently determine the status of files in your working directory and prepare them for commit. The index also keeps track of file paths relative to the root of your Git repository. This ensures that Git can correctly identify and manage files regardless of your current working directory.

The object ID (SHA-1 hash) stored in the git index is particularly important. It represents the content of the file at the time it was added to the index. When you commit, Git uses these object IDs to create a tree object representing the state of the index at that moment. This tree object becomes part of the commit, linking the commit to the specific versions of the files it contains. If you modify a file and stage it again, the object ID in the index will be updated to reflect the new content. This is how Git tracks changes to files over time. The Git index also supports extensions for features like sparse checkouts and file system monitoring. These extensions enhance Git’s performance and scalability, especially in large repositories.

Here’s a breakdown of what the git index contains:

  • File metadata (mode, timestamps, size)
  • Object IDs (SHA-1 hashes of file content)
  • File paths relative to the repository root
  • Stage numbers (for merge conflicts)
  • Extension data (for advanced features)

This detailed information allows Git to efficiently track changes, resolve conflicts, and maintain a consistent view of your project’s history. The structure of the index is carefully optimized for performance, allowing Git to quickly access and update file information. This is one of the reasons why Git is so fast and efficient, even when working with large projects. According to Atlassian [^2^], the index is a crucial component for understanding Git’s performance characteristics.

How the Git Index Facilitates Staging

The staging process, facilitated by the git index, is the act of adding changes from your working directory to the index in preparation for a commit. When you run git add, you’re essentially telling Git to update the index with the current state of the specified files. This updates the object ID and other metadata in the index to reflect the changes you’ve made. The index then becomes a snapshot of your project that you’re ready to commit. This allows you to carefully curate your changes and create meaningful commits that tell a clear story about your project’s development.

Staging allows for granular control over what gets included in each commit. This is especially useful when working on complex features or bug fixes that span multiple files. By selectively staging changes, you can create commits that are focused and easy to understand. This makes it easier to review code, revert changes, and understand the history of your project. For instance, imagine you’ve modified several files, but only one file contains a critical bug fix. You can stage just that file and commit the fix immediately, without including any unrelated changes. This ensures that the bug fix is quickly deployed and doesn’t get mixed up with other ongoing development work.

Here’s how staging works in practice:

  1. You modify files in your working directory.
  2. You use git add to stage the changes you want to include in the next commit.
  3. Git updates the index with the new object IDs and metadata for the staged files.
  4. You use git commit to create a new commit based on the contents of the index.

The git index thereby acts as a dynamic staging area, enabling you to selectively prepare changes for inclusion in the next commit. Understanding this process is fundamental to effectively using Git for version control. Using the index correctly ensures clean commits and helps to maintain a clear, understandable project history. This is a key factor in successful software development and collaboration.

Understanding Common Git Index Operations

Working with the git index involves several common operations that every Git user should understand. These include adding files (git add), removing files (git rm), viewing the index status (git status), and resetting the index (git reset). Each of these operations directly manipulates the contents of the index and affects what will be included in your next commit. Mastering these operations is essential for effectively managing your changes and maintaining a clean Git repository.

The git add command is used to add new files or stage changes to existing files. When you run git add , Git calculates the SHA-1 hash of the file’s content and adds it to the index, along with other metadata. If the file is already tracked, the index is updated with the new hash, reflecting the changes you’ve made. The git rm command, on the other hand, is used to remove files from both your working directory and the index. This command is used to delete files that are no longer needed in your project. The git status command is a powerful tool for viewing the current state of the index and your working directory. It shows you which files have been modified, staged, or are untracked. This command is essential for understanding what changes you’re about to commit and for identifying any potential issues.

The git reset command is used to unstage files from the index. This command allows you to undo changes that you’ve staged but no longer want to include in your next commit. There are several variations of git reset, each with different effects on the index and your working directory. For example, git reset HEAD unstages a specific file, while git reset –hard resets both the index and your working directory to the last commit, discarding any uncommitted changes. Understanding the different options for git reset is crucial for avoiding accidental data loss. Here’s why these operations are so important:

  • git add: Stages changes for commit.
  • git rm: Removes files from the working directory and index.
  • git status: Shows the current state of the working directory and index.
  • git reset: Unstages changes from the index.

By understanding how these commands interact with the git index, you can effectively manage your changes, create clean commits, and maintain a well-organized Git repository. These operations are fundamental to any Git workflow, from individual projects to large-scale collaborative development. Learning to use them effectively will significantly improve your productivity and reduce the risk of errors.

Infographic here
FAQ About the Git Index -----------------------
What happens if I modify a file after staging it?
If you modify a file after staging it, the index will not automatically reflect those changes. You'll need to run git add again to stage the updated version of the file.
Is the git index the same as the .git directory?
No, the **git index** is a specific file within the .git directory. The .git directory contains all of Git's internal data, including the index, object database, and configuration files.
Can I view the contents of the git index directly?
Yes, you can use the git ls-files --stage command to view the contents of the index, including file modes, object IDs, and file paths.
In essence, the **git index** is the unsung hero of Git's version control magic, meticulously managing the changes you're about to commit and providing the flexibility to craft meaningful, organized commits. It's the staging area where your changes are carefully prepared, allowing you to maintain a clean and understandable project history. \[^3^\]

We’ve explored the purpose of the index, its contents, and the essential operations involved in managing it. It’s more than just a list of files; it’s a structured data store that enables Git’s powerful features. Now that you have a clearer understanding of the git index, put your knowledge to practice! Experiment with staging changes, viewing the index status, and crafting commits that tell a clear story about your project’s evolution. Dive deeper into Git documentation and explore advanced staging techniques. By mastering the git index, you’ll unlock a new level of control over your version control workflow and contribute to a more efficient and collaborative development process. Consider exploring topics like Git hooks or branching strategies to further enhance your Git skills.

[^1^]: Chacon, S., & Straub, B. (2014). Pro Git. Apress. [^2^]: Atlassian. (n.d.). Git Index. Retrieved from [https://www.atlassian.com/git/tutorials/saving-changes/staging](https://www.atlassian.com/git/tutorials/saving-changes/staging) [^3^]: Git Documentation. (n.d.). Retrieved from [https://git-scm.com/docs](https://git-scm.com/docs) Question & Answer :
What does the Git index exactly contain, and what command can I use to view the content of the index?


Thanks for all your answers. I know that the index acts as a staging area, and what is committed is in the index rather than the working tree. I am just curious about what an index object consists of. I guess it might be a list of filename/directory names, SHA-1 pairs, a kind of virtual tree maybe?

Is there, in Git terminology, any plumbing command that I can use to list the contents of the index?

The Git book contains an article on what an index includes:

The index is a binary file (generally kept in .git/index) containing a sorted list of path names, each with permissions and the SHA1 of a blob object; git ls-files can show you the contents of the index:

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

The Racy git problem gives some more details on that structure:

The index is one of the most important data structures in git.
It represents a virtual working tree state by recording list of paths and their object names and serves as a staging area to write out the next tree object to be committed.
The state is “virtual” in the sense that it does not necessarily have to, and often does not, match the files in the working tree.


Nov. 2021: see also “Make your monorepo feel small with Git’s sparse index” from Derrick Stolee (Microsoft/GitHub)

https://github.blog/wp-content/uploads/2021/11/Fig-1-working-directory-index-commit-history.png

The Git index is a critical data structure in Git. It serves as the “staging area” between the files you have on your filesystem and your commit history.

  • When you run git add, the files from your working directory are hashed and stored as objects in the index, leading them to be “staged changes”.
  • When you run git commit, the staged changes as stored in the index are used to create that new commit.
  • When you run git checkout, Git takes the data from a commit and writes it to the working directory and the index.

In addition to storing your staged changes, the index also stores filesystem information about your working directory.
This helps Git report changed files more quickly.


To see more, cf. “git/git/blob/master/Documentation/gitformat-index.txt”:

The Git index file has the following format

All binary numbers are in network byte order.
Version 2 is described here unless stated otherwise.

  • A 12-byte header consisting of:
  • 4-byte signature:
    The signature is { ‘D’, ‘I’, ‘R’, ‘C’ } (stands for “dircache”)
  • 4-byte version number:
    The current supported versions are 2, 3 and 4.
  • 32-bit number of index entries.
  • A number of sorted index entries.
  • Extensions:
    Extensions are identified by signature.
    Optional extensions can be ignored if Git does not understand them.
    Git currently supports cached tree and resolve undo extensions.
  • 4-byte extension signature. If the first byte is ‘A’..’Z’ the extension is optional and can be ignored.
  • 32-bit size of the extension
  • Extension data
  • 160-bit SHA-1 over the content of the index file before this checksum.

mljrg comments:

If the index is the place where the next commit is prepared, why doesn’t “git ls-files -s” return nothing after commit?

Because the index represents what is being tracked, and right after a commit, what is being tracked is identical to the last commit (git diff --cached returns nothing).

So git ls-files -s lists all files tracked (object name, mode bits and stage number in the output).

That list (of element tracked) is initialized with the content of a commit.
When you switch branch, the index content is reset to the commit referenced by the branch you just switched to.


Git 2.20 (Q4 2018) adds an Index Entry Offset Table (IEOT):

See commit 77ff112, commit 3255089, commit abb4bb8, commit c780b9c, commit 3b1d9e0, commit 371ed0d (10 Oct 2018) by Ben Peart (benpeart).
See commit 252d079 (26 Sep 2018) by Nguyễn Thái Ngọc Duy (pclouds).
(Merged by Junio C Hamano – gitster in commit e27bfaa, 19 Oct 2018)

ieot: add Index Entry Offset Table (IEOT) extension

This patch enables addressing the CPU cost of loading the index by adding additional data to the index that will allow us to efficiently multi- thread the loading and conversion of cache entries.

It accomplishes this by adding an (optional) index extension that is a table of offsets to blocks of cache entries in the index file.

To make this work for V4 indexes, when writing the cache entries, it periodically"resets" the prefix-compression by encoding the current entry as if the path name for the previous entry is completely different and saves the offset of that entry in the IEOT.
Basically, with V4 indexes, it generates offsets into blocks of prefix-compressed entries.

With the new index.threads config setting, the index loading is now faster.


As a result (of using IEOT), commit 7bd9631 clean-up the read-cache.c load_cache_entries_threaded() function for Git 2.23 (Q3 2019).

See commit 8373037, commit d713e88, commit d92349d, commit 113c29a, commit c95fc72, commit 7a2a721, commit c016579, commit be27fb7, commit 13a1781, commit 7bd9631, commit 3c1dce8, commit cf7a901, commit d64db5b, commit 76a7bc0 (09 May 2019) by Jeff King (peff).
(Merged by Junio C Hamano – gitster in commit c0e78f7, 13 Jun 2019)

read-cache: drop unused parameter from threaded load

The load_cache_entries_threaded() function takes a src_offset parameter that it doesn’t use. This has been there since its inception in 77ff112 (read-cache: load cache entries on worker threads, 2018-10-10, Git v2.20.0-rc0).

Digging on the mailing list, that parameter was part of an earlier iteration of the series, but became unnecessary when the code switched to using the IEOT extension.


With Git 2.29 (Q4 2020), the format description adjusts to the recent SHA-256 work.

See commit 8afa50a, commit 0756e61, commit 123712b, commit 5b6422a (15 Aug 2020) by Martin Ågren (none).
(Merged by Junio C Hamano – gitster in commit 74a395c, 19 Aug 2020)

index-format.txt: document SHA-256 index format

Signed-off-by: Martin Ågren

Document that in SHA-1 repositories, we use SHA-1 and in SHA-256 repositories, we use SHA-256, then replace all other uses of “SHA-1” with something more neutral.
Avoid referring to “160-bit” hash values.

technical/index-format now includes in its man page:

All binary numbers are in network byte order.
In a repository using the traditional SHA-1, checksums and object IDs (object names) mentioned below are all computed using SHA-1.
Similarly, in SHA-256 repositories, these values are computed using SHA-256.

Version 2 is described here unless stated otherwise.


Commit 4950aca from commit cf4a3bd, Git 2.44, Q1 2024, details the block management in a Git index.