# Git Basics You Actually Need to Know - Part 1

You've cloned a repo, made some changes, and now you're staring at the terminal wondering what comes next. `git add .`, `git commit -m "fix"`, `git push` — you've copy-pasted these commands a hundred times, but do you actually know what they're doing?

Let's fix that. This is Part 1 of understanding Git from the ground up — the commands you use every day, what they actually do, and when to use them.

## How Git Actually Works

Before touching any commands, you need to understand Git's mental model. Git has four places your code can exist:

1.  **Working Directory** - Your actual files, the ones you edit
    
2.  **Staging Area (Index)** - Changes you've marked to commit
    
3.  **Local Repository** - Commits on your machine
    
4.  **Remote Repository** - Commits on GitHub/GitLab
    

![](https://cdn.hashnode.com/uploads/covers/69d007f5e466e2b7625cd1df/230146c9-dfe9-4744-9f4f-e937e7e8a2d3.svg align="center")

Every Git command moves your code between these areas. Once you see this, Git stops being magic.

## Starting a Repository: git init

Creating a new Git repository is simple:

```bash
git init
```

This creates a hidden `.git` folder in your current directory. That folder contains the entire history of your project. Delete it and your Git history is gone — but your files remain.

When you clone a repository, `git clone` does `git init` plus downloads all the commits from the remote:

```bash
git clone https://github.com/user/repo.git
```

This creates a new folder, initializes Git, downloads the history, and checks out the default branch (usually `main` or `master`).

## Understanding Commits

A commit is a snapshot of your code at a specific moment. Not a diff, not changes — a complete snapshot. Git is smart enough to store this efficiently, but conceptually, each commit contains the full state of your project.

Every commit has:

*   A unique SHA hash (like `a3f2d91`)
    
*   A parent commit (except the first commit)
    
*   Author and timestamp
    
*   A commit message
    
*   A complete snapshot of all tracked files
    

Commits form a chain:

![](https://cdn.hashnode.com/uploads/covers/69d007f5e466e2b7625cd1df/3f6ecd95-6a65-48d7-a8dc-c46fa775c42b.svg align="center")

## The Three-Step Commit Process

Making a commit is actually three separate actions:

### Step 1: Edit Files (Working Directory)

You change a file. Git sees it as "modified" but hasn't done anything with it yet.

```bash
# Check what changed
git status
```

Output:

```plaintext
Changes not staged for commit:
  modified:   src/app.js
```

### Step 2: Stage Changes (Staging Area)

You mark which changes should go into the next commit:

```bash
# Stage a specific file
git add src/app.js

# Stage all changes
git add .

# Stage all changes in current directory
git add -A
```

Now `git status` shows:

```plaintext
Changes to be committed:
  modified:   src/app.js
```

### Step 3: Commit (Local Repository)

You save the staged changes as a commit:

```bash
git commit -m "Add user authentication"
```

Your changes are now permanently saved in Git's history. But they're still only on your machine.

**Shortcut:** Stage and commit modified files in one step (doesn't work for new files):

```bash
git commit -am "Update user model"
```

## Branches: Parallel Universes

A branch is just a pointer to a commit. That's it. When you create a branch, Git creates a new pointer. When you commit, the pointer moves forward.

```bash
# Create a new branch
git branch feature/login

# Switch to it
git checkout feature/login

# Or do both at once
git checkout -b feature/login
```

Modern Git also has:

```bash
git switch feature/login        # Switch branches
git switch -c feature/login     # Create and switch
```

![](https://cdn.hashnode.com/uploads/covers/69d007f5e466e2b7625cd1df/af529c21-3c93-40c1-bac3-1e547972affe.svg align="center")

When you're on a branch and make a commit, only that branch pointer moves. Other branches stay where they are. This lets you work on multiple features simultaneously without them interfering.

**List all branches:**

```bash
git branch           # Local branches only
git branch -a        # Include remote branches
```

**Delete a branch:**

```bash
git branch -d feature/login      # Safe delete (won't delete if unmerged)
git branch -D feature/login      # Force delete
```

## Connecting to Remote: git remote

A remote is a URL where your repository lives online (GitHub, GitLab, etc). When you clone, Git automatically adds a remote called `origin`.

```bash
# View remotes
git remote -v
```

Output:

```plaintext
origin  https://github.com/user/repo.git (fetch)
origin  https://github.com/user/repo.git (push)
```

**Add a remote manually:**

```bash
git remote add origin https://github.com/user/repo.git
```

**Change remote URL:**

```bash
git remote set-url origin https://github.com/user/new-repo.git
```

**Remove a remote:**

```bash
git remote remove origin
```

You can have multiple remotes. Common pattern for open source:

```bash
git remote add upstream https://github.com/original/repo.git
git remote add origin https://github.com/yourfork/repo.git
```

Now you can pull from `upstream` (the original project) and push to `origin` (your fork).

## Pushing and Pulling

Push sends your commits to the remote. Pull downloads commits from the remote.

**Push to remote:**

```bash
# First time on a new branch
git push -u origin feature/login

# After that, just
git push
```

The `-u` flag sets the upstream tracking relationship. After that, Git knows where to push when you type `git push`.

**Pull from remote:**

```bash
git pull
```

This does two things:

1.  `git fetch` - Downloads commits from remote
    
2.  `git merge` - Merges them into your current branch
    

**Fetch without merging:**

```bash
git fetch origin
```

This updates your local knowledge of what's on the remote, but doesn't change your working directory. Useful when you want to see what changed before merging.

## Git Reset: Undoing Things

Reset moves the branch pointer backward. It comes in three flavors:

### git reset --soft

Moves the branch pointer, keeps staging area and working directory:

```bash
git reset --soft HEAD~1
```

This undoes the last commit but keeps your changes staged. Useful when you committed too early or want to recommit with a better message.

**Use case:** You committed "WIP" and want to add more changes to that commit:

```bash
git reset --soft HEAD~1
# Make more changes
git add .
git commit -m "Complete feature implementation"
```

### git reset --mixed (default)

Moves the branch pointer, unstages changes, keeps working directory:

```bash
git reset HEAD~1
# Same as: git reset --mixed HEAD~1
```

This undoes the commit and unstages the changes, but your file edits remain. The most common reset type.

**Use case:** You committed the wrong files:

```bash
git reset HEAD~1
# Now selectively stage the right files
git add src/correct-file.js
git commit -m "Fix authentication bug"
```

### git reset --hard

Moves the branch pointer, clears staging area, resets working directory:

```bash
git reset --hard HEAD~1
```

⚠️ **Danger zone:** This deletes your changes. They're gone. Use with caution.

**Use case:** You completely messed up and want to start over:

```bash
git reset --hard HEAD  # Discard all uncommitted changes
git reset --hard origin/main  # Match remote exactly
```

![](https://cdn.hashnode.com/uploads/covers/69d007f5e466e2b7625cd1df/c4547444-f1b9-4c17-86a3-7f0d873c1afe.svg align="center")

**HEAD~1 vs HEAD^:**

*   `HEAD~1` - One commit before HEAD
    
*   `HEAD~2` - Two commits before HEAD
    
*   `HEAD^` - First parent (same as HEAD~1 for linear history)
    

## Checking History

See what commits exist:

```bash
# Basic log
git log

# One line per commit
git log --oneline

# With branch graph
git log --oneline --graph --all

# Last 5 commits
git log -5

# Commits by author
git log --author="John"

# Commits in date range
git log --since="2 weeks ago"
```

**See what changed in a commit:**

```bash
git show a3f2d91
```

**See what changed in a file:**

```bash
git log -p src/app.js
```

## Practical Workflows

### Starting a New Feature

```bash
# Make sure you're on main and up to date
git checkout main
git pull

# Create feature branch
git checkout -b feature/user-profile

# Work and commit
git add src/profile.js
git commit -m "Add user profile component"

# Push to remote
git push -u origin feature/user-profile
```

### Fixing a Mistake in Last Commit

**Wrong commit message:**

```bash
git commit --amend -m "Better commit message"
```

**Forgot to add a file:**

```bash
git add forgotten-file.js
git commit --amend --no-edit
```

The `--amend` flag replaces the last commit. Don't amend commits that you've already pushed to a shared branch — it rewrites history.

### Discarding Uncommitted Changes

**Discard changes in one file:**

```bash
git checkout -- src/app.js
# Or in modern Git:
git restore src/app.js
```

**Discard all changes:**

```bash
git reset --hard HEAD
```

**Unstage a file (keep changes):**

```bash
git reset HEAD src/app.js
# Or:
git restore --staged src/app.js
```

## What We Covered

You now understand:

*   Git's four areas: working directory, staging, local repo, remote repo
    
*   How commits form a chain of snapshots
    
*   Creating and switching branches
    
*   The three-step commit process (edit, stage, commit)
    
*   Connecting to remotes and pushing/pulling
    
*   The three types of reset and when to use each
    
*   Basic history exploration
    

In Part 2, we'll cover merging, rebasing, handling conflicts, stashing, and recovering lost commits.

## Common Mistakes to Avoid

**Committing to main directly:** Always create a feature branch. Keep main clean.

**Not pulling before pushing:** Always pull before starting work. Prevents conflicts.

**Using** `reset --hard` **carelessly:** Your changes are gone. Make sure you want that.

**Amending pushed commits:** Rewrites history. Only amend commits that haven't been pushed.

**Forgetting to track new files:** `git add .` includes new files. `git commit -am` doesn't.

* * *

## TLDR;

Git has four areas: working directory (your files), staging area (changes marked for commit), local repository (commits on your machine), and remote repository (commits on GitHub/GitLab). The basic workflow is: edit files → `git add` to stage → `git commit` to save → `git push` to upload. Branches are pointers to commits — create them with `git checkout -b branch-name`. Connect to remotes with `git remote add origin url`. Reset moves the branch pointer: `--soft` keeps changes staged, `--mixed` (default) unstages them, `--hard` deletes everything. Use `git log` to see history. Always pull before pushing. Never reset hard unless you want to lose changes. Part 2 will cover merging, rebasing, and conflict resolution.
