Back to Git: Branching, Merge, Rebase
Q4Question 4 of 6

Git's four locations for code and the commands that move changes between them

Key Concepts
  • The working directory is the folder of files you edit on disk; changed files are unstaged until you explicitly add them.
  • The staging area (index) is where you declare exactly which changes go into the next commit, enabling focused, clean commits.
  • The local repository (.git) stores committed snapshots entirely on your machine with no network required.
  • The remote repository (GitHub, GitLab) is the shared copy the whole team uses as the common meeting point.
  • git add moves changes from working directory to staging; git commit saves staging to local repo; git push shares local with remote.
  • git fetch downloads remote changes without touching your working directory; git pull does fetch plus merge in one step.
  • git restore unstages or discards working-directory changes; git reset moves the branch pointer backward.

Definition

Working directory, staging area, local repo, remote repo -- add stages, commit saves locally, push shares upward, and fetch or pull brings changes down.
  • Working directory -- the set of files you actually edit on disk; changes here are called unstaged or modified.
  • Staging area (index) -- a holding area where you declare exactly which changes go into the next commit.
  • Local repository (.git) -- the database on your machine that stores committed snapshots, entirely offline.
  • Remote repository -- the shared copy on a server like GitHub that the whole team uses.
  • git add -- moves changes from working directory to staging area.
  • git commit -- takes everything staged and records it as a permanent snapshot in the local repository.
  • git push -- uploads local commits to the remote repository.
  • git fetch -- downloads remote changes into local repo without touching your working directory.
  • git pull -- fetch followed by merge (or rebase) into your current branch.

Imagine processing transactions at National Bank of India. The working directory is your desk where you edit draft forms. The staging area is the tray where you place only the forms you want to submit in this batch. The local repository is your personal locked drawer where submitted batches are filed as dated snapshots. The remote repository is the central vault that every branch shares. git add moves a form into the tray, git commit files it into your drawer, git push sends it to the vault, and git fetch brings the vault's latest batches back to you.

Understanding the Concepts

What is the working directory?

The working directory is the folder of files you see and edit. When you change a file, that change exists only here and is unstaged. Git knows the file differs from the last committed version, but you have not told it to include this change in the next commit.

BASH
# Edit a file in the working directory
cd /workspace/payment-service
vim src/main/java/com/bank/payments/TransferService.java

# Check status -- file is modified but unstaged
git status
TEXT
On branch feature/transfer-limit
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)

  modified:   src/main/java/com/bank/payments/TransferService.java

What is the staging area?

The staging area (also called the index) is Git's distinctive middle step. It lets you declare exactly which changes belong in the next commit. You might have edited five files but only want to commit three as one logical change. git add moves a change from the working directory into staging.

BASH
# Stage only the transfer service change, not the unrelated config edit
git add src/main/java/com/bank/payments/TransferService.java

git status
TEXT
On branch feature/transfer-limit
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)

  modified:   src/main/java/com/bank/payments/TransferService.java

Changes not staged for commit:
  modified:   src/main/resources/application.yml
JAVA
package com.bank.payments;

import java.math.BigDecimal;

public class TransferService {

    private static final BigDecimal DAILY_LIMIT =
        new BigDecimal("1000000.00");

    public void transfer(String fromAccount, String toAccount,
                         BigDecimal amount) {
        if (amount.compareTo(DAILY_LIMIT) > 0) {
            throw new IllegalArgumentException(
                "Transfer exceeds daily limit of " + DAILY_LIMIT);
        }
        System.out.println("Transferring " + amount
            + " from " + fromAccount + " to " + toAccount);
    }
}

What is the local repository?

The local repository is the .git directory. When you run git commit, Git takes everything in staging and records it as a permanent snapshot with a unique hash, your author information, a timestamp, and a message. No network is involved -- this is why Git is a distributed version control system.

BASH
git commit -m "feat: add daily transfer limit of 10 lakh for SAV accounts"
TEXT
[feature/transfer-limit abc1234] feat: add daily transfer limit of 10 lakh for SAV accounts
 1 file changed, 12 insertions(+), 2 deletions(-)
BASH
# The commit is stored locally -- no network needed
git log --oneline -3
TEXT
abc1234 feat: add daily transfer limit of 10 lakh for SAV accounts
def5678 fix: correct rounding in fee calculation
ghi9012 initial payment service setup

What is the remote repository?

The remote repository is a shared copy on a server like GitHub or GitLab. Your commits are not visible to anyone else until you push them. git push uploads commits from your local branch to the remote.

BASH
# Push your local commits to the remote
git push -u origin feature/transfer-limit
TEXT
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 412 bytes | 412.00 KiB/s, done.
To github.com:nbi/payment-service.git
 * [new branch]      feature/transfer-limit -> feature/transfer-limit
Branch 'feature/transfer-limit' set up to track 'origin/feature/transfer-limit'.

How does git fetch differ from git pull?

git fetch downloads new commits from the remote but does NOT change your working directory or current branch. It updates the remote-tracking references like origin/main so you can inspect what changed. git pull does a fetch followed by a merge into your current branch in one step.

BASH
# FETCH -- download but do not apply
git fetch origin

# See what changed on main without touching your branch
git log HEAD..origin/main --oneline
TEXT
jkl3456 feat: add SIP auto-debit (Priya)
mno7890 fix: correct interest rounding (Pankaj)
BASH
# Now merge when ready
git merge origin/main

# OR PULL -- fetch + merge in one step
git pull origin main

How do you undo changes at each location?

git restore discards or unstages changes. git reset moves the branch pointer. The undo command depends on which location the change is in.

BASH
# Discard working directory changes (revert file to last commit)
git restore src/main/java/com/bank/payments/TransferService.java

# Unstage a file (move from staging back to working directory)
git restore --staged src/main/java/com/bank/payments/TransferService.java

# Undo the last commit but keep changes staged
git reset --soft HEAD~1

# Undo the last commit and unstage changes
git reset --mixed HEAD~1

# Undo the last commit and discard all changes (DANGEROUS)
git reset --hard HEAD~1

What are common mistakes?

The most common mistakes are using git add . to stage everything including unrelated changes, committing directly without staging specific files, and using git pull when git fetch would be safer for inspecting changes first.

BASH
# WRONG -- stages everything, including an unrelated config experiment
git add .
git commit -m "feat: add transfer limit"

# CORRECT -- stage only the relevant files
git add src/main/java/com/bank/payments/TransferService.java
git add src/test/java/com/bank/payments/TransferServiceTest.java
git commit -m "feat: add daily transfer limit of 10 lakh [NBI-456]"

What should a senior engineer know?

A senior engineer prefers fetch over pull in deliberate situations because it lets them review incoming changes before merging. They stage specific files rather than using add dot, write focused commits that each represent one logical change, and use restore and reset fluently to undo at each level. They understand that Git's distributed nature means commits are free and local -- you should commit frequently and clean up with interactive rebase before sharing.

Visual Overview

DIAGRAM
  Git's Four Locations
  ────────────────────

  ┌──────────────┐   git add    ┌──────────────┐   git commit   ┌──────────────┐   git push    ┌──────────────┐
  │  Working      │────────────▶│  Staging      │──────────────▶│  Local Repo   │────────────▶│  Remote Repo  │
  │  Directory    │             │  Area (Index) │               │  (.git)       │             │  (GitHub)     │
  │              │◀────────────│              │◀──────────────│              │◀────────────│              │
  │  edit files   │  git restore │  staged       │  git reset    │  committed    │  git fetch   │  shared       │
  │  on disk      │  --staged    │  changes      │  --soft       │  snapshots    │  git pull    │  copy         │
  └──────────────┘              └──────────────┘               └──────────────┘              └──────────────┘

  Forward flow:  edit → add → commit → push
  Backward flow: fetch/pull ← remote
                 restore/reset ← undo

  Example:
  ┌─────────────────────────────────────────────────────────┐
  │ 1. Edit TransferService.java          (working dir)     │
  │ 2. git add TransferService.java       (→ staging)       │
  │ 3. git commit -m "add transfer limit" (→ local repo)    │
  │ 4. git push origin feature/limit      (→ remote)        │
  └─────────────────────────────────────────────────────────┘

Key Takeaway

Git organizes code across four locations. The working directory is the folder you edit on disk. The staging area lets you declare exactly which changes go into the next commit, enabling focused commits instead of dumping every edit together. The local repository stores committed snapshots entirely offline. The remote repository is the shared copy the team uses.

The commands form a clear forward pipeline. git add moves changes from working to staging. git commit records everything staged as a permanent local snapshot. git push uploads local commits to the remote. Going the other direction, git fetch downloads remote changes without touching your branch, and git pull does fetch plus merge in one step.

For undoing, git restore discards or unstages working-directory changes, and git reset moves the branch pointer backward with three modes -- soft keeps changes staged, mixed keeps them unstaged, and hard discards them entirely. The key habit is staging specific files rather than everything, so each commit represents one logical change.

Remember one sentence: edit in the working directory, stage with add, save locally with commit, share with push, and use fetch to bring changes down safely before merging.

---

Share
Use ← → arrow keys to navigate