DEV Community

Gold roger
Gold roger

Posted on

Git Explained: From Mental Models to Production Workflows

Introduction

If you're like me, you started using Git because someone told you to. You learned the magic words—git add, git commit, git push—and they kinda worke# Git Explained: From Mental Models to Production Workflows

Introduction

If you're like me, you started using Git because someone told you to. You learned the magic words—git add, git commit, git push—and they kinda worked. But you didn't really understand what was happening underneath.

This article is for you. I'm going to walk you through Git the way it finally clicked for me: starting with a mental model that actually makes sense, then building up to real-world workflows that professionals use every day.


Part 1: The Mental Model

Commits: Snapshots in Time

Forget thinking of commits as "saves." Think of them as photographs of your entire codebase at a moment in time.

When you make a commit, Git takes a picture of all your files—exactly as they exist right now. That photo is stored in Git's database forever. You can always go back and look at it, or restore your code to exactly how it was in that moment.

Key insight: Every commit is complete. If you want to see what your code looked like 5 commits ago, Git can show you the entire state—all files, all changes.

The Commit Train: Building History

Now imagine linking these commits together in a chain. The first commit has no parent. The second commit points back to the first. The third points to the second. And so on.

This chain is your history. It's a train of commits, each one building on the last. This is why Git is powerful—you can see the entire journey of how your code evolved.

Commit 1 → Commit 2 → Commit 3 → Commit 4
(Initial)  (Feature)  (Bug fix)  (Refactor)
Enter fullscreen mode Exit fullscreen mode

You can move back along this train whenever you want. Go back to Commit 2? Your code looks exactly as it did then.

The Staging Area: Selective Commits

Here's where most people get confused. Why does Git have two steps—git add and git commit—instead of just one?

Answer: Control.

Imagine your project has 4 files, but you only want to commit 3 of them right now. The staging area lets you do this:

  1. git add file1.py file2.py file3.py — Add the 3 files you want
  2. git commit -m "your message" — Commit only those 3 files

The fourth file stays out of the commit. It's still changed on your computer, but it's not part of this snapshot.

This matters because it lets you organize your commits logically. One commit = one logical piece of work. Not a jumble of unrelated changes.


Part 2: Branches—Parallel Universes of Code

The Problem with One Timeline

Imagine you're building a repair shop app. You're working on Feature A (booking system). Then your boss says "we need Feature B (payment processing) shipped tomorrow."

If you just keep committing to the same line, you'll have:

  • Commits for Feature A (incomplete)
  • Commits for Feature B (complete)
  • All mixed together on the same branch

Now you can't deploy just Feature B without Feature A. You're stuck.

Branches: Separate Timelines

A branch is a pointer to a commit. It's a separate line of development that doesn't interfere with other branches.

Here's how it works:

        Feature A (commits 2, 3, 4)
       /
Main (commit 1) → Feature B (commits 2, 3) → Merged back
       \
        Hotfix (commit 2)
Enter fullscreen mode Exit fullscreen mode

Now:

  • Feature A can develop independently
  • Feature B can develop independently
  • Main stays stable and production-ready
  • When Feature B is done, merge it into main and ship it
  • Feature A keeps developing without blocking anything

Main Branch: Your Safety Net

Main branch = production code. It's the code you trust. It's tested, it's stable, it's live in the world.

You never build directly on main. You build on feature branches, and only merge into main when the code is ready for production.

This is how teams prevent disasters. Main is always deployable. Always.


Part 3: Real-World Workflows

The Standard Feature Branch Workflow

Here's how a professional team uses Git:

Step 1: Start a new feature

git checkout main          # Make sure you're on main
git pull origin main       # Get the latest code
git checkout -b feature/booking-system  # Create and switch to feature branch
Enter fullscreen mode Exit fullscreen mode

Step 2: Build the feature

# Edit files, test, repeat
git add file1.py file2.py
git commit -m "feat: add booking form validation"

git add database.py
git commit -m "feat: connect booking form to database"

git add tests.py
git commit -m "test: add booking system tests"
Enter fullscreen mode Exit fullscreen mode

Notice: Multiple commits, each representing one logical piece of work.

Step 3: Feature is done and tested

git push origin feature/booking-system  # Push to GitHub
Enter fullscreen mode Exit fullscreen mode

Then create a Pull Request (PR) on GitHub. Your team reviews the code. If it looks good, merge it.

Step 4: Merge into main

git checkout main
git pull origin main
git merge feature/booking-system
git push origin main
Enter fullscreen mode Exit fullscreen mode

Your feature is now live. Delete the feature branch (you don't need it anymore):

git branch -d feature/booking-system
Enter fullscreen mode Exit fullscreen mode

The Hotfix: Emergency Bug Fixes

Production is live. Users find a bug. You need to fix it NOW.

Important: You fix it on a hotfix branch, not directly on main.

git checkout main
git checkout -b hotfix/email-double-send

# Fix the bug
git add email.py
git commit -m "fix: prevent double email sends"

# Merge back to main immediately
git checkout main
git merge hotfix/email-double-send

# Push to production
git push origin main

# Delete the hotfix branch
git branch -d hotfix/email-double-send
Enter fullscreen mode Exit fullscreen mode

Now main is fixed and deployable. Production is patched. Crisis averted.

Merge Conflicts: When Humans Decide

Say two people changed the same line of code in different branches. When you try to merge them, Git can't automatically decide which version is correct.

Git will show you something like:

<<<<<<< HEAD (main branch)
version of code from main
=======
version of code from feature branch
>>>>>>>>
Enter fullscreen mode Exit fullscreen mode

You manually edit the file, pick the version you want, and commit.

Git is asking you: "Which version is right?" Because only a human knows the answer.


Part 4: Commit Message Best Practices

Your commit messages tell a story. Future you (and your teammates) will read them to understand why a change was made.

Bad commit messages:

git commit -m "stuff"
git commit -m "fixed things"
git commit -m "changes"
Enter fullscreen mode Exit fullscreen mode

Good commit messages:

git commit -m "feat: add booking form validation"
git commit -m "fix: prevent double email sends in confirmation"
git commit -m "refactor: simplify database query logic"
Enter fullscreen mode Exit fullscreen mode

The Pattern

Start with a type:

  • feat: A new feature
  • fix: A bug fix
  • refactor: Code cleanup (no feature change)
  • test: Adding tests
  • docs: Documentation changes
  • style: Formatting (no logic change)

Then describe what you did in present tense: "add", "fix", "simplify", not "added", "fixed", "simplified".

Why? Because when you read the git log, it reads like a series of actions:

feat: add booking form
fix: validate email in form
refactor: clean up form code
test: add form validation tests
Enter fullscreen mode Exit fullscreen mode

Part 5: When to Commit

This is the question that trips people up: When should you actually make a commit?

The Rule

Commit when you've completed one logical unit of work that is testable and works.

Not "perfect"—just complete and functional. One reason to commit.

Examples

Good commits:

  • ✅ "Add email validation to booking form" — One feature, complete
  • ✅ "Fix typo in error message" — One bug, fixed
  • ✅ "Refactor database queries" — One improvement, done
  • ✅ "Add tests for booking system" — One logical piece

Bad commits:

  • ❌ "Add email validation + refactor database + fix typo + update tests" — Too many things
  • ❌ "Work in progress" — Not complete
  • ❌ "Stuff" — Not clear what you did

The Test

Ask yourself: If I had to revert this commit, would it break something?

If yes, you've bundled too much together. Split it into multiple commits.

If no, it's a good commit.


Part 6: The Complete Workflow (From Start to Finish)

Here's a real-world scenario: You're building a repair shop app with a teammate.

Initial Setup

git clone <repository-url>
cd repair-shop-app
Enter fullscreen mode Exit fullscreen mode

You: Building the Booking System

# Create a feature branch
git checkout -b feature/booking-system

# Work and commit logically
git add booking_form.py
git commit -m "feat: create booking form component"

git add database.py
git commit -m "feat: add booking to database"

git add tests.py
git commit -m "test: add booking system tests"

# Push to GitHub
git push origin feature/booking-system
Enter fullscreen mode Exit fullscreen mode

Your Teammate: Building Payment Processing

git checkout -b feature/payment-processing

git add payment.py
git commit -m "feat: integrate Stripe payment"

git add error_handling.py
git commit -m "feat: handle payment errors"

git push origin feature/payment-processing
Enter fullscreen mode Exit fullscreen mode

Both of you are working independently. No interference.

Feature B (Payment) is Done First

# Your teammate creates a Pull Request on GitHub
# Team reviews it
# Looks good, merge it

git checkout main
git pull origin main
git merge feature/payment-processing
git push origin main
git branch -d feature/payment-processing
Enter fullscreen mode Exit fullscreen mode

Payment processing is live. Feature A is still developing independently.

Bug in Production

Users report that confirmation emails send twice.

git checkout main
git checkout -b hotfix/email-double-send

git add email.py
git commit -m "fix: prevent double email sends"

git checkout main
git merge hotfix/email-double-send
git push origin main
git branch -d hotfix/email-double-send
Enter fullscreen mode Exit fullscreen mode

Bug is fixed. Production is patched.

Feature A is Done

git checkout feature/booking-system

# Feature A has been developing this whole time
# Now it's done and tested

git push origin feature/booking-system

# Create Pull Request, team reviews
# Merge it

git checkout main
git pull origin main
git merge feature/booking-system
git push origin main
git branch -d feature/booking-system
Enter fullscreen mode Exit fullscreen mode

Both features are now live. All commits are in history. All branches are cleaned up.


Part 7: The Commands You Actually Need

Here are the essential Git commands for this entire workflow:

# Clone a repository
git clone <url>

# Create and switch to a new branch
git checkout -b feature/name

# Switch to an existing branch
git checkout branch-name

# Check what branch you're on
git status

# Stage files for commit
git add filename
git add .  # Add all changed files

# Commit
git commit -m "type: description"

# Push to remote (GitHub)
git push origin branch-name

# Pull latest from remote
git pull origin branch-name

# Merge another branch into current branch
git merge branch-name

# Delete a branch
git branch -d branch-name

# View commit history
git log

# See what changed in a commit
git show commit-hash
Enter fullscreen mode Exit fullscreen mode

That's it. Those 12 commands cover 95% of what you'll do.


Conclusion

Git isn't magic. It's a system for:

  1. Taking snapshots of your code (commits)
  2. Building a history of those snapshots (the commit train)
  3. Working on multiple features in parallel (branches)
  4. Merging them back together safely (merges)
  5. Keeping production stable (main branch as safety net)

The mental model is simple. The commands are simple. The power comes from using them consistently.

Start with small commits. One logical piece of work per commit. Keep main stable. Work on branches. Review before merging. Keep history clean.

Do that, and you'll be ahead of most developers.


  1. Try it: Create a test repository. Make some branches, commit some stuff, merge them back. Get comfortable with the commands.

  2. Read the docs: GitHub has great guides on branching strategies and workflows.

  3. Work with a team: The real value of Git shows up when you're collaborating. Push your branches, create Pull Requests, review each other's code.

  4. Keep learning: Once you're solid on basics, look into rebasing, squashing commits, and more advanced workflows.

Happy coding. 🎯

Top comments (0)