Git: Beginner to Advanced
Git internals
See the objects and references behind each command.
Lesson 11 of 12
Reading: about 6 min
Lesson + practice: about 15 min
Difficulty: Advanced
On this page5 sections
See the objects and references behind each command. Follow the animated example, then use the sections below to review each idea.
Visual walkthrough
Use the player controls or jump menu to inspect each step. The diagram changes as the example moves forward.
The player shows one focused example. The sections below explain the ideas behind each topic.
Under every command is a small, simple design: Git stores snapshots as objects in a database inside .git, and uses a few named pointers to find them. Once you can see these pieces, commands like reset, rebase and reflog stop feeling like magic, and you can reason about what any command will do.
This lesson inspects a fresh repository containing one file, notes.md with the text “Hello”, as in the walkthrough above. You will use “plumbing” commands that look inside Git; they only read, so they are safe to try.
Blobs, trees, and commits
Git stores three main kinds of object:
- A blob holds the contents of one file. No name, no date: just the bytes.
- A tree is one folder: a list of names, each pointing at a blob or another tree.
- A commit points at the tree for the whole project, plus its parent commits, author, date and message.
Commit, then walk down from the commit
git cat-file -p prints an object. The commit points at a tree; the tree lists notes.md and the blob that holds its contents; the blob is the text itself. The number after the email is the time in seconds since 1970.
git commit -m "Add notes"
git cat-file -p HEAD
git cat-file -p b5c5a7499784b52836d9e36365218128ba294d5c
git cat-file -p e965047$ git commit -m "Add notes"
[main (root-commit) da840bf] Add notes
1 file changed, 1 insertion(+)
create mode 100644 notes.md
$ git cat-file -p HEAD
tree b5c5a7499784b52836d9e36365218128ba294d5c
author Alex Bennett <alex@example.com> 1792483260 +0100
committer Alex Bennett <alex@example.com> 1792483260 +0100
Add notes
$ git cat-file -p b5c5a7499784b52836d9e36365218128ba294d5c
100644 blob e965047ad7c57865823c7d992b1d046ea66edf78 notes.md
$ git cat-file -p e965047
HelloEvery commit after the first has a parent
The second commit records the commit before it. Following parent links from commit to commit is how git log builds the history.
git commit -m "Add copy"
git cat-file -p HEAD$ git commit -m "Add copy"
[main 8db9ed6] Add copy
1 file changed, 1 insertion(+)
create mode 100644 copy.md
$ git cat-file -p HEAD
tree 43c61d33fffa3f2033ed02611a5a6e7fd473502d
parent da840bf94e7c3eecce98ec0ade60805e59bb61ae
author Alex Bennett <alex@example.com> 1792483320 +0100
committer Alex Bennett <alex@example.com> 1792483320 +0100
Add copyReferences and HEAD
Nobody wants to type da840bf94e7c…. References are human-readable names for commits. A branch is a reference stored as a small file containing a commit ID, and a tag is another kind. HEAD is a reference to the branch you are on.
Look at the pointers themselves
.git/HEAD names the current branch. The branch file contains the full ID of its latest commit, the same one git rev-parse prints. Committing on main simply rewrites that one line.
cat .git/HEAD
cat .git/refs/heads/main
git rev-parse HEAD$ cat .git/HEAD
ref: refs/heads/main
$ cat .git/refs/heads/main
da840bf94e7c3eecce98ec0ade60805e59bb61ae
$ git rev-parse HEAD
da840bf94e7c3eecce98ec0ade60805e59bb61aeList every reference
After the second commit, main points at 8db9ed6. In bigger repositories you will also see tags and remote-tracking branches such as refs/remotes/origin/main here.
git show-ref8db9ed6816987f10382f8c322045881b13fcfb20 refs/heads/mainThe index
The index, or staging area, is a file (.git/index) listing every path for the next commit and the blob each path should use. git add stores the file's contents as a blob immediately and points the index entry at it. git commit then builds trees from the index.
git add writes the blob straight away
Before staging there are no objects. After git add there is one, the blob, even though nothing is committed. git ls-files --stage shows the index entry: file mode, blob ID, a stage number (0 means no conflict) and the path.
git count-objects
git add notes.md
git count-objects
git ls-files --stage$ git count-objects
0 objects, 0 kilobytes
$ git add notes.md
$ git count-objects
1 objects, 4 kilobytes
$ git ls-files --stage
100644 e965047ad7c57865823c7d992b1d046ea66edf78 0 notes.mdContent-addressed storage
An object's ID is a hash calculated from its contents (SHA-1 by default; newer repositories can use SHA-256). The same contents always give the same ID, on any computer. Change one character and the ID changes completely.
Same content, same ID, anywhere
git hash-object calculates the ID without storing anything. “Hello” plus a newline always hashes to e965047…, in your repository and in everyone else's.
git hash-object notes.md
echo "Hello" | git hash-object --stdin$ git hash-object notes.md
e965047ad7c57865823c7d992b1d046ea66edf78
$ echo "Hello" | git hash-object --stdin
e965047ad7c57865823c7d992b1d046ea66edf78Identical files are stored once
copy.md has the same contents as notes.md, so both index entries point at the same blob. After two commits there are only 5 objects: one shared blob, two trees and two commits. The object is stored in a folder named after the first two characters of its ID.
git ls-files --stage
git count-objects
ls .git/objects/e9$ git ls-files --stage
100644 e965047ad7c57865823c7d992b1d046ea66edf78 0 copy.md
100644 e965047ad7c57865823c7d992b1d046ea66edf78 0 notes.md
$ git count-objects
5 objects, 20 kilobytes
$ ls .git/objects/e9
65047ad7c57865823c7d992b1d046ea66edf78You copy a 50 MB video file to a second name in the same repository and commit both. Roughly how much extra space does the copy take in Git's database?
Reveal answer
Almost none. Both names point at the same blob, because the contents are identical. Only a slightly larger tree is stored.
Your teammate runs git hash-object on a file containing exactly “Hello” and a newline. What ID do they get?
Reveal answer
e965047ad7c57865823c7d992b1d046ea66edf78, the same as yours. Object IDs depend only on contents, not on who made them or where.
Your progress
Reveal the check answer or reach the end to complete this lesson.