< Back to Blog

Exploring the .git Directory – How Git Stores Your Code

We all use Git every day, but how many of us truly understand what's happening behind the scenes? Today, we're going to bravely venture inside the .git directory, unpack its most important contents, and demystify how Git actually works.

There's a mysterious .git folder at the root of every repository. You probably know that this folder serves as the brain, heart, and engine room of your project's version control system, even though it is often ignored and sometimes feared.

If you've ever wondered what types of files and folders exist inside this magical folder, then this tour is for you.

Ready for some enlightenment? Let's dive in!

1. What is the .git directory for?

At its core, Git is a content-addressable filesystem, and the .git directory is where all that content (and the pointers to it) lives. It's the repository itself, containing everything Git needs to know about your project's history, branches, configuration, and more. Your working directory (where your actual files are) is just one projection of what's inside .git.

Let's start by listing its contents. Navigate to the root of any Git repository in your terminal and type ls -F .git/. You'll see something like this:

branches/        HEAD        hooks/        logs/        objects/        refs/        config        description        index        info/

The exact contents might vary slightly depending on your Git version and repository state. Please note that the branches/ directory is a legacy remnant from older versions of Git and is no longer used in modern repositories.

You may also notice a COMMIT_EDITMSG file in the listing, which stores the message from your most recent commit that Git uses when you run git commit --amend.

Each of these files and directories plays a crucial role. Let's break them down.

2. The HEAD File (Your Current Position)

One of the most fundamental files in .git is HEAD. It's usually a simple text file that contains a reference to your current branch.

# Example content of .git/HEAD when on the 'main' branch
cat .git/HEAD
# Output: ref: refs/heads/main

This tells Git that your current HEAD (your "current commit") is the latest commit on the main branch.

What about a "Detached HEAD"?

When you git checkout <commit-hash>, the HEAD file changes to point directly to a commit hash, rather than a branch.

# Example content of .git/HEAD in a detached HEAD state
cat .git/HEAD
# Output: 8b0e7a2b... (40-character SHA-1 hash)

This is a "detached HEAD" state. It means you're directly on a commit, not on a branch. This simple file's content is the key to understanding a concept that often confuses new users!

Not a Tower user yet?

Download our 30-day free trial and experience a better way to work with Git!

Tower app icon

3. The config File (Your Project's Local Settings)

You've likely used git config from the command line. This is Git's configuration system, which is immensely customizable.

The config file is where your local, repository-specific configurations are stored.

# Example content of .git/config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = https://github.com/your-org/your-repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
    remote = origin
    merge = refs/heads/main

This file contains settings like remote URLs, branch tracking information, and any specific overrides for this particular repository. It's neatly organized into [sections].

4. The index File (Staging Area)

The index file is a crucial binary file that represents your "staging area" or "cache". It is a dynamic snapshot of your project's state that is waiting to be committed.

When you run git add <file>, Git takes the current version of that file from your working directory, computes its hash, stores it in the objects directory, and updates the index file to record that this new version of the file is now staged for the next commit.

5. The objects Directory (The Heart of Git)

This is where the magic truly happens. The objects directory is Git's content-addressable database. Every piece of content — every file, every directory state, every commit message — is stored here as an "object", identified by its SHA-1 hash.

Inside objects/, you'll find subdirectories named after the first two characters of the SHA-1 hash. This helps distribute the objects more evenly across the filesystem. The remaining 38 characters form the filename itself, so a full object path looks like .git/objects/8b/0e7a2b9d1f3c5e7a9b2d4f6e8c0a1b3d5f7e9a.

There are three main types of objects:

  • Blob Objects: These store the actual content of your files. If two files have identical content, Git only stores one blob object and points to it twice.
  • Tree Objects: These represent the state of a directory at a given point in time. They contain a list of pointers to blob objects (for files) and other tree objects (for subdirectories). This is how Git stores directory structures efficiently.
  • Commit Objects: These are the commits you create. Each commit object stores:
    • A pointer to the top-level tree object for that commit (the root directory snapshot).
    • Pointers to its parent commit(s).
    • Author and committer information.
    • The commit message.

This elegant system means Git doesn't store "diffs" between file versions. Instead, it stores full snapshots, and computes the differences on the fly when you ask for them.

That said, you may also notice a pack/ subdirectory inside objects/. For efficiency, Git periodically compresses objects into binary pack files using delta compression — so while conceptually Git stores full snapshots, on disk it optimizes storage behind the scenes (you can trigger this manually with git gc).

6. The refs Directory (The Pointers)

The refs directory is where Git stores simple pointers to specific commit objects. This is where your branches and tags truly live.

  • refs/heads/: Contains one file for each local branch (e.g., refs/heads/main, refs/heads/feature/login). Each file contains the SHA-1 hash of the commit that branch currently points to.

    # Example content of .git/refs/heads/main
    cat .git/refs/heads/main
    # Output: 8b0e7a2b9d1f3c5e... (the latest commit on 'main')

    This means that a branch is nothing more than a movable pointer to a commit. Moving a branch (e.g., with git commit or git reset) simply means updating the SHA-1 hash in this file.

  • refs/tags/: Similar to heads, but for tags. Each file contains the SHA-1 hash of the commit (or tag object) that the tag points to. Tags are generally immutable pointers.

  • refs/remotes/: Tracks the state of branches on remote repositories (e.g., refs/remotes/origin/main).

7. hooks and logs (Automate and Observe)

Finally, two more important directories:

  • hooks/: This directory contains sample scripts (e.g., pre-commit.sample, post-merge.sample) that you can rename and activate. These are your Git Hooks, allowing you to run custom scripts before or after certain Git events. They're powerful for enforcing code quality, running tests, or deploying code. You can learn more about Git Hooks here.

  • logs/: This is where Git keeps its reflog (reference logs). The reflog is an incredibly useful safety net that records every time your HEAD (or a branch) has been updated. This means you can almost always recover "lost" commits or branches, as we discussed in our article on Force Push disaster recovery.

Final Words

If you've made it this far, congratulations! You're not just using Git anymore; you're truly understanding it!

By taking this guided tour of the .git directory, you now realize that Git is not a complex, magical black box, but an elegant and robust system built upon simple, interconnected objects and pointers. Now, if something goes wrong, you'll have a better intuition for troubleshooting.

For more in-depth guides, don't forget to sign up for our newsletter below and follow Tower on Twitter and LinkedIn!

Your Download is in Progress…

Giveaways. Cheat Sheets. eBooks. Discounts. And great content from our blog!