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:
|
|
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:
|
|
You can add other remotes too, which is useful when you’re contributing to open-source projects:
|
|
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:
|
|
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:
|
|
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:
|
|
It’s like checking your mailbox AND bringing the mail inside to read it all at once.
Common scenario:
|
|
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
|
|
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
|
|
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:
|
|
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
-
Start fresh:
1 2
git checkout main git pull origin main
-
Create a feature branch:
1
git checkout -b feature/awesome-new-thing
-
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"
-
Stay up-to-date with main:
1 2
git fetch origin git rebase origin/main
-
Push your branch:
1
git push origin feature/awesome-new-thing
-
Create a Pull Request (on GitHub/GitLab/etc.)
-
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!