thecodingidiot.com

Version ControlYour First Commit

Your First Commit

Before I understood the staging area I committed everything at once with git add .. The commits were a mess — a working change bundled with a debug print bundled with a half-finished refactor. When I looked back two weeks later the history told me nothing.

Git has three zones, not two.

The working tree is your filesystem — files as they exist on disk, as your editor sees them. The index (also called the staging area) is a snapshot you are assembling toward the next commit. The commit history is the permanent, append-only record. Changes move through these zones explicitly:

working tree  →  git add  →  index  →  git commit  →  history

The index exists so you can commit exactly the changes that belong together, even if your working tree contains unrelated work in progress.


Initialise a repository

Create a directory and initialise it:

mkdir f02-practice && cd f02-practice
git init

Git creates a .git/ directory — the repository itself. Everything outside .git/ is your working tree.


Your first commit

Create a file:

echo "hello" > hello.txt

Check the state of the working tree:

git status

Output:

On branch main
 
No commits yet
 
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	hello.txt

hello.txt is in the working tree but not in the index. Stage it:

git add hello.txt

git status now shows it under "Changes to be committed". Commit:

git commit -m "add hello.txt"

Write commit messages in the imperative present tense: "add", "fix", "remove", "update" — not "added" or "adding". The subject line describes what applying the commit does, not what you were doing when you wrote it.


Reading the log

git log
git log --oneline

git log --oneline is one line per commit: the short hash and the message. As the history grows this is almost always what you want.


Seeing what changed

git diff compares the working tree to the index — what you have changed but not yet staged. git diff --staged compares the index to the last commit — what will go into the next commit.

echo "world" >> hello.txt
git diff             # unstaged change
git add hello.txt
git diff --staged    # staged change, waiting to be committed
git commit -m "append world"

Before committing a change, git diff --staged is the last check. It shows exactly what the commit will contain.


.gitignore

Some files should never be committed: compiled objects, editor swap files, operating system metadata. Create .gitignore in the repository root:

*.o
a.out
*.swp

Any file matching a pattern in .gitignore is invisible to git status and will never be staged by git add .. Commit .gitignore itself — it belongs in the repository so that every clone of the repo inherits the same rules.


Undoing changes

Discard an unstaged change — restore the working tree from the index (the file reverts to its last staged or committed state):

git restore hello.txt

Unstage a file — remove it from the index without touching the working tree:

git restore --staged hello.txt

Undo a committed change safelygit revert creates a new commit that reverses an earlier one. HEAD means your current commit, so git revert HEAD undoes the most recent commit while keeping the history intact:

git revert HEAD

Git will open your editor so you can write a commit message for the revert. Save and close to complete it.

git reset rewrites history. It is powerful and occasionally the right tool, but it is not the default undo. Treat it the way you treat rm -rf: reach for it only when you know exactly what you are removing.


Inspecting a commit

git show HEAD
git show <hash>

git show displays the commit metadata and the diff it introduced — the same unified diff format from The Patch page.