Skip to main content

Command Palette

Search for a command to run...

Inside Git: .git Folder Demystified

Updated
4 min read

The .git folder is essentially a generic key-value content-addressable database. It is created when a git repository is initialized using git init command.
Here is a complete breakdown of the .git folder.

The Root Level Files

These files sit directly inside .git folder and manage the state of the current working tree.

  • HEAD: This text file contains a reference to the current branch we are on.

    It’s content usually looks like: ref: refs/heads/main

  • config: This text file contains our local configuration. It stores the URL of our remote (origin), our user details (set locally), and branch tracking information

  • index: This is the staging area. This is the binary file which stores a sorted list of all files in our working directory. their permissions and the SHA1 hash of their content. Upon running git add, we are updating this file.

The objects / Directory (The Database)

Every file, every directory structure and every commit is stored here. Git is a content-addressable filesystem, i.e. it names file based on the SHA-1 hash of their contents.

There are four types of objects stored here:

  1. Blob (Binary Large Object)

    • It is the content of the file. It stores only the data, not the filename.

    • Ex: if we have 2 files README.md and INTRO.txt which has the exact same test “Hello“, Git stores only one blob.

  2. Tree

    • It represents a directory. It contains a list of other trees (subdirectories) and blobs (files), mapping names to their SHA-1 hashes.

    • It helps Git reconstructs your folder structure.

  3. Commit

    • It is a snapshot of the project at a specific time.

    • It contains a pointer to the top-level Tree (the root folder); a pointer to the Parent Commit (the previous state); and the Metadata (Author, Committer, timestamp, and message)

  4. Tag

    • An annotated tag (like v1.0.2) which points to a commit but includes extra metadata. Usually used alongside releases.

The refs / Directory (The Pointers)

It has the table of contents or the bookmarks.

  • refs/heads/ : Contains one file per local branch (e.g. main, feature-login). Git creates a new file at refs/heads/new-feature and writes the current commit hash into it.

  • refs/tags/ : Contains pointers for tags (e.g. v1.0.2)

  • refs/remotes/ : Contains the state of the branches on the server (e.g. origin/main). It gets updated when we do git fetch

Other Important Directories

  • hooks/

    This contains shell scripts that trigger automatically before or after Git events. Ex: pre-commit, post-merge

  • logs/

    It contains the Reflog (Reference Logs). Everytime HEAD or a branch tip updates, Git logs it here.

  • info/

    This acts like a local .gitignore file that is not shared with other collaberators. Useful for ignoring personal files like IDE settings.

Workflow

  1. The git add Phase: Creating Blobs and Updating the Index

When you run git add <filename>, Git does two specific things:

  • Creates a Blob: Git takes the content of your file, compresses it, and calculates a SHA-1 hash. It then stores this content as a blob object inside the .git/objects folder.

  • Updates the Index: Git updates the .git/index file (the staging area). This file acts as a map, linking your filename to the SHA-1 hash of the blob it just created. At this stage, your changes are tracked, but not yet part of the project history.

  1. The git commit Phase: Building the Snapshot

When you run git commit -m "message", Git solidifies the staging area into the permanent history:

  • Creates a Tree: Git creates a tree object that represents the structure of your project at that exact moment. This tree points to the blobs (files) and other trees (subdirectories) listed in the index.

  • Creates a Commit Object: Git creates a commit object that includes:

    • A pointer to the main tree object.

    • Metadata (author, committer, timestamp, and message).

    • A pointer to the parent commit (the SHA-1 of the previous commit), which is how Git maintains the chain of history.

  • Moves HEAD: Finally, Git updates the file in .git/refs/heads/[branch-name] to point to the SHA-1 of this new commit object.