Git Fundamentals
Git’s Mental Model
Before diving into commands, it is essential to understand the three areas where your files live in a Git project. This mental model is the foundation for everything else.
┌──────────────────┐ git add ┌──────────────────┐ git commit ┌──────────────────┐│ │ ──────────────► │ │ ──────────────► │ ││ Working Directory│ │ Staging Area │ │ Repository ││ │ ◄────────────── │ (Index) │ │ (.git) ││ │ git restore │ │ │ │└──────────────────┘ └──────────────────┘ └──────────────────┘ Your files Files ready for Permanent snapshots on disk the next commit (commit history)- Working Directory — The actual files on your filesystem. This is where you edit, create, and delete files.
- Staging Area (Index) — A preparation zone where you assemble changes before committing. You choose exactly which changes go into the next commit.
- Repository (.git directory) — The database of all commits, branches, and metadata. Once a change is committed here, it is part of the permanent history.
This three-stage architecture gives you fine-grained control. You can modify ten files but commit only three of them, keeping the rest for a separate commit.
Interactive Git Playground
Practice Git commands interactively. Create branches, make commits, merge, and rebase — see the commit graph update in real time.
Git Graph Visualizer
git commit -m "msg" | git branch name | git checkout name | git merge name | git rebase nameSetting Up Git
Before using Git, configure your identity. This information is attached to every commit you make.
# Set your name and email (used in commit metadata)git config --global user.name "Your Name"git config --global user.email "you@example.com"
# Optional: set your preferred text editorgit config --global core.editor "code --wait"
# Optional: set default branch name to 'main'git config --global init.defaultBranch main
# Verify your configurationgit config --listEssential Git Commands
Initializing and Cloning
Create a new Git repository in the current directory.
# Initialize a new repositorymkdir my-projectcd my-projectgit initThis creates a hidden .git directory that stores all version control data. Your project files remain untouched.
Create a local copy of a remote repository, including its full history.
# Clone via HTTPSgit clone https://github.com/user/repository.git
# Clone via SSHgit clone git@github.com:user/repository.git
# Clone into a specific directorygit clone https://github.com/user/repository.git my-folderCloning automatically sets up a remote called origin pointing to the source repository.
Inspecting State
Show the current state of your working directory and staging area.
git statusExample output:
On branch mainChanges to be committed: (use "git restore --staged <file>..." to unstage) modified: src/app.js
Changes not staged for commit: (use "git add <file>..." to update what will be committed) modified: src/utils.js
Untracked files: (use "git add <file>..." to include in what will be committed) src/newfile.jsUse git status -s for a compact summary.
View the commit history.
# Full log with detailsgit log
# Compact one-line formatgit log --oneline
# Graphical branch visualizationgit log --oneline --graph --all
# Show last 5 commitsgit log -5
# Show commits by a specific authorgit log --author="Jane"
# Show commits that changed a specific filegit log -- src/app.jsExample of git log --oneline --graph --all:
* e4f5g6h (HEAD -> feature) Add search functionality* a1b2c3d Implement user login| * d7e8f9a (main) Fix homepage layout|/* 1a2b3c4 Initial commitShow differences between various states.
# Changes in working directory (unstaged)git diff
# Changes that are staged for the next commitgit diff --staged
# Differences between two branchesgit diff main..feature
# Differences for a specific filegit diff src/app.js
# Summary of changes (files and line counts)git diff --statExample output:
diff --git a/src/app.js b/src/app.jsindex 1a2b3c4..d5e6f7g 100644--- a/src/app.js+++ b/src/app.js@@ -10,7 +10,7 @@ function greet(name) {- return "Hello, " + name;+ return `Hello, ${name}!`; }Staging and Committing
Move changes from the working directory to the staging area.
# Stage a specific filegit add src/app.js
# Stage multiple specific filesgit add src/app.js src/utils.js
# Stage all changes in a directorygit add src/
# Stage all changes in the entire projectgit add .
# Stage parts of a file interactivelygit add -p src/app.jsThe staging area lets you craft commits precisely. Stage only the changes that belong together logically.
Create a snapshot of all staged changes.
# Commit with an inline messagegit commit -m "Add user authentication feature"
# Commit with a detailed message (opens editor)git commit
# Stage all tracked files and commit in one stepgit commit -am "Fix typo in README"Writing Good Commit Messages:
Short summary (50 chars or less)
More detailed explanation if needed. Wrap at 72 characters.Explain the *why* behind the change, not just the *what*.
- Bullet points are fine- Use a hyphen or asterisk for the bulletBranching and Merging
Branches are one of Git’s most powerful features. They allow you to diverge from the main line of development and work in isolation.
┌─── C4 ─── C5 (feature) /C1 ─── C2 ─── C3 (main)Manage branches.
# List all local branchesgit branch
# List all branches (local and remote)git branch -a
# Create a new branchgit branch feature-login
# Delete a branch (safe -- only if merged)git branch -d feature-login
# Rename current branchgit branch -m new-nameSwitch between branches or create and switch in one step.
# Switch to an existing branchgit checkout feature-login# or (modern syntax)git switch feature-login
# Create a new branch and switch to itgit checkout -b feature-login# or (modern syntax)git switch -c feature-loginWhen you switch branches, Git updates your working directory to match the snapshot of the target branch.
Combine the history of one branch into another.
# First, switch to the branch you want to merge INTOgit checkout main
# Merge the feature branch into maingit merge feature-loginFast-forward merge (linear history, no merge commit):
Before: C1 ─── C2 (main) ─── C3 ─── C4 (feature)After: C1 ─── C2 ─── C3 ─── C4 (main, feature)Three-way merge (diverged history, creates merge commit):
Before: ┌─── C4 ─── C5 (feature) / C1 ── C2 ─── C3 (main)
After: ┌─── C4 ─── C5 (feature) / \ C1 ── C2 ─── C3 ─── M1 (main)Reapply commits on top of another branch, creating a linear history.
# While on the feature branch, rebase onto maingit checkout feature-logingit rebase mainBefore rebase:
┌─── C4 ─── C5 (feature) /C1 ─── C2 ─── C3 (main)After rebase:
C1 ─── C2 ─── C3 (main) ─── C4' ─── C5' (feature)Handling Merge Conflicts
When Git cannot automatically merge changes, it produces a conflict. The conflicted file will contain markers showing both versions:
<<<<<<< HEADfunction greet(name) { return `Hello, ${name}!`;}=======function greet(name) { return `Hi there, ${name}!`;}>>>>>>> feature-branchSteps to resolve:
- Open the conflicted file and decide which changes to keep (or combine both).
- Remove the conflict markers (
<<<<<<<,=======,>>>>>>>). - Stage the resolved file:
git add src/app.js - Complete the merge:
git commit
Undoing Changes
Discard changes in the working directory or unstage files.
# Discard changes in a file (revert to last commit)git restore src/app.js
# Unstage a file (keep changes in working directory)git restore --staged src/app.jsMove the current branch pointer to a different commit.
# Soft reset: move HEAD, keep changes stagedgit reset --soft HEAD~1
# Mixed reset (default): move HEAD, unstage changesgit reset HEAD~1
# Hard reset: move HEAD, discard all changesgit reset --hard HEAD~1--soft: Moves HEAD only. Staging area and working directory unchanged.--mixed: Moves HEAD and resets staging area. Working directory unchanged.--hard: Moves HEAD and resets everything. All changes are lost.Temporarily save uncommitted changes so you can switch context.
# Stash current changesgit stash
# Stash with a descriptive messagegit stash push -m "work in progress: login form"
# List all stashesgit stash list
# Apply the most recent stash (keep it in the stash list)git stash apply
# Apply and remove the most recent stashgit stash pop
# Apply a specific stashgit stash apply stash@{2}
# Drop a specific stashgit stash drop stash@{0}Stashing is useful when you need to quickly switch branches but are not ready to commit your current work.
Working with Remotes
Manage connections to remote repositories.
# List remotesgit remote -v
# Add a remotegit remote add origin https://github.com/user/repo.git
# Change a remote URLgit remote set-url origin https://github.com/user/new-repo.git
# Remove a remotegit remote remove originSynchronize with remote repositories.
# Push current branch to remotegit push origin main
# Push and set upstream trackinggit push -u origin feature-login
# Fetch changes from remote (does not merge)git fetch origin
# Pull changes (fetch + merge)git pull origin main
# Pull with rebase instead of mergegit pull --rebase origin mainFetch vs. Pull:
git fetch: Downloads new data but does NOT integrate it. Safe to run at any time.
git pull: Downloads new data AND merges it into your current branch. Equivalent to git fetch + git merge.Common Workflows
Solo Developer Workflow
# 1. Make changes to files# 2. Review what changedgit statusgit diff
# 3. Stage and commitgit add .git commit -m "Implement feature X"
# 4. Push to remotegit push origin mainFeature Branch Workflow
# 1. Create a feature branch from maingit checkout -b feature-search
# 2. Work on the feature (edit, stage, commit -- repeat)git add src/search.jsgit commit -m "Add search input component"
git add src/search.js src/api.jsgit commit -m "Connect search to API"
# 3. Push the feature branch to remotegit push -u origin feature-search
# 4. Open a pull request (on GitHub/GitLab)
# 5. After approval, merge into maingit checkout maingit pull origin maingit merge feature-search
# 6. Clean upgit branch -d feature-searchgit push origin --delete feature-searchQuick Reference
| Command | Purpose |
|---|---|
git init | Initialize a new repository |
git clone <url> | Copy a remote repository locally |
git status | Show working directory state |
git add <file> | Stage changes for commit |
git commit -m "msg" | Create a commit from staged changes |
git log --oneline | View compact commit history |
git diff | Show unstaged changes |
git branch <name> | Create a new branch |
git checkout <branch> | Switch to a branch |
git merge <branch> | Merge a branch into current branch |
git rebase <branch> | Reapply commits onto another branch |
git stash | Temporarily save uncommitted changes |
git push | Upload commits to remote |
git pull | Download and merge remote changes |
git fetch | Download remote changes without merging |
git reset | Move branch pointer / unstage changes |
git restore | Discard working directory changes |
Next Steps
Now that you understand the core Git commands, explore how teams organize their branches and review each other’s code: