LevelUpWith

Explore / Git & GitHub: From First Commit to Team Workflow / Lesson 2

Lesson 2: Working Tree, Staging Area and Commits

Understand the three places a change passes through, from the working tree to the staging area to a commit, and make small commits with clear messages.

Free to read, no account needed. Part of Git & GitHub: From First Commit to Team Workflow.

By the end of this level you'll be able to

  • Use git status to tell untracked, modified and staged files apart
  • Stage whole files or only some changes with git add and git add -p, then record them with git commit
  • Use git diff and git diff --staged to see exactly what will and will not go into the next commit

Three places a change lives

In Level 1 you made a repository. Now let's look at how a change ends up saved in it, because this is where people who copy commands usually get confused.

Git keeps track of three places:

  1. Working tree: the files you can see and edit in your folder.
  2. Staging area (also called the index): a holding area for what will go into the next commit.
  3. Commits: saved snapshots that become part of your history.

Think of packing a parcel. Your desk is the working tree, where things are scattered and half-finished. The open box is the staging area, where you put only what you mean to send. Taping the box and writing the label is the commit. The box is the useful part. It means you can finish three things at your desk and send only one of them.

Why have a middle step at all? Because real work is messy. You fix a bug, rename a variable and leave a debug print in the same file. The staging area lets you save the bug fix as its own clean commit and leave the rest for later.

Reading git status

git status is the command you'll run most often. Let's make three different kinds of change in your practice repository:

cd practice-repo
echo "# Notes" > notes.md                  # a brand-new file Git has never seen
echo "print('hello')" > hello.py
git add hello.py && git commit -m "Add hello script"   # hello.py is now tracked
echo "print('goodbye')" >> hello.py     # change a tracked file
echo "TODO" > todo.txt
git add todo.txt                         # stage a new file
git status

The output looks like this (your branch name may be different):

On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   todo.txt

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

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

Read it from the top down:

  • Changes to be committed: these are staged. They're in the box.
  • Changes not staged for commit: these are modified tracked files that are still on the desk.
  • Untracked files: Git has never recorded these files and will ignore them until you git add them.

For a compact view, run git status -s:

A  todo.txt     # left column = staging area: A = added
 M hello.py     # right column = working tree: M = modified, not staged
?? notes.md     # ?? = untracked

Gotcha: git status repeats the hints for its own commands. Read them. They usually tell you the exact next step, including how to take a file back out of the box with git restore --staged.

Seeing exactly what changed: git diff

git status tells you which files changed. git diff shows you which lines changed. There are two forms you should know:

git diff            # working tree vs staging area: what you have NOT staged yet
git diff --staged   # staging area vs last commit: what WILL go into the next commit

(--cached means the same as --staged, and you'll see both online.) Running git diff now shows this:

--- a/hello.py
+++ b/hello.py
@@ -1 +1,2 @@
 print('hello')
+print('goodbye')

Lines starting with + were added and lines starting with - were removed. Make it a habit to run git diff --staged before every commit. It's the last check that the box holds only what you meant to send.

Gotcha: If plain git diff prints nothing, that doesn't mean nothing changed. Everything may already be staged. Check git diff --staged too.

Staging whole files or only some changes

git add <file> stages everything in that file. git add . stages every change in the current folder and the folders inside it. It's quick, but it's also how debug files and passwords end up in history. Run git status first.

To stage part of a file, use patch mode:

printf "print('hello')\nprint('goodbye')\n\nprint('DEBUG x=', 42)\n" > hello.py
git add -p hello.py

Git shows each hunk (a block of changed lines) and asks what to do with it:

Stage this hunk [y,n,q,a,d,s,e,?]?
  • y: stage this hunk. n: skip it.
  • s: split the hunk into smaller ones, if Git can.
  • q: quit. ?: show help for every key.

Stage the goodbye line with y, skip the debug line with n, then check what you've done:

git diff --staged   # shows only the goodbye line
git diff            # shows only the DEBUG line, still on your desk

git status will now list hello.py under both "to be committed" and "not staged". That's normal: part of the file is in the box and part isn't.

Making the commit

git commit -m "Print goodbye after greeting"

Only what you staged is recorded. The debug line stays in your working tree. If you run git commit without -m, Git opens your editor so you can write a longer message.

Shortcut to be careful with: git commit -a stages every modified or deleted tracked file and commits it in one step. It skips untracked files, so a new file you forgot to add won't be included. It also skips the review that git add -p gives you.

Writing a clear message

Git's own documentation recommends a short summary line of no more than 50 characters, then a blank line, then more detail if you need it:

Fix crash when config file is empty

load_config() returned None and the caller indexed it.
Return an empty dict instead.

Write the summary as an instruction ("Fix crash...", not "fixed stuff"). A good test is whether it completes the sentence "If applied, this commit will...". Keep each commit to one logical change. Small commits are easier to review, explain and undo.

Try it and check

git add notes.md
git commit -m "Add notes and todo files"
git status -s       # expect only: " M hello.py" (the debug line)

If the only line left is M hello.py, you've committed everything except the debug line, which is what you wanted.

Key takeaways

  • A change moves from the working tree to the staging area (with git add) and then into a commit (with git commit).
  • git status sorts files into staged, modified-but-not-staged and untracked.
  • git diff shows changes you haven't staged. git diff --staged shows exactly what the next commit will contain.
  • git add -p lets you stage some hunks of a file and leave others out.
  • git commit -a skips untracked files. Make small commits with a short summary line in the instruction form.

A 6-question knowledge check follows this lesson in the app, free and without an account.

Keep going: levels 3 and 4 are free

Create a free account to open the next two levels, save your progress and pick up where you left off. No card needed.

Next: Level 3, Reading History and Ignoring Clutter.

Create a free account →See the whole course

More like this

  • GitHub Copilot (GH-300) Exam Prep

    Learn GitHub Copilot hands-on in the editor, in the CLI and on github.com, and work through every skill in the GH-300 study guide (skills measured as of August…

    Exam prep · GH-300 · Software & Engineering · Capable · 18 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 3, Mobile Apps, Games and Growth

    Turn your first live app into a real product. Learn to choose between web and app store apps, publish a browser game, take payments safely, run and monitor a l…

    Course · Software · Software & Engineering · Capable · 24 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 2, Online, Secure and AI-Powered

    Take one small app from your GitHub repository to a public web address. You will host it on Vercel and give it a Supabase database, sign-in and file storage, w…

    Course · Software · Software & Engineering · Capable · 16 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 1, From Prompt to Project

    Move an app you built in an AI chat onto your own computer and work on it step by step with a coding agent. Save your work with Git, keep secrets out of your c…

    Course · Software · Software & Engineering · Capable · 19 levels · 4 free · Professionally curated by levelupwith.com

  • Right Chip, Right Job: CPUs, GPUs, TPUs and Beyond

    Profile a workload, place it on a roofline and pick the processor that actually suits it, whether CPU, GPU, TPU, ASIC, inference chip, NPU, FPGA or DPU. You wi…

    Beyond the Obvious · Software & Engineering · Expert · 61 levels · 4 free · Professionally curated by levelupwith.com

  • Build Your First Website with HTML and CSS

    Start from a blank file and build a real, accessible personal or small-business website that works on phones. Each level adds to the same site, covering semant…

    Course · Software · Software & Engineering · Capable · 18 levels · 4 free · Professionally curated by levelupwith.com