1. Courses
  2. Developer Foundations
  3. Git from the Inside
  4. Stop 7

40 minAdvanced

Inside the .git folder: objects, refs and HEAD

Everything Git knows about your project lives in one hidden folder. It holds only two kinds of thing: objects named by a fingerprint of their content, and small name files that point at them. Once you have walked from HEAD to a file's bytes by hand, every command in this course stops being magic.

By the end you can

  • Explain content-addressable storage and why the same content always gets the same ID
  • Name the four object types and walk commit, tree and blob with git cat-file
  • Read refs, packed-refs and HEAD, and explain why a branch costs almost nothing
  • Recognise a detached HEAD and save work made in it
  • Describe packfiles, delta compression and where SHA-256 fits, and compute a blob ID yourself in code

The everyday picture

Imagine a distribution centre where every carton gets a label computed from exactly what is inside it. Pack 24 bottles of the same sunflower oil and you get the same label, every time, in any of the four DCs. Two identical cartons? You only need to store one. Change one bottle and the label changes, so nobody can swap contents without it showing.

Next to the racks hangs a board of index cards: "Festival stock: carton 3f9a...", "Current price list: carton 81c2...". The cards are cheap. Moving a card to a new carton takes a second and moves nothing heavy. Git's .git folder is that DC. The cartons are objects, labelled by their content. The cards are refs: branches and tags.

Content-addressable storage

Git stores data in an in .git/objects. Each object's name is the of its content. This is called . For a file, Git hashes a short header (the word blob, a space, the size in bytes and a zero byte) followed by the file's bytes. The result, in a normal repository, is a 40-character ID such as cd39bff4ac5ff93704ecccc19d3e86bc886791af.

Three consequences follow, and most of Git's behaviour comes from them:

  • Same content, same ID, everywhere. Your laptop and a teammate's compute identical IDs for identical files, which is why fetching only sends objects the other side lacks (GitHub: remotes, clone, push and pull).
  • Storage is deduplicated. A file unchanged in 500 commits is stored once. 500 copies of the same logo are one object.
  • Objects never change. Changing content means a new ID, so an "edited" object is really a new one. That is why amend and rebase create new commits (Rewriting history safely), and why git fsck can detect a corrupted file: its content no longer matches its name.

On disk, a new object is a : zlib-compressed, in a folder named by the first two hex characters, with the other 38 as the file name. That is why you see folders like .git/objects/cd/.

Quick check

Git has just written a loose object with ID 6195263fe767120970c04b6f61c22cf22215ebf5. Where is it on disk?

Loading the rest of the lesson…