Skip to content

Why Git?

The previous lesson introduced version control in general. This lesson looks specifically at Git: what came before it, why it was created, and why its core design choices — distributed history, speed, and content-addressable storage — turned out to matter so much.

Git was not the first version control system. Earlier systems included:

  • SCCS
  • RCS
  • CVS
  • Subversion (SVN)
  • BitKeeper

Systems such as SVN already supported history, collaboration, branches, and merging by the time Git appeared. Git was not created simply because earlier systems had no branches — the real reasons have more to do with how those systems were designed internally, which the next sections unpack.

The Linux kernel is a very large project developed by thousands of contributors. Its development previously relied on BitKeeper, a proprietary distributed version control system offered free of charge to open-source projects.

In 2005, that free-use arrangement ended. Linus Torvalds, the creator of Linux, started building a new version control system to support the Linux kernel’s development workflow — and that project became Git.

Git was designed around a specific set of priorities:

  • Distributed development, so every contributor has a full copy of history.
  • Speed, for common day-to-day operations.
  • Offline local work, without depending on a central server.
  • Efficient branching and merging.
  • Support for very large projects with many contributors.
  • Data integrity, so corrupted or tampered history can be detected.
  • Reliable tracking of project history over time.

4. Centralized versus distributed repositories

Section titled “4. Centralized versus distributed repositories”

The previous lesson already covered the general difference between centralized and distributed version control, so this section focuses on what that means concretely for Git.

A normal Git clone contains:

  • The project files.
  • A local repository.
  • The commit history available at clone or fetch time.
  • Branches and references.
  • The underlying Git objects.

Because all of that lives on the developer’s machine, many operations never need to contact GitHub or any other server:

Terminal window
git add
git commit
git log
git diff
git branch
git merge
git rebase

Operations that exchange data with a remote repository still require access to that remote:

Terminal window
git fetch
git pull
git push

Many Git operations work entirely with local files and local repository data rather than making a network request:

  • git log reads the commit history stored locally.
  • git diff compares local states such as the Working Tree, the Index, and already-committed data.
  • Creating commits and branches does not require GitHub or any remote at all.
  • Network speed has no effect on normal local Git operations, since they never touch the network.

It helps to keep these two ideas clearly separate:

Git = the version control tool
GitHub = a repository hosting and collaboration platform

Git can operate:

  • Without GitHub.
  • Without internet access.
  • With GitLab or Bitbucket instead.
  • With a private, self-hosted server.
  • With multiple remotes at once.
  • Entirely locally, with no remote at all.

Branching is a good example of how differently Git and earlier systems are built internally.

In SVN, branches are commonly represented as ordinary directories inside the repository, created with a command such as svn copy. SVN uses a “cheap copy” mechanism: creating a branch does not immediately duplicate every file’s content physically, but the branch is still fundamentally a path inside the repository, following a directory convention such as:

/trunk
/branches/payment-feature
/tags/v1.0

In Git, a branch is not a directory or a copy of anything. It is a lightweight, movable reference that points at a commit:

branch → commit

Moving a Git branch forward, or creating a new one, means changing what commit a small reference points to — not copying any files. The full mechanics of creating, switching, and merging branches belong to a later phase of this course; this lesson only introduces the underlying idea.

Git models each commit as a snapshot of the whole project. That does not mean Git blindly creates a complete physical duplicate of every unchanged file for every commit. A simplified example:

Commit A:
app.php → Blob X
user.php → Blob Y
Commit B:
app.php → Blob X
user.php → Blob Z
  • app.php reused the existing blob X because its content did not change.
  • user.php received a new blob Z because its content changed.
  • Existing Git objects are immutable — once created, an object’s content never changes.
  • Old objects are not overwritten when new content is added; a new object is created alongside them instead.

Git objects — blobs, trees, and commits — are covered in much more depth in a later phase. This lesson only introduces the idea that a “snapshot” is a logical model, not a literal full copy of every file.

Git is a content-addressable system: it identifies an object by its content, not by a filename.

  • The filename is not stored inside the blob itself.
  • Filenames, directory structure, and file modes are represented by tree entries instead.
  • Two files with identical content can reference the same blob.
  • Changing the content produces a different object ID.
  • Renaming a file without changing its content can reuse the same blob while producing a different tree.
Before rename:
Tree A
└── invoice.php → Blob X
After rename:
Tree B
└── old-invoice.php → Blob X

Git usually detects a rename by comparing snapshots and noticing that the content is highly similar — it does not store a permanent, standalone “rename operation” as its own kind of object.

Git uses cryptographic hashes to identify and verify its objects.

  • Changing an object’s content normally changes its object ID.
  • Because of this, Git can detect corrupted or mismatched objects.
  • Hashing is not encryption — a hash is not used to recover the original content, only to identify and verify it.
  • Hash collisions are theoretically possible, but they should not be presented as something that happens in normal, everyday use.

The command git fsck can check the integrity of a repository’s objects. It is only introduced here as a name to recognize — its detailed usage belongs to a later phase.

This short experiment mirrors the one completed during this checkpoint.

Create two files with identical content:

Terminal window
printf "same content\n" > file-a.txt
cp file-a.txt file-b.txt
git hash-object file-a.txt
git hash-object file-b.txt

Both commands print the same object ID, because Git derives the ID from the file’s content, and the content is identical.

Now change one of the files:

Terminal window
printf "changed content\n" > file-b.txt
git hash-object file-a.txt
git hash-object file-b.txt

file-b.txt now produces a different object ID, while file-a.txt keeps its original one — the ID only changes when the content changes.

Terminal window
git hash-object <file>

only calculates the object ID; it does not store the object in the repository unless the relevant write option is used.

Changed file content
↓
New Blob
↓
New Tree
↓
New Commit

The tree changes because one of its entries now points at the new blob instead of the old one. The commit changes because it points at a new tree and carries its own commit metadata (parent, author, message, and so on). The deeper mechanics of these objects have their own dedicated phase later in this course.

Git was designed for fast, distributed development.
Every developer can have a local repository and history.
Most Git operations do not require a network connection.
Git identifies objects by their content.
Unchanged content can reuse existing objects.
Git works without GitHub.
1. Why was Git created if version control systems already existed?

Earlier systems such as SVN already had history, branches, and merging, so missing features were not the core problem. Git was created specifically to support the Linux kernel’s workflow after the free-use BitKeeper arrangement ended, and it was designed around distributed history, speed, offline work, and efficient branching in ways earlier systems were not.

2. Why can Git perform many operations offline?

A normal clone already contains the project files, a full local repository, the available commit history, and Git’s objects and references. Operations such as git add, git commit, git log, git diff, git branch, git merge, and git rebase only need what’s already on disk, so they work without a network connection. Only operations that exchange data with a remote, such as git fetch, git pull, and git push, need connectivity.

3. Does a Git snapshot physically duplicate every unchanged file?

No. A commit represents a complete logical snapshot, but unchanged files keep pointing at their existing blob. Only files whose content actually changed get a new blob; Git does not create a fresh physical copy of every file for every commit.

4. Can two differently named files reference the same blob?

Yes. A blob is identified by its content, not its filename. If two files have identical content — even under different names or in different folders — they can reference the exact same blob, since Git stores content once and lets multiple tree entries point at it.

5. Why does changing one file’s content eventually produce a new tree and commit?

Changing a file’s content produces a new blob (existing objects are immutable, so Git cannot edit the old one in place). Because one of the tree’s entries now needs to reference that new blob, Git creates a new tree. Because the commit needs to reference that new tree, Git creates a new commit as well.