.git directory introduction

吳哲賢
NTUST-AIVC
Published in
5 min readSep 12, 2023

After understanding the purpose and basic operations of git, we will find that after we create a local repository, your workspace will create a hidden folder .git. This is where git stores all version history, data, branches, etc. Let’s briefly introduce them!

$mkdir t1
$cd t1
$git init
Initialized empty Git repository in /home/abudy/t1/.git/
$tree .git
.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
├── heads
└── tags

.git / branches/

A slightly deprecated way to store shorthands to be used to specify a URL to git fetch, git pull, and git push. A file can be stored as branches/<name> and then a name can be given to these commands in place of a repository argument. This mechanism is legacy and not likely to be found in modern repositories.

.git / config

Various configuration options and parameters for storing Git repositories. It usually contains information such as the global configuration of the Git library, user configuration, and remote library configuration. As shown below:

$cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = git@github.com:AbudyWu/hw1.2.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main
[branch "test"]
remote = origin
merge = refs/heads/test

The [core] section contains global configuration options for the Git repository, such as the format version, file modes, and log updates. These options apply to all branches and commits.

The [remote “origin”] section contains configuration information for the remote repository of the Git repository, such as the URL address of the remote repository and rules for pulling and pushing branches. These options are used to synchronize the local repository with the remote repository.

The [branch “main”] section contains the configuration for the branches in the Git repository, it shows the pair of remote branch and local branch.

In summary, the .git/config file contains various configurations for the Git repository, which is important for managing the Git repository and pushing code to the remote repository. Developers can customize the behavior and functionality of the Git repository by modifying these configuration options.

.git / HEAD

In simple terms, we can think of HEAD as the “current branch”. When we use git checkout to switch branches, HEAD will change to point to the new branch. In addition, when we checkout to not a branch, .git/HEAD can also save the commit HASH value at that point. As shown below :

$cat .git/HEAD
ref: refs/heads/main
$git checkout 13bb9da3f5dae82160bd00495c728c097338f0d0
Note: switching to '13bb9da3f5dae82160bd00495c728c097338f0d0'.
You are in 'detached HEAD' state.
.
.
.
$cat .git/HEAD
13bb9da3f5dae82160bd00495c728c097338f0d0

.git /ORIG_HEAD

When we are using commands such as merge, rebase, reset, etc. that will cause historical changes, the ORIG_HEAD file will record the position of HEAD before execution.

.git / hooks

Git hooks are a mechanism that can trigger the execution of scripts before and after we execute certain commands. These hooks are of two types: client and server. If you want to edit hook scripts that are preset to be off, you’ll have to rename them; their filenames all end in .sample. The link below provides a detailed description of each hook script:

.git / info/

Additional information about the repository is recorded in this directory. Currently, there is only one file whose content is annotations.

$cat .git/info/exclude
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

.git / objects/

To put it bluntly, it is the place where all files are stored. Before explaining its operating principle, first introduce the four file types of blob, tree, commit, and tag.

from:https://ithelp.ithome.com.tw/articles/10276087
Schematic diagram of blob tree commit relationship
  1. blob: Suppose we create a text file in HEAD folder and pull it to the temporary storage area withgit add”, Git will convert the file content into binary and generate an “object” stored in SHA-1, called a blob.
  2. tree: Tree can help us store the name of the file, the name of the directory, and file permissions. Like blob, it also uses SHA-1 as the file name to store binary content. The difference is that the blob stores the content, the tree stores the file name, and the tree can also contain another tree beside the blob. We can use the Tree object to find some file content or file names under the subdirectory.
  3. commit: When we execute git commit, we can find that in addition to tree-type files to store file names, we can also find commit files that also have SHA-1 file names. Through “git cat-file -p <SHA-1>”, you will see the following complete information:
    1. Tree object.
    2. Point to the parent of the last commit.
    3. The time of this Commit.
    4. The message of this commit.
  4. tag: We can think of the tag as a note paper specially used to paste on the commit, recording the SHA-1 of the commit and stored in .git/refs, usually used to record the commit of an important version.

Introduce SHA-1 : https://zh.wikipedia.org/wiki/SHA-1

$vim A.txt
$tree .git/objects
.git/objects
├── 45
│ └── b983be36b73c0788dc9cbcb76cbb80fc7bb057
├── info
└── pack
$git cat-file -t 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
blob
$git commit
$git tag -a check -m "tag test"
$tree .git/objects
.git/objects
├── 45
│ └── b983be36b73c0788dc9cbcb76cbb80fc7bb057
├── 66
│ └── 4e5e21d7b38bc020ab1dcb3cf760471e17aa8f
├── 6f
│ └── aa1e8399eba696f21af478469aff34cf38e7dc
├── d5
│ └── 523ebbf963c0d8ae77cad818ee2874b097611f
├── info
└── pack
$git cat-file -t d5523ebbf963c0d8ae77cad818ee2874b097611f
tree

$git cat-file -p d5523ebbf963c0d8ae77cad818ee2874b097611f
100644 blob 45b983be36b73c0788dc9cbcb76cbb80fc7bb057 A.txt

$git cat-file -t 664e5e21d7b38bc020ab1dcb3cf760471e17aa8f
commit

$git cat-file -p 664e5e21d7b38bc020ab1dcb3cf760471e17aa8f
tree d5523ebbf963c0d8ae77cad818ee2874b097611f #
author AbudyWu <B11007143@gapps.ntust.edu.tw> 1680523847 +0800
committer AbudyWu <B11007143@gapps.ntust.edu.tw> 1680523847 +0800

dev1

$git cat-file -t 6faa1e8399eba696f21af478469aff34cf38e7dc
tag

$git cat-file -p 6faa1e8399eba696f21af478469aff34cf38e7dc
object 664e5e21d7b38bc020ab1dcb3cf760471e17aa8f
type commit
tag check
tagger AbudyWu <B11007143@gapps.ntust.edu.tw> 1682100677 +0800

tag test

.git / refs/

It contains two folders, namely heads, and tags.

heads/
Are used to store the commit SHA-1 value pointed to by the current branch.

$tree heads
heads
├── dev
└── main
$cat heads/main
23596618c886d0a38be6eeefad2845bbaa3ed6aa
$cat heads/dev
675dd53c1a04020548a39010d67f70ce399a0783

tags/
Store all tag files.

$git tag -a check -m "tag test"
$tree .git/refs
.git/refs
├── heads
│ ├── dev
│ └── main
└── tags
└── check

.git / logs/

$tree .git/logs
.git/logs
├── HEAD
└── refs
└── heads
├── dev
└── main

HEAD: It is the historical record of HEAD, which records your action and the commit SHA-1 value of that HEAD.

refs/heads/: Record the SHA-1 value of the last commit of each branch. Same as .git/refs/heads mentioned above.

--

--