Git Index Inspector
Read .git/index in your browser: every staged entry with its blob hash, mode and flags, conflict stages, extensions and the trailing checksum.
How to use
- Drop in a .git/index from any repository. It has no extension, so if your file manager hides it, type the path into the picker or copy it somewhere first — a copy reads exactly the same.
- Start at the summary: the format version, how many entries the header declares against how many were actually read, whether the object ids are SHA-1 or SHA-256, and whether the trailing checksum still verifies.
- Check the flag counts. Anything other than zero for assume-unchanged or skip-worktree explains a file git has been refusing to notice changes in, and intent-to-add marks paths added with -N that have no content staged yet.
- Look up a path in the entry table for the blob hash it is staged at, its mode, the recorded size and the cached modification time. Very large indexes list the first few hundred rows and the full count next to them.
- After a merge, read the conflicts section: it lines up the base, ours and theirs stages of every unresolved path, and the resolve-undo extension lists the ones already resolved in this session.
About this tool
ShowHide
Reads .git/index — a repository's staging area — straight out of the bytes, the way git ls-files --stage --debug reads it, and entirely inside your browser. Every entry is listed with the object id of the blob it is staged at, its file mode, its merge stage, the size git recorded, and the cached mtime it compares against lstat() to decide a file has not changed. That cache is behind the most common mystery about this file: when git insists a file you just edited is unchanged, the entry usually carries the assume-unchanged or skip-worktree bit, and both are shown per entry and counted at the top along with intent-to-add. Entries written by git update-index --index-info have a stat block of all zeros, which is normal rather than damage, so they are labelled as having no stat data instead of being printed with a 1970 timestamp. All three index versions are handled: version 2, version 3 with its extra flag word, and version 4, whose paths are prefix-compressed against the previous entry using git's own offset varint — get that decoding wrong and you still get plausible-looking paths, which is exactly why it is worth reading with something tested against real files. Nothing in the header says whether a repository hashes with SHA-1 or SHA-256, so both object-id widths are tried and the one whose entries and extensions land exactly on the trailing checksum is used; that checksum is then verified against the rest of the file. The extensions git appends after the entries are listed with their sizes and, where it is useful, their contents: the cached tree with how many of its subtrees are still valid, resolve-undo with the paths it remembers, the untracked cache, fsmonitor, and the offset tables that let git read a large index in parallel. A split index is recognised for what it is — a file whose paths are all empty because the real entries live in .git/sharedindex. What this cannot tell you is anything about the content: an entry names a blob by hash, and the blob itself is in .git/objects, which is a different file entirely.
Frequently asked questions
Why does git keep saying a file is unchanged when I have just edited it?
Almost always because the entry carries assume-unchanged (the on-disk bit git calls CE_VALID) or skip-worktree. Both tell git it may trust the index and skip the lstat comparison for that path, and both survive in the index until something clears them, which is why the effect looks permanent and follows the repository rather than your editor. They mean different things — assume-unchanged is a promise you make about a slow filesystem, skip-worktree is a statement that the file is deliberately absent or locally modified and should be left alone — but the symptom is identical. This page counts them and marks the entries carrying them, so you can find the path and run git update-index --no-assume-unchanged or --no-skip-worktree on it.
What is all the stat data in an entry for, and why is some of it zero?
Each entry caches ctime, mtime, device, inode, uid, gid, mode and size from the last time git looked at the working-tree file. On the next status git calls lstat() and compares: if every cached field still matches, the file cannot have changed and git skips reading and hashing it, which is what makes status fast in a big repository. All of the fields are truncated to 32 bits, so they are approximations by design. An entry whose whole stat block is zero has never been compared with a real file — that is what git update-index --index-info and the entries of a conflict produce — so it is shown as having no stat data rather than as a timestamp in 1970, which would be a fabrication.
Why does the version number in my index keep changing between 2, 3 and 4?
Version 2 is the baseline. Git writes version 3 the moment any entry needs the extended flag word, which is the only place skip-worktree and intent-to-add can live, and it silently drops back to 2 when the last such entry goes away — so marking one file with skip-worktree rewrites the whole file in a different version. Version 4 is opt-in (git update-index --index-version 4) and compresses each path against the previous one, saving real space in a repository with deep directory trees at the cost of making the file readable only front to back. All three are read here, and the version is taken from the header rather than guessed.
My .git/index is tens of megabytes. What is actually in it?
Each entry costs about 62 bytes plus its path, so a hundred thousand files is only a handful of megabytes; anything much larger is usually an extension. The untracked cache (UNTR) stores a directory-by-directory record of everything not tracked and grows with the junk in your working tree. The cached tree (TREE) stores one record per directory. On a repository with a huge number of files git may also be using a split index, where the bulk lives in .git/sharedindex.<id> and the file you opened is mostly a link extension. The extensions table here shows the size of each one, which is the fastest way to see which is responsible.
What does the checksum at the end of the index protect against?
The last twenty bytes (thirty-two in a SHA-256 repository) are a hash of everything before them, written every time git rewrites the file. It catches truncation and corruption — a crash mid-write, a bad disk, a partial copy — but not deliberate tampering, since anyone editing the file can recompute it. If it does not match, git refuses to use the index at all. That is recoverable: the index holds no content of its own, so deleting it and running git reset rebuilds it from HEAD. What you lose is the arrangement — which paths were staged, and any intent-to-add entries — not the objects, which are already in .git/objects. One exception: with index.skipHash, which feature.manyFiles turns on, git writes twenty zero bytes here and skips the hash entirely, so an all-zero trailer is shown as not computed rather than as a mismatch.
Does the file get uploaded anywhere?
No. The index is read with the browser's File API and decoded by JavaScript in the page; there is no server side to send it to. That matters more here than for most formats, because .git/index is a complete list of the paths in a private repository along with the hash of every staged file — the sort of thing that should not be pasted into a web form. You can load this page, disconnect from the network, and everything still works.
Related tools
Git Config Precedence Tester
Paste your git config files and see which value wins for every key, the scope, file and line it came from, what it overrode, and which includeIf fired.
Developer
Java Class File Inspector
Read a compiled .class file in the browser: class file version and JDK release, access flags, constant pool, fields, methods and referenced classes.
File
Ogg Container Inspector
Walk an .ogg, .oga or .opus page by page: granule positions, segment tables, CRC32 checks, and the logical streams the container carries.
File
Git Packfile Inspector (.pack / .idx)
Read a .pack and .idx pair in the browser: every object with its type, size, offset, delta depth and base, totals by type and the biggest objects.
File
TAR Inspector
Open a .tar, .tar.gz or .tgz and list every entry — permissions, owner, size, timestamp and link target — without extracting it.
File
xz (.xz) Stream Inspector
Read an .xz container: stream header, every block header and filter chain, the index and the footer — with the true uncompressed size, unpacking nothing.
File