The .git/objects directory in Git

Git consists of three main directories:

./ your project directory/working directory
./.git/objects the archive/index directory
./.git/refs the branch/reference directory

The working directory is the root directory of your project, just as you created it. Inside of it, there will be a .git subdirectory created by Git, where Git stores all of its files.

The ./.git/objects directory is the archive/index directory. It will contain a copy of each version of your files (archive), and an index of each version of your project with its directory and file structure (index).

Each file in the ./.git/objects directory is named with a hashtag, that is, is a sequence of 40 hexadecimal characters, it has no explicit meaning but it is unique and not random (like an ID in a database).

To avoid putting thousands of files in the same directory, Git uses the first two characters of the hashtag as the directory (for example, file 6eebd841e22d0bb761eb391f1b961630e7e4ada5 will go into the subdirectory ./.git/objects/6e, so the full pathname of the file will be ./.git/objects/6e/ebd841e22d0bb761eb391f1b961630e7e4ada5)

Files inside the archive/index are of three types:

  • blob: stores the content of each version of your file
  • tree: stores the version of files and subdirectories in a particular directory
  • commit: stores the informations about a commit

A blob is the simplest type of file. It stores the content of the version of the file at the time you added it to the archive/index directory, compressed. It does not store its filename, however.

A tree is just a list of files (or, to be precise, a hashtag to their blobs plus their filename) and of hashtags to other trees (they represent the subdirectories). It is similar to what you would get with a ls (or dir) command. For example, a tree can contain:

code type hashtag file/folder name
100644 blob 4d1c430bd04b8aea1ce399524cdecf93b9b71da7 filename1.txt
100644 blob 4d1c430bd04b8aea1ce399524cdecf93b9b71da7 filename2.txt
100644 blob 6eebd841e22d0bb761eb391f1b961630e7e4ada5 filename3.txt
040000 tree 1e73f604cd641c7f2f3d5437bbede6433e2f785d subdirectory1
040000 tree 753fefe1f0616dceec292b4a0a131699e8ca8e4c subdirectory2

A commit contains the hashtag of the root tree (that is, the root directory of your project at the time the version was saved), the hashtag of the parent commit, the author and the commit message.

To summarize:

  • a commit contains a tree and a parent commit
  • a tree contains blobs and other trees
  • a blob contains only itself

You can view any file you find in the .git/objects directory with the git cat-file hash command:

  • git cat-file commit 45093e5
  • git cat-file tree 753fef
  • git cat-file blob 4d1c43

or with the more general -p [pretty print] option, that works with any file type:

  • git cat-file -p 4d1c43

You do not need to be in the .git/objects directory to use that command, as Git will automatically search the file for you.

Everything in Git is about adding, moving, and removing files/subdirectories from your directory to the .git/objects and .git/refs directories.


See also