Git stores the entire file for each modification to it

A simple repo with just one file, .gitignore and a couple of commits

csetariq@workstation: dotfiles (master) $ git log --patch
commit cd8c0bdcf87c69ce55cf97446ed89f37f7fdf6a4 (HEAD -> master)
Author: csetariq <csetariq@gmail.com>
Date:   Wed Oct 20 14:50:35 2021 +0530

    Exclude IntelliJ

diff --git a/.gitignore b/.gitignore
index dc0d833..d9332c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
 target/

+# IntelliJ
+.idea/
+

commit f4db303f7732a761f20c46190f7f59569e47ba99
Author: csetariq <csetariq@gmail.com>
Date:   Wed Oct 20 14:49:40 2021 +0530

    Initial Commit

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dc0d833
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target/
+

Let's follow the commit tree backwards

csetariq@workstation: dotfiles (master) $ cat .git/refs/heads/master
cd8c0bdcf87c69ce55cf97446ed89f37f7fdf6a4

Last commit object

1
2
3
4
5
6
7
csetariq@workstation: dotfiles (master) $ git cat-file -p cd8c0bdcf87c69ce55cf97446ed89f37f7fdf6a4
tree f1837972b430fe168db1bdc10b982b7b72d72ed7
parent f4db303f7732a761f20c46190f7f59569e47ba99
author csetariq <csetariq@gmail.com> 1634721635 +0530
committer csetariq <csetariq@gmail.com> 1634721635 +0530

Exclude IntelliJ

First commit object

1
2
3
4
5
6
csetariq@workstation: dotfiles (master) $ git cat-file -p f4db303f7732a761f20c46190f7f59569e47ba99
tree 7f6bfff7f3bee94725de11412ad6eda697e5d59c
author csetariq <csetariq@gmail.com> 1634721580 +0530
committer csetariq <csetariq@gmail.com> 1634721580 +0530

Initial Commit

Let's see the contents of the tree

Tree object of first commit

csetariq@workstation: dotfiles (master) $ git cat-file -p 7f6bfff7f3bee94725de11412ad6eda697e5d59c
100644 blob dc0d833af175411f8bc64034aa6b571566041719    .gitignore

Tree object of last commit

csetariq@workstation: dotfiles (master) $ git cat-file -p f1837972b430fe168db1bdc10b982b7b72d72ed7
100644 blob d9332c4930fd7dd3e2964a0243dd553f8eadfb63    .gitignore

Let's look at the contents. Complete file is stored for each modification

1
2
3
4
5
6
7
8
csetariq@workstation: dotfiles (master) $ git cat-file -p dc0d833af175411f8bc64034aa6b571566041719
target/

csetariq@workstation: dotfiles (master) $ git cat-file -p d9332c4930fd7dd3e2964a0243dd553f8eadfb63
target/

# IntelliJ
.idea/

I thought git cat-file command intelligently applied the patch and showed me the complete file. But NO!

csetariq@workstation: dotfiles (master) $ ls -l .git/objects/dc/0d833af175411f8bc64034aa6b571566041719
-r--r--r-- 1 csetariq csetariq 24 Oct 20 14:49 .git/objects/dc/0d833af175411f8bc64034aa6b571566041719

csetariq@workstation: dotfiles (master) $ ls -l .git/objects/d9/332c4930fd7dd3e2964a0243dd553f8eadfb63
-r--r--r-- 1 csetariq csetariq 43 Oct 20 14:50 .git/objects/d9/332c4930fd7dd3e2964a0243dd553f8eadfb63

csetariq@workstation: dotfiles (master) $ cat .git/objects/dc/0d833af175411f8bc64034aa6b571566041719 | openssl zlib -d
blob 9target/

csetariq@workstation: dotfiles (master) $ cat .git/objects/d9/332c4930fd7dd3e2964a0243dd553f8eadfb63 | openssl zlib -d
blob 28target/

# IntelliJ
.idea/

csetariq@workstation: dotfiles (master) $

Git stores a header followed by the content of the file and then compresses it.

blob {size}\0{content}

Checkout Pro Git Book

Edit Report
Pub: 20 Oct 2021 09:49 UTC
Views: 243