Lexicon
⌘K
Explore
ExploreGuidesNotes
WriteMy LibraryBooks
Sign in
Browse

Learning

  • Building a Sustainable Learning System

Networking

  • OSI Model
  • TCP vs UDP
  • TCP/IP Model

Programming

  • Start Here — How to Solve a Problem
  • From if/else to DSA — The Whole Path
  • Problem Solving
  • DSA Practice — Learn by Solving
  • C Programming
  • Python

Software Craft

  • How to Structure a Software Project
  • Debugging Software Systematically
  • Designing Clean and Maintainable User Interfaces

Tools & Workflow

  • A Practical Introduction to Git and Version Control
  • Introduction to Linux for Developers

Web & APIs

  • Understanding REST APIs

Writing

  • Writing Better Technical Documentation
New noteSuggest a guide

Lexicon

a personal knowledge base

Tools & Workflow

A Practical Introduction to Git and Version Control

Updated 2026-07-12 · 7 min read

Git feels intimidating because most people learn it as a list of magic incantations. You memorize git commit, git push, and a rescue command you found on the internet, and you hope nothing goes wrong. But Git is far less scary once you understand the small model underneath it. Almost every command becomes obvious once you can picture what it's doing.

This guide builds that mental model first, then walks through the commands you'll use every day, and finishes with how to undo things safely — because undoing mistakes calmly is what separates comfortable Git users from anxious ones.

The mental model

Git tracks snapshots of your project over time. Each snapshot is a commit — a complete picture of your files at a moment, plus a message and a pointer to the commit that came before it. Chain those pointers together and you get history.

There are three places your work lives:

  • Working directory — the actual files you edit.
  • Staging area (index) — a holding zone for changes you've marked as ready to commit.
  • Repository — the committed history, stored in the hidden .git folder.

The staging area is the part beginners skip, and it's the key to good commits. It lets you choose exactly which changes go into the next snapshot, so a single commit can be one clean idea instead of a dump of everything you touched.

edit files → git add → staging area → git commit → repository
  (working dir)          (index)                     (history)

A commit is identified by a hash like a1b2c3d. A branch is just a lightweight, movable label pointing at a commit. HEAD is a pointer to wherever you currently are. That's the whole core.

Getting started

Set your identity once, then create or clone a repository.

git config --global user.name "Your Name"
git config --global user.email "you@example.com"
 
# start a new repo in the current folder
git init
 
# or copy an existing one
git clone https://github.com/someone/project.git

Check status constantly. git status is the command you'll run more than any other — it tells you what's changed, what's staged, and what branch you're on.

git status
git status -s   # short, compact output

The everyday loop

Ninety percent of Git use is the same short cycle: change files, stage them, commit, repeat.

git add file.js          # stage one file
git add .                # stage everything changed
git commit -m "Add login form validation"

Write commit messages that explain why, not just what. A good message is a short imperative summary: "Fix off-by-one in pagination," not "changes" or "stuff." Future you, reading the log at 2am, will be grateful.

Look at history with git log:

git log --oneline --graph --decorate

That flag combination gives you a compact, visual history that shows branches — it's worth aliasing so you type it often.

Branching and merging

A branch lets you work on something without disturbing the main line. Because branches are just pointers, creating one is instant and cheap.

git switch -c feature/search   # create and switch to a new branch
# ...make commits...
git switch main                # go back to main
git merge feature/search       # bring the work in

When the branches haven't diverged, Git does a fast-forward — it just slides the label forward. When both branches have new commits, Git creates a merge commit that ties the two histories together.

If both branches changed the same lines, you get a merge conflict. Git pauses and marks the clashing region in the file:

<<<<<<< HEAD
color = "blue"
=======
color = "green"
>>>>>>> feature/search

Resolving a conflict is manual and low-drama: edit the file to the version you actually want, delete the marker lines, then stage and commit.

# edit the file to resolve
git add file.css
git commit          # completes the merge

Conflicts feel scary the first time, but they're just Git honestly telling you it can't guess your intent. You decide, and move on.

Working with a remote

A remote is a copy of the repository hosted somewhere else, usually called origin. You sync with it by pushing and pulling.

git push origin main       # send your commits up
git pull origin main       # fetch and merge others' commits down
git fetch                  # download changes WITHOUT merging them

git fetch then reviewing before you merge is safer than a blind git pull, because you see what's coming before it touches your working files.

Before pushing a shared branch, pull first so you integrate others' work and avoid a rejected push.

Undoing things without panic

This is the section people wish they'd read first. The right undo depends on where the change is.

Unstage a file (keep the edits, just remove it from staging):

git restore --staged file.js

Discard uncommitted changes in a file (this throws work away — be sure):

git restore file.js

Fix the last commit message or add a forgotten file to it:

git commit --amend -m "Better message"

Undo a commit but keep the changes as uncommitted edits:

git reset --soft HEAD~1

Undo a commit and its changes entirely (destructive to those changes):

git reset --hard HEAD~1

The safest option for shared history is git revert, which makes a new commit that reverses an old one — nothing is rewritten, so it's safe on branches other people use:

git revert a1b2c3d

Rule of thumb: rewrite history (reset, amend, rebase) only on commits you haven't shared. Once others have your commits, prefer revert.

And the ultimate safety net — git reflog records where HEAD has been, so you can recover commits that seem lost:

git reflog
git reset --hard HEAD@{2}   # jump back to a previous state

A sane everyday workflow

You don't need a heavyweight process for personal or small-team work. This is enough:

  1. Pull the latest main.
  2. Create a branch for the task: git switch -c fix/typo-in-header.
  3. Make small, focused commits as you go.
  4. Push the branch and open a pull request for review.
  5. Merge when it's approved and green, then delete the branch.

Keep branches short-lived. The longer a branch lives, the more it drifts from main and the uglier the eventual merge. A .gitignore file keeps junk — build output, secrets, node_modules — out of history from the start:

node_modules/
.env
dist/
*.log

If you're on Linux or macOS, many of these commands feel natural alongside shell basics — see Linux for developers.

Common mistakes

  • Committing everything at once. Use the staging area to make each commit one coherent idea.
  • Vague commit messages. "fix" and "wip" tell future you nothing. Explain the why.
  • Committing secrets. Once a password or key is in history, treat it as leaked. Add a .gitignore before your first commit.
  • git reset --hard on shared branches. You'll rewrite history others depend on. Use revert instead.
  • Fear of branches. They're cheap and disposable. Make them freely.
  • Blind git pull into a dirty working directory. Stash or commit first so a merge doesn't tangle with your uncommitted edits.
  • Letting a branch live for weeks. Merge conflicts grow with time apart. Integrate often.

Checklist

  • Can I explain the difference between working directory, staging area, and repository?
  • Do my commit messages say why, in the imperative mood?
  • Am I working on a branch, not directly on main?
  • Do I have a .gitignore before the first commit?
  • Do I know how to unstage, discard, and revert — and which is safe to share?
  • Do I pull (or fetch) before I push a shared branch?
  • Do I know git reflog exists as my safety net?

Keep learning

The fastest way to get comfortable is to make a throwaway repo and deliberately break it: create conflicts, reset commits, recover them with reflog. Nothing is at stake, so you can be fearless.

Concrete next steps:

  • Learn interactive rebase to clean up messy local history before sharing (git rebase -i).
  • Set up a couple of aliases for the commands you type most.
  • Read structuring a software project so your repos are organized before they grow.
  • Pair Git with a real workflow habit — small branches, frequent integration — from building a sustainable learning system, applied to how you ship, not just how you study.
← PreviousDesigning Clean and Maintainable User InterfacesNext →Introduction to Linux for Developers
Reading progress0%

Curated guide

Part of the Lexicon knowledge base — hand-written and kept up to date.

Browse all guides →