Git Fundamentals: Tracking Change with Confidence

Git is a source control system built to answer a simple question: what changed, when did it change, and why? In this first post, you will build a practical foundation you can reuse in every repository.

Table of Contents

This post builds a practical Git foundation you can reuse in every repository.

Core Concepts

Setup

Commit Workflow

Recovery

Series Navigation

What Git is actually tracking

Git tracks snapshots of your project over time. A commit is not a “diff file”; it is a recorded state of tracked files plus metadata (author, date, message, and parent commit references).

That design gives you three immediate advantages:

  • You can review exactly what changed before saving a commit
  • You can move backward and forward through project history
  • You can create isolated branches without copying entire directories by hand

Configure identity once

Before you commit in any repository, set your name and email. This data becomes part of commit history.

git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main

Check your configuration:

git config --list --show-origin

Start from scratch or clone an existing repository

Create a new repository:

mkdir demo-git-basics
cd demo-git-basics
git init

Or clone one that already exists:

git clone https://example.com/org/project.git
cd project

Understand the three states: working tree, index, and HEAD

Most confusion disappears when you know these three locations:

  • Working tree: files on disk that you are actively editing
  • Index (staging area): the exact set of changes queued for the next commit
  • HEAD: the currently checked-out commit

Use this cycle constantly:

git status
git add <file>
git status
git commit -m "Describe why this change exists"

git status is your ground truth. If you feel lost, run it first.

Make your first commit with intent

Try a small commit:

echo "# Demo Project" > README.md
git status
git add README.md
git commit -m "Create project README with initial heading"

Now inspect history:

git log --oneline --decorate --graph

This one-line format is a great daily view, especially as branches are introduced later in this series.

Review changes before committing

Git lets you inspect changes in detail at each stage:

# unstaged changes (working tree vs index)
git diff

# staged changes (index vs HEAD)
git diff --staged

For cleaner commits, stage only parts of a file:

git add -p

This helps separate unrelated edits into focused commits that are easier to review and revert.

Keep noise out of history with .gitignore

Use .gitignore to prevent build artifacts, secrets, and local environment files from being committed.

# .gitignore
.env
*.log
dist/
node_modules/

If a file is already tracked, adding it to .gitignore does not remove it from history automatically. You must untrack it first.

git rm --cached .env
git commit -m "Stop tracking local environment file"

Safe local undo before pushing

Two common local recovery actions:

# restore a file in working tree back to last committed state
git restore path/to/file

# unstage a file but keep your edits
git restore --staged path/to/file

Use these to clean up local mistakes before your changes are shared.

Practice checklist

Run this sequence in a practice repository until it feels automatic:

  1. Edit one file.
  2. Run git status.
  3. Run git diff.
  4. Stage with git add -p.
  5. Run git diff --staged.
  6. Commit with a message that explains why.
  7. Inspect with git log --oneline.

Once this loop is natural, the next topic becomes much easier.

Next in this series

In the next post, we move from single-line history to parallel work with branches, merge strategies, and conflict resolution