# # Git Adventures --- Part 2: When Git Starts Judging Your Decisions

In Part 1, everything was clean. Repository created. Project initialized. Branches created. Team motivated.

That illusion lasted exactly one day.

Because on Day 2, the team learned an important truth: **Writing code is easy. Understanding history is hard.**

And Git remembers everything.

* * *

## Chapter 1 --- The Calm Before the Debugging Storm

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wb8n8osxaefk6wsaibd8.png align="center")

Amaresh notices something feels wrong after pulling updates. A feature that worked yesterday is broken. When did this happen?

He opens the timeline:

```bash
git log --oneline
```

Output:

```plaintext
a3f9c2b Add authentication flow
9d1a2e4 Fix validation issue
c81be77 Initial setup
```

Each commit shows a short hash (abbreviated commit ID) and message.

**When you need the full commit ID:**

```bash
git log
```

Or to just grab HEAD's full ID:

```bash
git rev-parse HEAD
```

Output:

```plaintext
a3f9c2b7d8e9f0a1b2c3d4e5f6g7h8i9
```

**Pro tip:** Use `git log --oneline -n 20` to see only the last 20 commits. Saves scrolling through months of history.

**The gotcha:** `git log` shows commits in reverse chronological order (newest first). If you're looking for *when* something broke, scroll down, not up.

**Commit IDs are your time machine.** They allow precise navigation through Git history—and they're immutable. The same commit ID always points to the exact same code, forever.

* * *

## Chapter 2 --- Understanding What Actually Changed

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b83y3b6jfme6j5e2v0e2.png align="center")

Amaresh needs to see *exactly* what was changed. Not just which files, but which lines.

```bash
git diff
```

Output:

```diff
diff --git a/auth.js b/auth.js
index 1a2b3c4..5d6e7f8 100644
--- a/auth.js
+++ b/auth.js
@@ -12,7 +12,7 @@
  function validateToken(token) {
-   if (token.length < 32) {
+   if (token.length < 16) {
      return false;
    }
```

Git highlights **removed lines** in red (with `-`) and **added lines** in green (with `+`).

**Compare two branches:**

```bash
git diff main feat/authentication
```

This shows all changes in `feat/authentication` that aren't in `main`.

**Compare two commits:**

```bash
git diff a3f9c2b 9d1a2e4
```

**See only filenames (not the code):**

```bash
git diff --name-only main feat/authentication
```

**See file statistics:**

```bash
git diff --stat main feat/authentication
```

Output:

```diff
auth.js     | 15 ++++++++++++---
utils.js    |  8 ++------
 2 files changed, 14 insertions(+), 9 deletions(-)
```

**The gotcha:** `git diff` with no arguments shows **unstaged changes only**. If you've already run `git add`, you won't see those changes. Use `git diff --staged` to see staged changes.

* * *

## Chapter 3 --- Inspecting a Single Decision

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ohplfhhdml9eoxzxpqc.png align="center")

Johnny broke something three commits ago. Now Amaresh needs to see exactly what that commit changed.

```bash
git show a3f9c2b
```

Output:

```diff
commit a3f9c2b7d8e9f0a1b2c3d4e5f6g7h8i9
Author: Johnny <johnny@company.com>
Date:   Wed Mar 24 14:32:15 2026 +0530

    Add authentication flow

diff --git a/auth.js b/auth.js
new file mode 100644
index 0000000..a1b2c3d
--- /dev/null
+++ b/auth.js
@@ -0,0 +1,45 @@
+function authenticate(user, password) {
...
```

`git show` displays:

*   **Author** — who made the change
    
*   **Date** — when it was committed
    
*   **Message** — the commit description
    
*   **Full diff** — every line added/removed
    

**See just the commit message:**

```bash
git show a3f9c2b --format=fuller
```

**Use with current HEAD:**

```bash
git show HEAD
```

**This is your bug detective tool.** When you find a broken line, you can track exactly when it was added and by whom.

**The gotcha:** If a commit only renamed a file without changing it, `git show` will say "similarity index 100%" but show no actual changes. The file content is identical.

* * *

## Chapter 4 --- The Unexpected Urgent Task

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gp0bedmbyur7t5ktwsd0.png align="center")

Danny has been working on a feature for hours. Code is half-written, tests are incomplete. Then a critical production bug appears, and he must switch branches immediately.

He can't commit incomplete work (it breaks the build). He can't lose his changes. So he uses:

```bash
git stash
```

This saves all changes to a temporary location and resets the working directory to the last commit.

```bash
git checkout hotfix/critical-bug
# Fix the bug, commit, merge back to main
git checkout feat/incomplete-feature
```

Now he gets his incomplete work back:

```bash
git stash pop
```

**But there's a problem:** He had created a new file (`utils.js`) that hadn't been staged. After stashing and popping, the file is gone.

That's because `git stash` by default only saves **tracked** files (files Git already knows about). New files are left behind.

**The solution:**

```bash
git stash -u
```

The `-u` (or `--include-untracked`) flag tells Git to stash everything, including brand new files.

**Better yet, use this to be safe:**

```bash
git stash -u -m "WIP: authentication feature with new utils"
```

The `-m` flag lets you label the stash so you remember what's in it.

**View all stashes:**

```bash
git stash list
```

Output:

```plaintext
stash@{0}: WIP: authentication feature with new utils
stash@{1}: WIP: fixing typo in validator
stash@{2}: On main: saving work
```

**Pop a specific stash:**

```bash
git stash pop stash@{1}
```

**Delete a stash without popping:**

```bash
git stash drop stash@{0}
```

**Clear all stashes (⚠️ dangerous):**

```bash
git stash clear
```

**The gotcha:** `git stash pop` removes the stash after applying it. If the pop fails (merge conflict), the stash stays safe. But if it succeeds and you later realize you needed it, it's gone. Use `git stash apply` instead if you want to keep the stash around.

* * *

## Chapter 5 --- The First Real Merge Conflict

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ep1dypi6z5hr20fi094z.png align="center")

Johnny finishes his service-layer feature. Ronaldo finishes his database optimization feature. Both edited the same file. Johnny tries to merge Ronaldo's branch:

```bash
git merge feat/service-layer
```

Git responds:

```plaintext
Auto-merging api.js
CONFLICT (content): Merge conflict in api.js
Automatic merge failed; fix conflicts and then commit the result.
```

He opens `api.js` and sees:

```javascript
function handleRequest(req, res) {
<<<<<<< HEAD
  // Ronaldo's code (database optimization)
  const data = db.query(req.id);
  res.send(data);
=======
  // Johnny's code (service layer)
  const service = new Service();
  const data = service.fetch(req.id);
  res.send(data);
>>>>>>> feat/service-layer
}
```

The conflict markers show:

*   `<<<<<<< HEAD` — start of current branch (what you have now)
    
*   `=======` — divider
    
*   `>>>>>>> feat/service-layer` — end of incoming branch (what you're merging in)
    

**Johnny must decide:** Keep Ronaldo's code? Keep his own? Use both?

He decides to use his service layer but call the optimized query:

```javascript
function handleRequest(req, res) {
  const service = new Service();
  const data = service.fetch(req.id); // Johnny's code
  // Ronaldo's optimization is now inside service.fetch()
  res.send(data);
}
```

Now resolve the conflict:

```bash
git add api.js
git commit -m "Merge feat/service-layer: resolve conflict in api.js"
```

**Tools to help with conflicts:**

```bash
# See which files have conflicts
git diff --name-only --diff-filter=U

# Use a visual merge tool (if configured)
git mergetool
```

**Abort a merge if you're not ready:**

```bash
git merge --abort
```

**The gotcha:** Merge conflicts are not errors—they're Git asking you to make a decision. A merge with zero conflicts often means someone's code got silently overwritten. Conflicts are actually good; they force you to think.

* * *

## Chapter 6 --- Fetch vs Pull vs Merge (The Confusion Explained)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emiorkgktx4aaltbo9z8.png align="center")

Many developers use these terms interchangeably. They're not.

`git fetch` — Downloads changes from remote, but doesn't integrate them:

```bash
git fetch origin
```

This updates your local tracking branches (`origin/main`, `origin/feat/something`) but leaves your local `main` branch untouched.

`git merge` — Combines histories:

```bash
git merge origin/main
```

This integrates the remote changes into your current branch.

`git pull` — Fetch + merge in one command:

```bash
git pull origin main
```

Equivalent to:

```bash
git fetch origin
git merge origin/main
```

**Why does this matter?**

The **professional workflow** is:

```bash
git fetch origin          # Download changes
git log main origin/main  # Inspect what changed
git merge origin/main     # Merge when ready
```

Why? Because `git pull` can silently create merge commits you didn't expect. Fetching first lets you review changes before integrating them.

**Comparison table:**

| Command | Changes local branch? | Creates merge commit? | Safe to use blindly? |
| --- | --- | --- | --- |
| `git fetch` | ❌ No | ❌ No | ✅ Yes |
| `git merge` | ✅ Yes | ✅ Maybe | ⚠️ Only if branches are synced |
| `git pull` | ✅ Yes | ✅ Usually | ⚠️ Can surprise you |

**The gotcha:** `git pull` can create a merge commit automatically. If you're trying to keep a clean history, this is annoying. Use `git pull --rebase` to rebase instead of merge (we'll cover rebase in Part 3).

* * *

## Chapter 7 --- Undoing Mistakes Properly

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bxkglkg3f2i8c50imc7c.png align="center")

Mistakes happen. Git gives you three different ways to undo, and they each do something different.

### Mistake Type 1: "I edited a file but haven't staged it"

Amaresh edited `config.js` but realizes it's wrong. He hasn't run `git add` yet.

```bash
git restore config.js
```

This overwrites `config.js` with the version from the last commit. Changes are gone.

**Old syntax (still works):**

```bash
git checkout config.js
```

* * *

### Mistake Type 2: "I staged changes I shouldn't have"

Amaresh ran `git add .` and included `config.js` accidentally. He hasn't committed yet.

```bash
git restore --staged config.js
```

This unstages the file. The file still exists in your working directory with all changes intact—only the staging is removed.

**Undo all staged changes:**

```bash
git restore --staged .
```

* * *

### Mistake Type 3: "I committed something wrong but haven't pushed"

Johnny committed buggy code. It's in his local history but not on GitHub yet.

```bash
git reset HEAD~1
```

This moves the branch pointer back one commit. The buggy commit disappears from history. But the files are still in your working directory with changes intact.

```bash
# Edit the files, fix the bug
git add .
git commit -m "Fixed version of that commit"
```

**The variants:**

```bash
git reset --soft HEAD~1   # Undo commit, keep changes staged
git reset --mixed HEAD~1  # Undo commit, keep changes unstaged (default)
git reset --hard HEAD~1   # Undo commit, DISCARD all changes (⚠️ dangerous)
```

**The gotcha:** `git reset --hard` is permanent. Your code is deleted. If you haven't pushed, you can use `git reflog` to recover, but it's nerve-wracking. Default to `--mixed` or `--soft`.

* * *

### Mistake Type 4: "I committed bad code that's already pushed"

Ronaldo pushed a commit that broke production. He can't just `git reset` because others have already pulled his changes. Rewriting history would break their local repos.

```bash
git revert a3f9c2b
```

This creates a **new commit** that undoes the changes from commit `a3f9c2b`. Git history stays intact. Everyone can pull the revert safely.

Output:

```plaintext
[main 7f8e9d0] Revert "Add broken authentication"
 1 file changed, 2 deletions(-)
```

Now the repo is fixed, and history shows exactly what happened.

**Compare the three approaches:**

| Situation | Command | Creates new commit? | Safe to push? | Reversible? |
| --- | --- | --- | --- | --- |
| Unstaged file mess | `git restore` | ❌ No | ✅ N/A | ❌ Deleted |
| Staged file mess | `git restore --staged` | ❌ No | ✅ N/A | ✅ Still in working dir |
| Wrong local commit | `git reset` | ❌ No | ❌ Rewrites history | ✅ Use `git reflog` |
| Pushed bad commit | `git revert` | ✅ Yes | ✅ Safe | ✅ Fully reversible |

* * *

## The Safety Net: `git reflog`

Here's the command nobody tells you about until you need it.

Amaresh ran `git reset --hard` and deleted code he wanted. Is it gone forever?

```bash
git reflog
```

Output:

```plaintext
a3f9c2b HEAD@{0}: reset: moving to HEAD~1
9d1a2e4 HEAD@{1}: commit: Add authentication flow
c81be77 HEAD@{2}: commit: Initial setup
```

The reflog shows every place HEAD has been. He can recover:

```bash
git reset --hard HEAD@{1}
```

**The safety net catches you.** Use this when you panic after a hard reset.

* * *

## Quick Reference Cheat Sheet

| Problem | Command | Result |
| --- | --- | --- |
| View commit history | `git log --oneline` | Shows last commits |
| See what changed | `git diff` | Shows unstaged changes |
| See staged changes | `git diff --staged` | Shows changes ready to commit |
| Compare branches | `git diff main feat/new` | Shows differences |
| Inspect a commit | `git show <commit-id>` | Shows commit details |
| Save work temporarily | `git stash -u -m "label"` | Saves including untracked files |
| Restore saved work | `git stash pop` | Applies last stash |
| Download remote changes | `git fetch origin` | Safe, doesn't merge |
| Download + merge | `git pull` | Fetch + merge in one |
| Undo unstaged changes | `git restore <file>` | Discards edits to file |
| Unstage changes | `git restore --staged <file>` | Keeps changes, removes from staging |
| Undo last commit (local) | `git reset HEAD~1` | Moves branch back |
| Undo last commit (pushed) | `git revert <commit-id>` | Creates undo commit |
| Undo hard reset | `git reflog` | Shows all HEAD positions |

* * *

By the end of Day 2, the team realized something important:

Git doesn't judge you for making mistakes. **It judges you for not knowing how to recover from them.**

**Master these commands, and you'll never panic:**

*   `git log` + `git show` — understand what happened
    
*   `git diff` — see exactly what changed
    
*   `git stash` — escape from immediate problems
    
*   `git restore` / `git reset` / `git revert` — fix them the right way
    
*   `git reflog` — panic button
    

* * *

## End of Part 2

**The team learned:**

*   `git log --oneline` — time machine for commits
    
*   `git diff` — see changes precisely
    
*   `git show` — inspect a single commit
    
*   `git stash -u` — save incomplete work
    
*   Merge conflicts — human decisions required
    
*   `git fetch` vs `git pull` — when to use which
    
*   `git restore` vs `git reset` vs `git revert` — right tool for the job
    
*   `git reflog` — the safety net
    

* * *

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ez324ex5hvcve0s79dub.png align="center")

## What's Coming in Part 3

*   **Rebase** — rewriting history (safely)
    
*   **Interactive rebase** — rearranging commits
    
*   **Cherry-pick** — copying specific commits
    
*   **Tagging** — marking important versions
    
*   **Rebasing vs Merging** — the great Git debate
