What would you like to learn?

Try PowerShell, networks, XSS, or Step 138

Browse the full curriculum →

Developer tools

Step 86. Git Basics — A Time Machine for Code

Step 86Estimated practice · 2.5 hours

Level 1 — Programming and the Inside of a Computer | Difficulty ★★☆☆☆ | Estimated time: 2.5 hours

Prerequisites: Python basics from Steps 41–43, file handling from Step 46, and basic terminal operations.

  • What you need: a computer with Git installed. On Windows, keep Git Bash open — it’s installed together with Git.
  • Caution: all of today’s experiments happen only inside a new practice folder you create. Your existing work is untouched, so it’s 100% safe.

report_final.docx, report_final_real.docx, report_final_real2_professorsfeedback.docx — everyone has crammed history into filenames. Code changes far more often than documents, and one wrongly edited line can stop everything. That’s why programmers use a tool called a version control system (VCS), and the de facto world standard among them is Git. Git in one line: "a time machine for code." Because you can return to any point in the past at any time, the fear of "what if I break it while editing" disappears and you can touch code boldly. From this chapter on, every piece of code you write is managed with Git.


1. Learning Objectives

By the end of this chapter, you will be able to:

  • Explain Git’s operating structure with the three concepts: repository, commit, staging
  • Repeat the basic flow init → add → commit → log without getting stuck
  • Read the output of git status and git diff and decide your next action yourself
  • Revert a specific file to a past version using a commit hash
  • Write a one-line commit message that reveals "why it was changed"

2. Background Knowledge — Today’s Tools and Concepts

Today’s Tools at a Glance

Category Details
Language/environment Git Bash (Windows) or terminal, Git 2.x
Today’s commands git init, git status, git add, git commit, git log, git diff, git checkout, git restore
Concepts needed Repository, commit, hash, staging, HEAD
Today’s artifact A practice repository git-lab with 4 commits piled up

2-1. Repository and Commit — Two Words

A repository (repo for short) is "a folder managed by Git." It looks like an ordinary folder, but once a hidden folder called .git appears inside, all of this folder’s history is recorded there.

A commit is "the act of taking a snapshot." It records the entire current state of the folder like a photograph. Each commit carries a unique number (a hash, e.g., bc51216...), who changed what and when, plus a one-line description (the commit message).

2-2. Working Directory and Staging — Picking Subjects Before Taking the Photo

Git has one unusual intermediate stage.

  1. Working directory — the very folder where you create and edit files
  2. Staging — a waiting room where you select "changes to include in the next commit." git add is the command that places things in this waiting room
  3. Repositorygit commit finalizes the waiting room’s contents as a snapshot and records it

Why bother with an intermediate stage? It’s like choosing "who goes in this photo" before taking it. Even if you edited 5 files, you can commit just 2 of them separately, bundling them into a meaningful unit like "bug fix." A commit is a bundle of changes, and add is the hand that picks the bundle.

2-3. Kinds of Reverting

In Git, "reverting" uses different tools depending on the situation.

  • Just one file back to the past: git checkout hash -- filename (what we’ll measure today)
  • Discarding edits not yet added: git restore filename
  • Canceling a commit itself: git revert (not covered today)

Today we learn the first two. What matters now isn’t memorizing every tool — it’s getting the sense of "I can go back" into your hands.


3. Follow Along

3-1. Checking the Git Installation and Registering Your Identity

Input (Git Bash):

git --version
git config --global user.name "Gildong Hong"
git config --global user.email "gildong@example.com"

Output (measured 2026-09-09):

git version 2.47.1.windows.1

The two config lines succeed if they print nothing.

How to read it: --global means "apply commonly to all repositories on this computer." Since this registers the "who did it" stamped on every commit, it’s good to match the email you’ll later connect to GitHub.

If it’s not installed: on Windows, install from git-scm.com. The version number may differ in your environment.

3-2. Creating Your First Repository — git init

Input:

mkdir git-lab && cd git-lab
git init
ls -a

Output (measured 2026-09-09, the username in the path is altered):

Initialized empty Git repository in C:/Users/yourname/.../git-lab/.git/

The result of ls -a shows ., .., and .git.

How to read it: this folder has now become a repository. The hidden folder .git is the warehouse of history — delete it and all history vanishes, leaving an ordinary folder, so never touch it.

3-3. Your First File and git status — How to Read What Git Says

Input:

echo "print('hello git')" > hello.py
git status

Output (measured 2026-09-09):

On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	hello.py

nothing added to commit but untracked files present (use "git add" to track)

How to read it: status is the command you’ll type most — it tells you "what’s happening right now." Untracked means "a new file Git doesn’t know yet." You can also see Git kindly telling you the next action (git add).

Why: Git proficiency is essentially "the speed at which you read status messages." Build the habit of typing status whenever you’re stuck.

3-4. add and commit — Your First Snapshot

Input:

git add hello.py
git commit -m "first commit: add hello.py"
git log

Output (measured 2026-09-09):

warning: in the working copy of 'hello.py', LF will be replaced by CRLF the next time Git touches it
[main (root-commit) bc51216] first commit: add hello.py
 1 file changed, 1 insertion(+)
 create mode 100644 hello.py
commit bc51216bf5725e1543462fcea48e5252b57c8c87
Author: StudyUser <study@example.com>
Date:   Wed Sep 9 13:32:47 2026 +0900

    first commit: add hello.py

How to read it: 1 file changed, 1 insertion(+) is a summary meaning "1 file changed, 1 line added." The text in quotes after -m is the commit message — "a letter to your future self, writing why you changed it in one line." In log you see the long hash, author, date, and message in order. The warning on the first line is a Windows line-ending notice, not an error (covered in section 6, Wall 1). The commit hash and date will naturally differ in your environment.

Why: repeating these two commands is 80% of using Git. Edit → pick with add → snap with commit. Once this rhythm is in your body, you’re halfway there.

3-5. diff — Seeing with Your Eyes What Changed

Input: let’s edit hello.py.

echo "print('version 2')" >> hello.py
git diff

Output (measured 2026-09-09):

diff --git a/hello.py b/hello.py
index 926ebea..388fa71 100644
--- a/hello.py
+++ b/hello.py
@@ -1 +1,2 @@
 print('hello git')
+print('version 2')

How to read it: lines starting with + are "newly added lines"; lines starting with - are "deleted lines." @@ -1 +1,2 @@ is a position marker telling you "near which line the change happened."

Why: looking at diff before committing is like reading a contract before signing. The habit of checking "is this the change I intended?" prevents half of all mistakes.

3-6. Make a Prediction — What If You Commit Without add?

Right now hello.py is edited but not added. In this state, what happens if you run git commit -m "test"?

  • (a) The edits get committed automatically too
  • (b) Nothing happens and a guidance message appears
  • (c) An error occurs and Git exits

Check for yourself (measured 2026-09-09):

On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   hello.py

no changes added to commit (use "git add" and/or "git commit -a")

The answer is (b). Since you didn’t place the edits in staging, Git tells you there’s nothing to commit. Reading this message as "ah, I forgot add" — that is today’s core experience.

3-7. Stacking Commits and Reverting — The Time Machine’s First Ignition

Input: make the second and third commits.

git add hello.py && git commit -m "second version"
echo "print('version 3')" >> hello.py
git add hello.py && git commit -m "third version"
git log --oneline

Output (measured 2026-09-09):

efcfe3b third version
a3df5a6 second version
bc51216 first commit: add hello.py

How to read it: the 7 letters and digits on the left are each commit’s abbreviated hash (identifier). The top is the newest.

Now let’s revert just hello.py to the first commit. Use the hash you read from your own log --oneline.

git checkout bc51216 -- hello.py
cat hello.py
git status

Output (measured 2026-09-09):

print('hello git')
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   hello.py

How to read it: hello.py is back to its original one-line form, print('hello git'). The command’s shape means "from that point in history, take out just this file and overwrite the present with it." And as status tells you, the revert didn’t rewrite history — it placed "the old content" onto the working directory and staging. Commit in this state, and the very fact "I went back to the past" piles up as a new commit.

Try it (measured 2026-09-09): after git commit -m "restore to first version", git log --oneline:

15672a3 restore to first version
efcfe3b third version
a3df5a6 second version
bc51216 first commit: add hello.py

History wasn’t erased — a new line called "restore" was added. History isn’t deleted; it’s stacked — that is Git’s philosophy, and the basis for the confidence that "in Git, almost everything is recoverable."

3-8. git restore — Discarding Edits Not Yet Added

Input: make a bad edit to hello.py and throw it away.

echo "bad edit" >> hello.py
git restore hello.py
cat hello.py

Output (measured 2026-09-09):

print('hello git')

How to read it: the uncommitted edit vanished cleanly. restore is "return the working directory to the last committed state." Note that edits discarded this way can’t be recovered, so confirm you really want to discard before typing.


4. Missions & Exercises

Mission — A Mini Project with Three Layers of History

  1. Make a my-tool folder into a repository (git init), put "feature 1" in tool.py, and make the first commit
  2. Add "feature 2," check the changes with git diff before committing, and make the second commit
  3. Add "feature 3" and make the third commit
  4. Record in your notes the git log --oneline output, plus the cat result after reverting tool.py with the first commit’s hash
  5. Use the same command with the most recent hash to recover the latest state

Exercises

Exercise 1. Explain the three-stage structure — working directory, staging, repository — together with the roles of git add and git commit.

Exercise 2. Explain the differences among the situations where git status shows Untracked files, Changes not staged for commit, and Changes to be committed.

Exercise 3. In git diff output, what do lines starting with + and - each mean? What is @@ -1 +1,2 @@?

Exercise 4. After reverting with git checkout hash -- filename, why does git status show "Changes to be committed"? Explain from the perspective of "history isn’t deleted, it’s stacked."


Answers & completion criteria · expand/collapse

5. Model Answers & Completion Criteria

Mission Model Answer

The order of commands is this (identical to the measured flow of 3-2 through 3-7):

mkdir my-tool && cd my-tool && git init
echo "# feature 1" > tool.py
git add tool.py && git commit -m "add feature 1"
echo "# feature 2" >> tool.py
git diff                          # check changes before committing
git add tool.py && git commit -m "add feature 2"
echo "# feature 3" >> tool.py
git add tool.py && git commit -m "add feature 3"
git log --oneline                 # check the 3 hashes
git checkout <first-hash> -- tool.py
cat tool.py                       # should show only the one line "# feature 1"
git checkout <third-hash> -- tool.py
cat tool.py                       # all three lines recovered

How to verify: ① does git log --oneline show 3 commits? ② when reverted to the first hash, is the cat result the single "feature 1" line? ③ when recovered with the latest hash, do all three lines come back? If all three are "yes," it’s complete.

Exercise Answers

Answer 1. The working directory is the scene where you create and edit files; staging is a waiting room where you select "changes to put in the next commit"; the repository is the record warehouse where commits pile up. git add lifts changes from the working directory into staging, and git commit finalizes staging’s contents as a snapshot in the repository.

Answer 2. Untracked is a new file Git doesn’t know yet (never added even once); Changes not staged is a file Git knows, whose edits haven’t been added yet; Changes to be committed is the state where changes have been added and are waiting to go into the next commit. All three are messages we actually observed in 3-3 through 3-7.

Answer 3. + is a newly added line; - is a deleted line. @@ -1 +1,2 @@ is a change-position marker meaning "near line 1 of the original became lines 1–2 in the result."

Answer 4. Because reverting didn’t delete past commits — it placed the file content of a past point anew onto the working directory and staging. So Git says "you can commit this change," and committing adds a new history called "restore" (as in the 3-7 measurement, where a new line appears in log).

Completion Criteria Checklist

  • [ ] I created a repository with git init and confirmed the .git folder exists
  • [ ] I can repeat the add → commit → log flow without getting stuck
  • [ ] I can read git status, distinguishing Untracked / not staged / to be committed
  • [ ] I can explain the meaning of + and - lines in git diff
  • [ ] I can revert a specific file to a past version with a commit hash
  • [ ] I can discard pre-commit edits with git restore
  • [ ] Mission: I made three layers of history and completed reverting and recovery

6. Common Pitfalls & Fixes

Wall 1. An LF/CRLF warning appears

Symptom (measured 2026-09-09, Windows):

warning: in the working copy of 'hello.py', LF will be replaced by CRLF the next time Git touches it

Cause: not an error. Windows uses CRLF (two characters) for line endings and Linux uses LF (one character), and Git is giving advance notice that "line endings may be converted."
Fix: ignore it and proceed. It has no effect on this book’s exercises.

Wall 2. Only "nothing to commit" / "no changes added" appears

Symptom (measured 2026-09-09):

no changes added to commit (use "git add" and/or "git commit -a")

Cause: nine times out of ten, you forgot git add. Editing and placing into staging are separate acts (measured in 3-6).
Fix: check with git status whether the file is under "Changes not staged" → git add filename, then commit again.

Wall 3. The commit message opens a strange screen (vim)

Symptom: you committed without -m and an unfamiliar editor opened, trapping you.
Cause: without a message, Git launches the default editor.
Fix: escape by pressing Esc, then typing :q! and Enter (exit without saving). From now on, always attach -m "message".

Wall 4. An "error: pathspec" error occurs on checkout

Symptom (measured 2026-09-09, when the filename was typo’d as helo.py):

error: pathspec 'helo.py' did not match any file(s) known to git

Cause: the hash is wrong, or you wrote a filename that didn’t exist at that commit, or you typo’d the filename.
Fix: re-check the hash with git log --oneline, and verify the file exists in that commit with git show hash --stat.

Wall 5. I deleted the .git folder and regret it

Symptom: git status says fatal: not a git repository.
Cause: .git is the warehouse holding all of this folder’s history. The moment you delete it, it becomes an ordinary folder.
Fix: there’s no way to revive it, so prevention is the only answer. Never touch .git when cleaning up — being a hidden folder that’s hard to see is rather a safety device.


7. Summary

Today’s Concepts

Concept One-line explanation
Repository A folder managed by Git. .git is the warehouse of history
Commit A snapshot of the whole folder’s state. Carries hash, author, date, message
Hash Each commit’s unique number. The first 7 characters alone can identify it
Staging A waiting room for selecting changes to put in the next commit
HEAD A marker pointing to "where I’m standing right now"
LF/CRLF The different line-ending conventions of Linux/Windows

Today’s Commands

Command What it does
git init Turn this folder into a repository
git status See what’s happening right now
git add file Place changes into staging
git commit -m "message" Record staged changes as a snapshot
git log --oneline View history one line at a time
git diff See changes not yet added
git checkout hash -- file Fetch one file from a past point
git restore file Discard edits not yet added
git show hash --stat Check what’s in that commit

An Instinct More Important Than Commands

All of Git is three beats — edit (working directory) → pick (add) → snap (commit). And the first command when stuck is always git status. Git mostly tells you what to do next itself.

The connection to security: in a breach investigation, tracking "when did the attacker change what" uses the same way of thinking as Git’s history. If code on a Git-managed server was secretly altered, a single git diff line becomes evidence of tampering. And one more — in a Git repository, even deleted files remain in history. Write a password in code, delete it, and commit — it stays as-is in past commits. This fact is a very important warning we’ll take out again when we handle remote repositories.


Once every box is checked, Step 86 is complete.

ONE STEP FURTHER

Finished this lesson?

Check the completion criteria, then mark your progress.

Something wrong with this page or a link? Let us know.
Next