Three words you'll use every day
Git's whole world is built from three ideas:
- A repository (or repo) is a folder that Git is watching. Git keeps its entire database inside a hidden subfolder called
.git. Delete.gitand the folder becomes an ordinary folder again. - A commit is a saved snapshot of the project at one moment, together with a message explaining it, the author's name, and the date. Think of it as a save point in a video game.
- The history is the chain of all commits, oldest to newest. Each commit remembers which commit came right before it, called its parent.
That's it. Everything else in this course is commands for creating commits, looking at them, and moving between them.
Snapshots, not diffs
A common misconception: people imagine each commit stores only the lines that changed. Mentally, treat it the other way. Each commit is a complete snapshot of every tracked file at that moment. (Internally Git compresses cleverly, so this costs almost no disk space.)
Every commit gets a unique id, a 40-character code like c7d8e9f2a91b... called a hash, computed from the commit's contents. Since the first 7 characters are almost always unique within a project, Git lets you use the short form, like c7d8e9f. When you see a hash in this course, that's all it is: the name of one specific snapshot.
Why the id is computed, not counted
Git does not number commits 1, 2, 3. Each id is computed from the commit's contents, meaning the files, the message, the author, the date, and the parent, using a hashing function: a function that turns any text into a fixed-length code.
That choice has two consequences, and together they are what make Git trustworthy.
- The same contents always produce the same id, on any computer. Your machine and a teammate's machine agree on every commit's name with no central numbering authority involved, which is precisely what lets separate copies of a repository cooperate in unit 7.
- Changing anything, even one letter, produces a completely different id. A commit therefore cannot be quietly altered after the fact, because altering it renames it.
Numbering would fail both tests. Two people working offline would each hand out a commit number 5 for different work, and editing an old commit while keeping its number would leave no trace at all.
Both rules are easy to watch directly, which is what the next example does.
Watching a hash behave
This runs sha1, the hashing function Git has historically used, on two versions of a small snapshot. Hashing identical text twice gives the same id, and changing one word gives a completely unrelated one. The [:7] slice keeps the short form you see in git log.
import hashlib snapshot_a = "Pancakes\n- flour\n- eggs\n- milk\n" snapshot_b = "Pancakes\n- flour\n- eggs\n- oat milk\n" print("snapshot A:", hashlib.sha1(snapshot_a.encode()).hexdigest()[:7]) print("snapshot A again:", hashlib.sha1(snapshot_a.encode()).hexdigest()[:7]) print("snapshot B:", hashlib.sha1(snapshot_b.encode()).hexdigest()[:7])
Output
snapshot A: aab29bf snapshot A again: aab29bf snapshot B: db347c6
The first two lines hashed the same text and produced exactly the same id, with no randomness and no state carried between the calls. That repeatability is what makes the id a name rather than a serial number.
The third line differs from the first by two characters of input, yet db347c6 shares nothing with aab29bf. A hash does not change proportionally to the input, which is why a tampered commit cannot keep a similar-looking id and hope to pass unnoticed.
A single Git commit contains a full snapshot of every tracked file, plus a message, an author, a date, and a link to its parent commit.
The phrase to keep in mind is snapshot rather than diff. Each commit records the complete state of the project at one moment, not just the lines that moved, and Git computes a diff between two snapshots whenever you ask for one.
That distinction explains behavior you will meet later. Checking out an old commit can restore the whole project immediately, with no need to replay a chain of changes, and a corrupted commit in the middle of history does not invalidate the ones after it.
Git stores its entire database in a hidden folder called .git.
It sits at the top level of the repository and holds every commit, the full history, and Git's settings for that project. The leading dot is what hides it from a plain ls on Linux and macOS, which is why seeing it requires ls -a as covered in the terminal course.
Knowing this makes two facts concrete. Deleting .git turns the repository back into an ordinary folder, keeping the current files and losing all history, and copying a project folder copies its entire history along with it, since the history lives inside the folder rather than on a server.
With commit 2 made right after commit 1, the true statement is that commit 2 stores a pointer back to commit 1, its parent.
Links always point backwards in time, and the reason is structural rather than stylistic. When commit 1 was created, commit 2 did not exist, so there was nothing for commit 1 to point at. A commit knows its parent and can never know its children.
There is a second reason the links cannot run forward. A commit's id is computed from its contents, so adding a child pointer later would change the parent's contents and therefore its id, breaking every reference to it. That backwards chain of parent pointers is what the word history refers to.