After some time using Git, you almost certainly know the best ways to use it every day, including the most useful commands.

When you achieve this level of understanding of how to use a tool, it’s time to delve deeper into its concepts, architecture, and structure.

In this post, we will understand how Git organizes its information and how it persists this information in its file structure.

The HEAD in .git/HEAD

HEAD is a file that contains the name of the current branch.

ref: refs/heads/dev

In this example, your HEAD is pointing now to dev branch.

HEAD can also be a commit ID, which is called a detached HEAD state.


Branches in .git/refs/heads/

Each branch is stored as a file that contains 1 (only one) commit ID.

These files are stored in a folder called refs/heads.

refs/heads folder

In the picture each file is the name of a branch, and the folders represent branch names with a / separator, like fix/BUG-123. In this example BUG-123 will be a file with this name and maybe the following commit ID:


Tags, stash, remotes all in .git/refs

Just as branches live in .git/refs, also tags, stash, remotes.

- .git
-- refs
--- heads <- *branches*
--- remotes
--- stash
--- tags

Commits in .git/objects

A commit is saved in a file containing its parent(s), message, tree and author.

These information is compressed, and the best way to see git objects is using the command:

git cat-file -p HASH

On above command HASH is the commit ID.

git cat-file -p 95173d8501

# output
tree e0645455629c2bd9d64b81fb17503dcb4df5bd9f
parent 81b21476b2c5d19a8fdbf9d414b42088c94484c8
parent 7473e3c226411ed5252539ca9d337de0a6f9ccbb
author Ademir Mazer Jr [ Nuno ] <[email protected]> 1697586900 -0300
committer GitHub <[email protected]> 1697586900 -0300
gpgsig -----BEGIN PGP SIGNATURE-----

Merge pull request #705 from Mazer/1510-planilha-prod-preco

fix: staus de completo da classe quando não tem um item na NF do pedido

Trees in .git/objects

Trees are files with directory listings. This files in it are called blobs.

git cat-file -p master^{tree}

# output
100644 blob 6537ca4677ee97ddcb112f22d086b92721fd578c	.editorconfig
100644 blob 354be23c7b01803db48f6008a82ce042e41f9a04	.env.example
100644 blob 967315dd3d16d50942fa7abd383dfb95ec685491	.gitattributes
100644 blob f6fb8a7f6d07dd3f7a624bb373f87be0365cc569	.gitignore
100644 blob 57f7d3b20c41447e1c9f6cc80fd161b9cad54d42	.rnd
040000 tree 42f824c3c2b6743a468d08893b3fdaa453316fc5	.scribe
100644 blob 9231873a112ba0ded2550a45741bad544e7a1998	.styleci.yml
040000 tree e7170f21fba71d487011969e6eebae029cbc2afd	.vscode
100644 blob 80258098b18a85ff17ccf7d29259886882ee97be
040000 tree e489d9339d4dfd9c025a40053c18815596d1df08	app
100644 blob 5c23e2e24fc5d9e8224d7357dbb583c83884582b	artisan
040000 tree fa579600b150dfe96277f923c509bc473517b32a	bootstrap
100644 blob 08183152f2089d6c229474c8eb020fd54fe0070c	composer.json
100644 blob 67772e4ece555d51d3833d5f1b8c634902ceb709	composer.lock
040000 tree bf28bd62dc2e4604e853c6aac64b4ee6bb79c762	config
040000 tree 48955a5c0935bcb7c88b1cbb0599eba405b66b36	database
100644 blob 769dd5516e2308eff567d1774de12a842db7f16b	package-lock.json
100644 blob ca5629bc4cd598cae98b89c723a707b3f7bc6b38	package.json
100644 blob 90952f05a7c49f0ebc6af0fe4f7b332cd61ea586	phpstan.neon
100644 blob 4ae4d979d1ecc9bb45aabf0ff7071ce0e63bd4e2	phpunit.xml
040000 tree 2297374bcd5c5d552865315e4d310cc14de468d7	public
040000 tree a6ef03f417eff40e2e6a1e19ff020a789c2dc201	resources
040000 tree 33d6539ee1ae71d17961971a618825157083e38a	routes
100644 blob 5fb6379e71f275a1784e6638adc96420aaa5c5b2	server.php
040000 tree d0be5083619e6e92c3408f2455afd9b338970e16	storage
040000 tree d50aa6e9b745b0dba78abd8fa5b1c9a57946a46a	tests
100644 blob b9889e995f67106aebdb994d29c30e4dd5a85325
100644 blob 6189710be60e7cb518dc9f5e7eea7d4b88879388	webpack.mix.j

Blobs in .git/objects

Blobs are the files that contain your actual content (source code, texts, etc).

git cat-file -p 6537 

# output
root = true

charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

trim_trailing_whitespace = false

indent_size = 2

Look at first line of previous section (Trees), 6537 is the hash code of the blob file for .editorconfig.

Reflog in .git/logs/refs/heads/main

reflog stores the history of every branch, tag and HEAD in folder .git/logs/refs. In this directory, HEAD file stores the full HEAD log. In sulfolders inside refs there are logs story for heads and remotes.

Each line of reflog has:

  • before/after commit IDs
  • user
  • timestamp
  • log message
0000 6e6b Ademir Mazer Junior <[email protected]> 1695844143 -0300	branch: Created from HEAD
6e6b 075d Ademir Mazer Junior <[email protected]> 1695847428 -0300	commit: feat: #1510 planilha modelo com produtos
075d af8b Ademir Mazer Junior <[email protected]> 1697505509 -0300	commit: fix: corrige atualização de preço promocional pela planilha
af8b ff78 Ademir Mazer Junior <[email protected]> 1697544622 -0300	commit: fix: nome da classe
ff78 7473 Ademir Mazer Junior <[email protected]> 1697586865 -0300	commit: fix: staus de completo da classe quando não tem um item na NF do pedido
7473 44a1 Ademir Mazer Junior <[email protected]> 1698783202 -0300	commit: fix: cálculo de valor final e exception no cálculo de valor promocional

Remote tracking branches in .git/refs/remotes/origin/main

The remote-trackingbranches store the most recently seen commit ID for a remote branch.

When git status outputs you're up to date with origin/main, it is referring to commit ID in the main file inside `refs/remotes/origin.


Config in .git/config

The repository configuration is stored in .git/config file. In this file you set remotes, author, and other repository settings.

Git has a local, global and system settings. Global configs are usually located at ~/.gitconfig.

To know more about configurations read Git Config: Username and Email Configuration.

Git config levels
Git config levels

Hooks in .git/hooks/pre-commit

The scripts called hooks in Git are optional, you can write then to do anything, and set up and run when some event occur on Git workflow, for example before a commit.

phpstan app/

Staging area in .git/index

The staging area stores files that are ready to be commited. The file where they are stored is a binary file called index.

To know more about git index read Git Index.

Final considerations

As software engineers and developers, a deep understanding of Git files and folder structure not only enhances our proficiency in using Git but also empowers us to troubleshoot, optimize, and leverage Git to its fullest potential.