Featured image of post Understanding Git: The Ultimate Guide

Understanding Git: The Ultimate Guide

A comprehensive, beginner-friendly guide to Git concepts, commands, and workflows with practical examples and clear explanations

The Mental Model: Understanding Git’s Core Concepts

Ever stared at Git documentation and felt like you were reading hieroglyphics? I’ve been there too. Let’s break Git down in a way that actually makes sense.

Git’s Big Picture: It’s All About Copies

At its heart, Git is just a sophisticated system for managing different copies of your code:

  • Remote copies: These live on servers (like GitHub, GitLab, or your company’s servers)
  • Local copy: This is the one on your computer that you actually work with

Here’s what makes this interesting:

While the remote can have many different copies (branches), you only work with one active version locally at any given time.

Think of it like this: imagine you’re working on a group essay in college. The “official” version lives in a shared Google Drive (remote), but everyone has their own local copy they’re tweaking. Git helps you manage how these versions sync up.

The Repository: Your Project’s Home

A repository (or “repo”) is simply the collection of all these copies, along with their history. Each repository has its own unique URL (the repo_url).

For example, the React repository lives at https://github.com/facebook/react.git - that’s its repo_url.

Git Concepts Explained With Real Examples

What is a “Commit”?

A commit is like taking a snapshot of your code at a specific point in time.

Think of commits like saving checkpoints in a video game. You’ve made progress, and you want to make sure you can always return to this exact state if things go sideways.

Example scenario:

1
2
3
# You've made changes to your code
git add index.html styles.css
git commit -m "Add responsive header and fix navigation styles"

At this point, you’ve saved this checkpoint locally, but the remote repository doesn’t know about it yet. That’s why we need to push our commits.

What is “Origin”?

Since typing out full repository URLs is tedious, Git uses aliases like “origin” to refer to remote repositories.

“Origin” is just the default nickname Git gives to the place where you originally cloned your repository from.

Real-world example:

1
2
3
4
5
6
7
8
9
# When you clone a repository
git clone https://github.com/your-username/cool-project.git

# Git automatically sets up "origin" to point to that URL
# Later you can just say:
git push origin main

# Instead of the much more tedious:
git push https://github.com/your-username/cool-project.git main

You can add other remotes too, which is useful when you’re contributing to open-source projects:

1
2
3
4
5
# Add another remote repository
git remote add upstream https://github.com/original-creator/cool-project.git

# Now you can fetch changes from the original repository
git fetch upstream

What is a “Branch”?

This is where many Git tutorials get confusing. Let’s set things straight:

A branch is not really a branch in the traditional sense - it’s more like a pointer or label that indicates a specific timeline of development.

If we use a tree as an analogy, a branch should really be called a leaf (time itself is the branch)

Here’s a clearer way to think about it:

Imagine your project timeline as a train track. The main branch is the main track. When you create a new branch, you’re essentially placing a flag at a specific point saying “I’m going to build a new track that diverges from here.”

Practical example:

1
2
3
4
5
6
# Start a new feature branch from main
git checkout main
git checkout -b feature/user-authentication

# Now you can make changes without affecting the main branch
# Each commit moves the feature/user-authentication pointer forward

All your commits on the feature branch create a separate timeline of development, which can later be merged back into the main timeline.

What is “Fetch”?

The git fetch command is like checking your mailbox for updates without actually opening and reading the mail yet.

When you fetch, Git downloads information about what has changed in the remote repository, but doesn’t apply those changes to your working files.

Example:

1
2
3
4
5
6
# Check for updates from the remote repository
git fetch origin

# Now Git knows about remote changes, but hasn't applied them
# You can see what branch is where with:
git branch -a

After fetching, you can decide if and how you want to incorporate those changes into your local copy.

What is “Pull”?

The git pull command is a two-step process combining fetch and merge:

1
git pull origin main = git fetch origin + git merge origin/main

It’s like checking your mailbox AND bringing the mail inside to read it all at once.

Common scenario:

1
2
3
4
# Start your workday by getting the latest changes
git pull origin main

# This updates your local main branch with any changes your teammates pushed while you were away

But sometimes, you might want to use git pull --rebase instead, which brings us to our next topic…

The Battle: “Merge” vs “Rebase”

This is where Git gets philosophical, and developers get into heated debates. Let me break it down with a real scenario:

Scenario: You’ve been working on a feature branch for a few days. Meanwhile, the main branch has moved forward with other people’s changes.

Option 1: Merge

1
2
git checkout feature-branch
git merge main

Merging creates a “merge commit” that ties the two branches together. Your history shows a branch that diverged and then came back together.

Option 2: Rebase

1
2
git checkout feature-branch
git rebase main

Rebasing “replays” your changes on top of the latest main branch. It’s like saying, “Pretend I started my work from the current state of main.”

The key difference:

  • Merge: Preserves history exactly as it happened (branch and rejoin)
  • Rebase: Creates a cleaner, linear history (as if you never branched)

When to use which:

  • Use merge for public/shared branches that others work on
  • Use rebase for your personal feature branches before merging to main

Pro tip: It’s often a good idea to rebase your feature branch onto main before merging. This gives you the cleanest history and minimizes merge conflicts.

What is “Stash”?

Ever been working on something, then suddenly needed to switch tasks without committing your half-finished work?

That’s what git stash is for - it’s like putting your changes in a drawer to deal with later.

Real scenario:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# You're working on a feature, but there's an urgent bug to fix
# Stash your current changes
git stash save "Half-implemented user profile page"

# Switch to fix the bug
git checkout main
git checkout -b hotfix/critical-login-bug

# Fix the bug, commit, and merge it

# Now go back to your feature
git checkout feature/user-profile
git stash list  # See all your stashed changes
git stash apply stash@{0}  # Apply the most recent stash

# Once you're done with a stash, you can drop it
git stash drop stash@{0}

Think of stashes as sticky notes you can apply to different versions of your code.

Common Git Workflows

Now that you understand the pieces, let’s put them together into a typical workflow:

The Feature Branch Workflow

  1. Start fresh:

    1
    2
    
    git checkout main
    git pull origin main
    
  2. Create a feature branch:

    1
    
    git checkout -b feature/awesome-new-thing
    
  3. Work in small commits:

    1
    2
    3
    4
    5
    6
    7
    
    # Make changes
    git add -A
    git commit -m "Implement the first part of awesome feature"
    
    # More changes
    git add -A
    git commit -m "Complete the awesome feature"
    
  4. Stay up-to-date with main:

    1
    2
    
    git fetch origin
    git rebase origin/main
    
  5. Push your branch:

    1
    
    git push origin feature/awesome-new-thing
    
  6. Create a Pull Request (on GitHub/GitLab/etc.)

  7. After approval, merge or rebase and merge

Wrapping Up

Git might seem complex at first, but once you understand its mental model, everything clicks into place. Remember:

  • Branches are just pointers to specific commits
  • Commits are snapshots of your code at a point in time
  • Remote repositories store the shared history
  • Your local repository is your personal workspace

The most important thing is to develop a workflow that makes sense for you and your team, and stick to it consistently.

What Git concepts still confuse you? Let me know in the comments below!