Back to Blog

Git CLI Crash Course: From Zero to Version Control Hero

GitDevOpsTutorial
5 min read
Usman Ali Qureshi

Usman Ali Qureshi

Learn Git the practical way. No fluff, just the commands you'll actually use every day, plus the ones that'll save you when things go wrong.

Git CLI Crash Course: From Zero to Hero 🚀

Alright, let's be honest. Git can feel intimidating. All those commands, the weird terminology, the fear of somehow deleting everything. I've been there.

But here's what I've learned after years of using Git daily: you really only need to know about 20 commands for 95% of your work. The rest you can look up when you need them.

So let's skip the theory-heavy explanations and get you productive with Git as fast as possible.


📋 What We're Covering

  1. Git Fundamentals
  2. Commands You'll Use Every Day
  3. Branching and Merging
  4. Working with Others
  5. Fixing Your Mistakes
  6. Power User Stuff
  7. Good Habits
  8. Common Mistakes

🎯 Git Fundamentals

What Even Is Git?

Git tracks changes in your code. That's it. Every time you save a "checkpoint" (called a commit), Git remembers exactly what your code looked like at that moment.

The magic is that unlike something like Google Docs, everyone on the team has their own complete copy of the project history. You can work offline, and nothing is lost if one person's computer dies.

The Three Places Your Files Live

This trips people up, so let me break it down simply:

Working Directory → Staging Area → Repository
   (your files)     (ready to save)   (saved history)

Or think of it like this:

Edit files → git add → git commit → git push
   📝           ➕         💾          ☁️

First Time Setup

Before you can do anything, Git needs to know who you are:

# Tell Git your name and email
git config --global user.name "Your Name"
git config --global user.email "your@email.com"

# Use 'main' as default branch (the new standard)
git config --global init.defaultBranch main

# Set your editor for commit messages
git config --global core.editor "code --wait"  # VS Code
# OR
git config --global core.editor "vim"

# See what you've set
git config --list

Do this once and you're done forever.


💼 Commands You'll Use Every Day

Starting Out

# Start a new project
git init
git init my-project  # Creates folder and initializes

# Get someone else's project
git clone https://github.com/user/repo.git
git clone https://github.com/user/repo.git my-folder  # Different folder name

The Workflow You'll Repeat a Thousand Times

# 1. Check what's changed (seriously, run this constantly)
git status

# 2. Stage what you want to save
git add file.txt                    # One file
git add folder/                     # Whole folder
git add .                           # Everything
git add *.js                        # All JS files
git add -p                          # Review each change (super useful)

# 3. Save your changes
git commit -m "Add user authentication"
git commit -am "Quick commit"      # Stage + commit tracked files
git commit --amend                 # Oops, fix that last commit message

# 4. See what happened
git log                            # Full history
git log --oneline                  # Compact (my favorite)
git log --graph --all --decorate   # Pretty branch visualization
git log -5                         # Just last 5
git log --since="2 weeks ago"      # Recent stuff

# 5. See what changed
git diff                           # What's different (unstaged)
git diff --staged                  # What's staged
git diff HEAD                      # Everything since last commit
git diff branch1 branch2           # Compare branches

The git status and git log --oneline commands are your best friends. When in doubt, run them.


🌳 Branching and Merging

Branches are probably Git's best feature. You can try out ideas without messing up the stable code.

Branch Basics

# Create a new branch
git branch feature-login
git branch feature-login main      # Branch from specific point

# Switch to it
git checkout feature-login
git switch feature-login           # Newer, cleaner way

# Create and switch in one go (what you'll usually do)
git checkout -b feature-login
git switch -c feature-login        # Newer version

# See your branches
git branch                         # Local ones
git branch -r                      # Remote ones
git branch -a                      # All of them
git branch -v                      # With last commit info

# Rename
git branch -m old-name new-name
git branch -M new-name             # Rename the one you're on

# Delete
git branch -d feature-login        # Safe delete (won't delete unmerged)
git branch -D feature-login        # Force delete (careful!)

Merging Branches Together

# Go to the branch you want to merge INTO
git checkout main

# Merge the other branch in
git merge feature-login

# Some useful options
git merge --no-ff feature-login    # Always create a merge commit
git merge --squash feature-login   # Combine all commits into one

# Things got messy? Back out
git merge --abort

Dealing with Merge Conflicts

Sometimes Git can't figure out how to combine changes. When that happens, you'll see something like this in your file:

======= HEAD
Your changes
=======
Their changes
======= branch-name

Don't panic. Here's what to do:

# 1. Open the file and pick what you want to keep
# 2. Delete the ======= and branch markers
# 3. Stage the fixed file
git add conflicted-file.txt

# 4. Finish the merge
git commit

Want something visual? Run git mergetool to use a GUI merger.


🤝 Working with Others

Managing Remotes

# Connect to GitHub (or wherever)
git remote add origin https://github.com/user/repo.git

# See what's connected
git remote -v

# Change the URL
git remote set-url origin https://new-url.git

# Remove a connection
git remote remove origin

Push and Pull

# Send your stuff
git push origin main
git push -u origin main            # Set it as default upstream
git push --all                     # All branches
git push --tags                    # All tags

# Get their stuff
git pull origin main               # Download and merge
git pull --rebase origin main      # Download and rebase (cleaner)

# Just download without merging (safer)
git fetch origin
git fetch --all                    # From all remotes

Typical Workflow When Collaborating

Here's basically what I do every day:

# 1. Start fresh
git checkout -b feature-new-ui

# 2. Do work, commit as you go
git add .
git commit -m "Add new UI components"

# 3. Push it up
git push -u origin feature-new-ui

# 4. Keep your branch up to date with main
git checkout feature-new-ui
git fetch origin main
git merge origin/main

⏮️ Fixing Your Mistakes

This is where Git really shines. Almost nothing is permanent.

"I didn't mean to stage that"

# Unstage but keep changes
git restore --staged file.txt      # Modern way
git reset HEAD file.txt            # Old way

# Throw away changes entirely (careful!)
git restore file.txt               # Modern (⚠️ DESTRUCTIVE)
git checkout -- file.txt           # Old way (⚠️ DESTRUCTIVE)

# Nuclear option - discard EVERYTHING
git restore .                      # ⚠️ DANGER
git reset --hard HEAD              # ⚠️ DANGER

"I messed up that commit"

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

# Undo commit, keep changes unstaged
git reset HEAD~1
git reset --mixed HEAD~1           # Same thing

# Undo commit AND throw away changes
git reset --hard HEAD~1            # ⚠️ DESTRUCTIVE

# Undo multiple commits
git reset --soft HEAD~3            # Last 3

# Make a new commit that reverses an old one (safe for shared code)
git revert abc123
git revert HEAD                    # Revert last commit

"I already pushed it..."

# Don't reset pushed commits! Use revert instead:
git revert abc123
git push origin main

# If you REALLY have to force push:
git push --force-with-lease origin main  # At least this checks first

Never force push to a shared branch like main. You'll mess up everyone else.


🔥 Power User Stuff

Stashing (Pause Your Work)

Need to switch branches but you're mid-work? Stash it.

# Stash current changes
git stash
git stash save "Work on login feature"

# See your stashes
git stash list

# Get them back
git stash apply                    # Keep in stash list
git stash pop                      # Remove from stash list
# For a specific stash: git stash pop stash@[N]

# See what's in a stash
git stash show
git stash show -p                  # Full diff

# Clean up
# Delete one: git stash drop stash@[N]
git stash clear                    # Delete all

Cherry-Picking

Grab specific commits from other branches:

# Apply one commit to current branch
git cherry-pick abc123

# Multiple commits
git cherry-pick abc123 def456

# Apply without committing (lets you modify first)
git cherry-pick --no-commit abc123

Interactive Rebase

Rewrite history. Incredibly powerful, slightly dangerous.

# Edit last 3 commits
git rebase -i HEAD~3

In the editor, you can:

  • pick = keep as is
  • reword = change commit message
  • edit = stop and let you amend
  • squash = combine with previous
  • fixup = combine, throw away message
  • drop = delete entirely

Example:

pick abc123 Add feature
squash def456 Fix typo
reword ghi789 Update docs

Reflog - Your Safety Net

Even if you "delete" something, Git usually remembers for 30 days.

# See everything that's happened
git reflog

# Found what you lost? Get it back
git checkout abc123                # Just look at it
git cherry-pick abc123             # Grab just that commit
git reset --hard abc123            # Reset to that point

Reflog has saved me more times than I can count.

Tags

Mark important points like releases:

# Lightweight tag
git tag v1.0.0

# Annotated tag (better for releases)
git tag -a v1.0.0 -m "Release version 1.0.0"

# List them
git tag
git tag -l "v1.*"                  # Pattern match

# Push tags
git push origin v1.0.0
git push origin --tags

# Delete
git tag -d v1.0.0
git push origin :refs/tags/v1.0.0  # Delete from remote

✅ Good Habits

Write Good Commit Messages

Use Conventional Commits format:

type(scope): subject

body

footer

Types you'll use:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation
  • style: Formatting only
  • refactor: Code change that isn't a fix or feature
  • test: Adding tests
  • chore: Maintenance

Examples:

git commit -m "feat(auth): add password reset functionality"
git commit -m "fix(api): handle null response in user endpoint"
git commit -m "docs(readme): update installation instructions"

Branching Strategy

Keep it simple:

main          ──●────●────●────●──  (production)
               /      \         
develop    ───●────●───●──────●──  (integration)
             /    /     \    
feature-x  ─●────●       \
                  \       \
feature-y         ●────●───●

Name branches clearly:

feature/user-authentication
bugfix/login-error
hotfix/critical-security-patch
release/v1.2.0

One Commit = One Change

# ❌ Don't do this
git commit -m "Fix login, update styles, add tests, refactor utils"

# ✅ Do this instead
git commit -m "fix(auth): resolve token expiration issue"
git commit -m "style(login): update button colors to match design"
git commit -m "test(auth): add unit tests for login flow"
git commit -m "refactor(utils): extract date formatting to helper"

Always Pull First

git pull --rebase origin main
git push origin main

Use .gitignore

touch .gitignore

Common patterns:

# Dependencies
node_modules/
vendor/

# Environment
.env
.env.local

# Build output
dist/
build/
out/

# IDE stuff
.vscode/
.idea/
*.swp

# OS junk
.DS_Store
Thumbs.db

# Logs
*.log
npm-debug.log*

⚠️ Common Mistakes

Working Too Long Without Committing

I've seen people code for 8 hours straight then make one giant commit. Don't do this. Commit every time you finish something logical.

git add .
git commit -m "Implement user login validation"

Committing to the Wrong Branch

We've all done it. Here's the fix:

git reset --soft HEAD~1            # Undo the commit
git stash                          # Save the changes
git checkout -b correct-branch     # Make the right branch
git stash pop                      # Get changes back
git commit -m "Add feature"        # Commit on correct branch

Forgetting to Pull

Always start your day with:

git pull origin main
git checkout -b new-feature

Force Pushing to Shared Branches

# ❌ NEVER do this on main
git push --force origin main

# ✅ If you must force push, use this (at least it checks)
git push --force-with-lease origin feature-branch

Committing Large Files

Git doesn't handle big files well. If you've already committed one:

  1. Use BFG Repo-Cleaner to remove it from history
  2. Set up Git LFS going forward
git lfs track "*.psd"
git lfs track "*.mp4"

🎓 Quick Cheat Sheet

Setup

git config --global user.name "Name"
git config --global user.email "email"
git init
git clone [url]

Daily Workflow

git status
git add [file]
git commit -m "message"
git push
git pull

Branching

git branch [name]
git checkout [name]
git checkout -b [name]
git merge [branch]
git branch -d [name]

Looking at History

git log
git log --oneline
git diff
git show [commit]

Undoing Things

git restore [file]
git reset HEAD~1
git revert [commit]
git stash

Remotes

git remote add origin [url]
git push origin [branch]
git pull origin [branch]
git fetch

🚀 What's Next?

You've got the fundamentals. Here's how to keep leveling up:

  1. Just use it. Use Git for everything, even tiny projects
  2. Read commit history on open source projects. See how pros do it
  3. Try the advanced stuff when you're comfortable. Hooks, submodules, worktrees
  4. Pick a workflow. GitFlow, GitHub Flow, or trunk-based development
  5. Get good at rebasing. git rebase -i is powerful once you get it

Good Resources


💡 Things to Remember

  • Commit often, push reasonably
  • Read error messages. Git actually tells you what went wrong
  • Don't panic. Reflog remembers almost everything
  • Branches are free. Use them liberally
  • Pull before you push

Now go build something! 🎉


Questions? Find me on X/Twitter.