GitVibes / Core Safety Loop
Part 2

The Core Safety Loop: Your "Save Game" for AI Coding

"Commit early, commit often. Every save point is a universe you can return to."

This is the heartbeat of your entire Git workflow. Every time the AI generates code, you'll follow this three-step rhythm: check what changed, approve what you trust, and freeze it in time. Master this loop and you'll never lose work again. We'll close the part with the flip side of saving: the files that should never enter history at all.

The diagram above shows the full cycle you'll repeat every time you work with AI-generated code. This chapter covers the middle of the loop — discarding is Part 4's territory, and pushing comes in Part 3. Let's break it down:

Important
This is your fundamental daily workflow. It's a three-step process: the AI makes a change, you review it, and you "save" it. In Git, this loop is Status → Stage → Commit. For this to be an effective safety net, commit after every single logical, working change.

2.1 "What Did the AI Just Do?"

You just prompted the AI to refactor a module, and it went silent for a moment. What exactly did it touch? Before you do anything, you need situational awareness.

Always check your status before staging — know exactly what the AI changed
Note
The Problem: You prompted Copilot or Cursor to "refactor this function." It applies changes across several files. What exactly did it touch?

git status is your "heads-up display." The output shows three categories:

"Changes not staged" (Red)

Files Git tracks that were modified but not yet approved for the next save.

"Untracked files" (Red)

Brand-new files the AI created that Git has never seen before.

"Changes to be committed" (Green)

Staged files — reviewed, approved, and going into the next commit. Your goal is moving the right files here.

A typical git status, all three sections
On branch feature/login
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   src/auth.py

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
        modified:   src/routes.py

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

The good news? You don't actually need to type git status in the terminal. VS Code shows you all of this visually. Just click the Source Control icon in the Activity Bar (the branch icon on the left sidebar). The badge shows how many files changed, and each file is labeled M (modified), U (untracked), or D (deleted):

VS Code
The Source Control panel is your visual 'git status' — modified (M), untracked (U), and deleted (D) files are listed with clear badges.

You can also spot changes right in the editor without opening the Source Control panel. VS Code adds colored indicators in the gutter (the narrow strip to the left of your code): green for added lines, blue for modified lines, and a red triangle for deleted lines. Click any indicator to preview the change inline:

VS Code
Colored gutter indicators let you spot changes at a glance — green (added), blue (modified), and red (deleted). Click to preview.
Vibe it

"What files did you just change? Show me a summary"

"Check git status and explain what each changed file does"

2.2 Reviewing and Staging the AI's Work

Now you know what changed. The next step is the most important one: reviewing the AI's work line by line, and only approving what you trust. This is staging — your quality gate.

Selective staging lets you approve AI changes hunk by hunk
Warning
The Problem: git status shows the AI changed five files. Blindly trusting this is how bugs are introduced. You must review every line and then "stage" the changes you approve.

Step Zero: Actually Read the Diff

git status tells you which files changed; git diff shows you what changed inside them — removed lines in red with a -, added lines in green with a +. It's the terminal twin of the VS Code Diff Editor you'll meet below, and it's the command every AI agent runs before staging (Part 6 makes it a rule).

The two diffs you'll run constantly
git diff            # Unstaged changes: working directory vs staging area
git diff --staged   # Staged changes: what the next commit will contain
Tip
Make git diff --staged your ritual final check: it shows exactly — and only — what's about to be frozen into the commit. If a secret or debug print shows up there, you just caught it in time.

Option 1: Stage All (the "trusting" add)

Stage everything
git add .
Caution
This is fast but dangerous. If the AI added a temporary debug file or a flawed change, you just approved it without review.

Option 2: Stage One File (the "surgical" add)

Stage specific file
git add src/my_file.py

Option 3: Stage Parts of a File (the "AI-first developer's" add)

Tip
This is your single most powerful review tool. The AI made multiple changes in one file, and you only want to accept some of them. git add --patch walks you through every individual block of changes ("hunk") interactively. One blind spot: it only shows modifications to tracked files — brand-new files the AI created won't appear at all. Stage those by name with git add <file> after reading them.

Here's how to start an interactive staging session:

Interactive staging
git add --patch  # or git add -p

For each hunk, Git asks: y (stage), n (skip), s (split into smaller pieces), q (quit). In the Try It: The Complete Loop playground (next section), git add -p is simplified to file-by-file staging — type y or n on the next line for each file.

The VS Code Way: Visual Staging

This is where VS Code really shines. Instead of typing cryptic y/n/s/q responses in the terminal, you get a beautiful side-by-side Diff Editor. To stage an entire file, just hover over it and click the + button:

VS Code
Hover over any file and click + to stage it. The file moves from 'Changes' to 'Staged Changes'.

When you click a file in the Changes list, VS Code opens the Diff Editor -- a side-by-side view showing the old version (left) and new version (right). This makes it easy to review exactly what changed before staging:

VS Code
The Diff Editor shows your changes side-by-side: red highlights deletions, green highlights additions. Review before you stage.

For even more precision, click a file to open the Diff Editor, then select specific lines and right-click → "Stage Selected Ranges". This is the visual equivalent of git add -p, but far easier to use:

VS Code
In the Diff Editor, select specific lines and use the gutter to stage just those changes -- even more precise than git add -p.
Vibe it

"Stage only the files related to the authentication feature"

"Show me the diff of each changed file one at a time so I can decide what to stage"

Warning
Accidentally staged everything with git add .? Use git restore --staged <file> to unstage specific files before committing. This is especially critical if you accidentally staged .env files with secrets or debug files. You'll practice exactly this in the "Unstage Secrets" playground in section 4.2 (or right now — open the playground from the header and pick the scenario).

2.3 Creating the Save Point

You've reviewed the changes and staged the ones you trust. Now it's time to freeze this moment in time — a commit is your permanent save point that you can always travel back to.

Each commit is a checkpoint you can always travel back to
Note
The Problem: You've staged your reviewed changes. Now, bundle them into an immutable "save point" -- a commit. (Immutable, not untouchable: Part 4 teaches the history-editing tools. What's written can be rewritten — but never silently changed in place.)
Create a commit with a message
git commit -m "feat: add user authentication endpoint"

The command itself is simple, but the message you write matters more than you might think.

Important
Writing Good Commit Messages: Your code shows how a change was made; your commit message must explain the why. Use Conventional Commits format:
TypeWhen to UseExample
feat:A new feature for the userfeat: add login button to homepage
fix:A bug fix for the userfix: resolve dimension mismatch
docs:Documentation only changesdocs: update API reference
style:Formatting, missing semicolons, etc.style: fix indentation in utils
refactor:Code change that neither fixes a bug nor adds a featurerefactor: simplify form validation
test:Adding or correcting teststest: add unit tests for auth
chore:Build process or tools changeschore: update dependencies
perf:A code change that improves performanceperf: cache database queries

Where the "Why" Actually Goes: the Body

The subject line above says what changed. The "why" lives in the commit body — a blank line after the subject, then as many lines of context as the change deserves. Run git commit with no -m and Git opens your editor (VS Code, if you set core.editor in Part 1) for exactly this:

A commit message with a body
fix(auth): reject expired tokens before the DB lookup

The AI's first fix checked expiry after loading the user, which
let expired tokens trigger a full query. Checking first avoids
the load and matches how the session middleware already behaves.

Save and close the editor tab, and the commit completes. (Changed your mind? Close it with an empty message and Git aborts the commit.)

Tip
AI Integration: GitHub Copilot and Cursor can analyze your staged changes and suggest a commit message. Always verify it follows your team's standards — and remember the bar: six months from now, does this message explain why?

One last habit: prove to yourself the save point exists. Right after committing, run git log --oneline -1 — one line, your hash and message. (That's also the final step Part 6 teaches agents: commit, then report the hash.)

In VS Code, committing is just as simple: type your message in the input box at the top of the Source Control panel and click the Commit button (or press Cmd+Enter / Ctrl+Enter). Notice the sparkle icon next to the input -- click it to let AI generate a commit message from your staged changes:

VS Code
The full Source Control view: your staged changes, the commit message input, and the Commit button. Click the sparkle icon to auto-generate a message.

Here's the AI commit message feature in action. After staging your changes, click the sparkle icon and Copilot will analyze your diff and write a descriptive message for you:

VS Code
Click the sparkle icon and AI generates a commit message based on your staged changes. Always review it before committing!

Try It: The Complete Loop

Run real Git commands in your browser. Type help in the terminal for the full command list.
The Core Safety Loop

Loading playground...

Vibe it

"Commit the staged changes with a good conventional commit message"

"Write a descriptive commit message for these changes and commit them"

2.4 What NOT to Commit (.gitignore)

You asked the AI to scaffold your project, and it delivered: dependencies installed, an .env file holding your API keys, and a working app. Then it helpfully runs git add . — and now your secrets, your node_modules folder, and a stray .DS_Store are all staged for your next commit. You just learned how permanent a commit is — before you freeze that mistake into history, you need to teach Git what to ignore.

A .gitignore file is the guardrail that makes 'git add .' safe — secrets and junk never enter history
Note
The Problem: AI agents move fast and stage everything. Without a guardrail, one git add . can commit API keys, gigabytes of dependencies, and OS junk into a history that everyone on your team will clone.

A .gitignore file is a plain text file at the root of your repository that lists patterns of files Git should pretend don't exist. Ignored files never show up as "untracked" in git status, and git add . silently skips them. The file itself gets committed, so the whole team — and every AI agent working in the repo — shares the same guardrail.

.gitignore — a realistic starter for a JS/Python project
# Dependencies
node_modules/
.venv/
__pycache__/
*.pyc

# Secrets & local config
.env
.env.*
!.env.example

# Build output
dist/
build/
coverage/

# Logs & caches
*.log
.cache/

# AI tool local state (personal settings stay personal)
.claude/settings.local.json
CLAUDE.local.md
.cursor/
.aider*

(Purely personal noise like .DS_Store or .idea/ belongs in your global ignore file instead — see the end of this section. And while a repo's main .gitignore lives at the root, you can drop extra ones in any subfolder to scope rules to just that corner of the project.)

Pattern Syntax Essentials

  • *.log — a glob: matches any file ending in .log, in any directory
  • dist/ — a trailing slash matches only directories (and everything inside them)
  • /config.json — a leading slash anchors the pattern to the repository root
  • docs/**/*.tmp** matches any depth of nested directories
  • !.env.example — a leading ! negates a pattern, re-including a file an earlier rule excluded (it can't re-include anything inside an excluded directory, though)

The Gotcha: Already-Tracked Files Stay Tracked

.gitignore only affects untracked files. If a file was already committed before you added it to .gitignore, Git keeps tracking it — and keeps committing your changes to it. To stop tracking a file without deleting it from your disk, remove it from the staging area (which Git's own messages call the index — same thing, older name):

Untrack a file that's already committed
git rm --cached .env
# For a whole directory:
git rm -r --cached node_modules

# Then commit the removal
git commit -m "chore: stop tracking ignored files"
Warning
If a secret was ever committed, removing it in a new commit is not enough. The key still exists in every older commit, and anyone who clones the repository can read it. Treat a pushed secret as compromised: rotate the credential immediately (revoke the key and issue a new one), then scrub it from history with a rewriting tool like git filter-repo — specialized surgery beyond this guide, but worth knowing the name. Rotation comes first; no amount of history surgery un-leaks a key that's already been seen.

A Global Ignore File for OS and Editor Junk

Files like .DS_Store (macOS) or Thumbs.db (Windows) are about your machine, not the project. Instead of asking every repository to ignore them, configure a global ignore file that applies to all your repositories:

Set up a global ignore file (once per machine)
git config --global core.excludesFile ~/.gitignore_global

echo ".DS_Store" >> ~/.gitignore_global
echo "Thumbs.db" >> ~/.gitignore_global
Tip
Rule of thumb: project artifacts (builds, dependencies, secrets) go in the repository's .gitignore so the whole team is protected; personal noise (your OS, your editor) goes in your global ignore file.

Line Endings: the Cross-Platform Papercut

Windows ends lines with CRLF, macOS and Linux with LF. On a mixed team this produces the classic horror diff: every line of the file "changed" because a teammate's editor rewrote the endings — and AI agents reformatting files make it worse. The team-level fix is a committed .gitattributes file, which overrides everyone's personal settings:

.gitattributes — one line ends the war
# Commit LF, let Git normalize what each OS checks out
* text=auto

# Files that must keep exact bytes, no conversion ever
*.png binary
*.webp binary

(You may also see core.autocrlf in older guides — that's the per-machine version of the same idea. Prefer .gitattributes: it lives in the repo, so it protects teammates and agents who never configured anything. If a diff ever claims every line changed, check line endings before anything else.)

Vibe it

"Write a .gitignore for this project — look at my stack and include editor and OS artifacts"

"Check my repo for tracked files that look like secrets or build artifacts that shouldn't be committed"

Challenge: Stage Only What You Trust

Loading challenge...