|$ curl https://forge-ai.dev/api/markdown?path=docs/git/basics
$cat docs/git-—-basics.md
updated Recently·45 min read·published

Git — Basics

GitVersion ControlBeginner
Introduction

Git is a distributed version control system that tracks changes in source code during software development. It enables multiple developers to work on the same project without interfering with each other, provides a complete history of every change, and allows branching and merging for parallel development.

Unlike centralized systems (SVN, CVS), every Git working directory is a full-fledged repository with complete history and version tracking, enabling offline work and resilient backups.

Three-Tree Architecture

Git manages content through three core areas that files move through during development. Understanding this architecture is essential to using Git effectively.

1. Working Directory

The actual files on your filesystem that you edit. Git does not automatically track changes here — you must explicitly stage them.

terminal
Bash
1# Working directory state - files are "untracked" or "modified"
2$ echo "new file" > index.html
3$ git status
4On branch main
5Untracked files:
6 index.html

2. Staging Area (Index)

A preview of your next commit. You selectively add changes from the working directory to the staging area. This lets you craft atomic commits.

terminal
Bash
1# Stage a file for commit
2$ git add index.html
3$ git status
4On branch main
5Changes to be committed:
6 new file: index.html

3. Repository (Commit History)

The committed history stored in .git. Once you commit, Git permanently stores a snapshot of the staged changes.

terminal
Bash
1# Commit the staged snapshot
2$ git commit -m "Add index.html"
3[main 1a2b3c4] Add index.html
4 1 file changed, 1 insertion(+)
5
6# The three trees after commit:
7# Working Directory = Staging = HEAD (clean state)

info

The three-tree model lets you build commits incrementally. Stage only related changes, leave unrelated modifications unstaged, and commit when you have a logical unit of work. This creates a clean, reviewable history.
Git Config

Git configuration is managed at three levels: system (all users), global (your account), and local (per repository). Each level overrides the one above it.

terminal
Bash
1# Set your identity (required for commits)
2git config --global user.name "Jane Doe"
3git config --global user.email "jane@example.com"
4
5# Set default branch name
6git config --global init.defaultBranch main
7
8# Set editor for commit messages
9git config --global core.editor "code --wait"
10
11# Enable color output
12git config --global color.ui auto
13
14# Set diff tool
15git config --global diff.tool vscode
16
17# View all config
18git config --list
19
20# View config file directly
21cat ~/.gitconfig
LevelLocationScope
--system/etc/gitconfigAll users on the machine
--global~/.gitconfigYour user account
--local.git/configCurrent repository only

best practice

Always set user.name and user.email globally before your first commit. Your email should match the one used on GitHub/GitLab for proper attribution. Use --local to override per project (e.g., for work vs. personal repos).
Initializing a Repository

There are two ways to get a Git repository: creating a new one from scratch or cloning an existing one from a remote.

terminal
Bash
1# Create a new repository from scratch
2mkdir my-project
3cd my-project
4git init
5# Output: Initialized empty Git repository in /path/my-project/.git/
6
7# Clone an existing repository
8git clone https://github.com/user/repo.git
9# Clones into ./repo directory
10
11# Clone into a custom directory name
12git clone https://github.com/user/repo.git my-custom-name
13
14# Clone a specific branch
15git clone --branch develop https://github.com/user/repo.git
16
17# Shallow clone (only recent history, faster)
18git clone --depth 1 https://github.com/user/repo.git

After git init, Git creates a hidden .git directory that contains all repository metadata:

.git-directory
Bash
1.git/
2├── HEAD # Points to current branch reference
3├── config # Repository-specific config
4├── description # Repository description (used by GitWeb)
5├── hooks/ # Scripts that run on specific events
6├── info/ # Additional repository info
7├── objects/ # All Git objects (commits, trees, blobs)
8└── refs/ # References (branches, tags)
9 ├── heads/ # Local branch pointers
10 └── tags/ # Tag pointers

warning

Never delete or manually edit files inside .git/ unless you fully understand the implications. Corrupting Git internals can result in permanent data loss. Use Git commands to interact with the repository.
Basic Workflow

The daily Git workflow follows a predictable pattern: modify files, stage changes, commit, and repeat. This section covers the essential commands.

terminal
Bash
1# 1. Check what changed
2git status
3
4# 2. See detailed diffs (unstaged)
5git diff
6
7# 3. Stage specific files
8git add index.html
9git add src/*.js
10
11# 4. Stage all changes (use with caution)
12git add -A
13
14# 5. See staged diff (what will be committed)
15git diff --staged
16
17# 6. Commit with a message
18git commit -m "Add responsive header component"
19
20# 7. Commit with a multi-line message
21git commit -m "Refactor auth module
22
23- Extract token validation into middleware
24- Add rate limiting to login endpoint
25- Update test suite for new error types"
26
27# 8. Shortcut: stage all tracked files + commit
28git commit -am "Quick fix to button styles"
29
30# 9. View commit history
31git log
32
33# 10. One-line log
34git log --oneline --graph --decorate
🔥

pro tip

Use git commit -am only for trivial changes. For meaningful work, always use git add to stage files intentionally. This prevents accidentally committing debug code, temporary files, or unrelated changes.
Understanding git status

git status is the most frequently used command. It shows the state of your working directory and staging area. Learn to read its output quickly.

terminal
Bash
1$ git status
2On branch main
3Your branch is up to date with 'origin/main'.
4
5Changes to be committed:
6 (use "git restore --staged <file>..." to unstage)
7 modified: src/app.ts
8
9Changes not staged for commit:
10 (use "git add <file>..." to update what will be committed)
11 modified: src/utils.ts
12 deleted: old-config.json
13
14Untracked files:
15 (use "git add <file>..." to include in what will be committed)
16 new-feature.tsx
17 temp.log

Each section tells you a different story:

Changes to be committed (staged)

Files in the staging area, ready for commit. Use git restore --staged to unstage if needed.

Changes not staged for commit (modified)

Tracked files that have been modified but not yet staged. Use git add to stage them.

Untracked files

New files that Git has never seen. They are not part of the repository until you git add them.

best practice

Run git status before every git add, git commit, and git push. It provides a safety check — you will see exactly what is about to change.
Viewing History with git log

git log displays the commit history. It has dozens of formatting options to help you find specific changes quickly.

terminal
Bash
1# Standard log
2git log
3
4# One line per commit (compact)
5git log --oneline
6
7# Graph view with branches
8git log --oneline --graph --all
9
10# Show diffs in log
11git log -p
12
13# Show last 3 commits
14git log -3
15
16# Filter by author
17git log --author="Jane"
18
19# Filter by date range
20git log --after="2026-01-01" --before="2026-06-30"
21
22# Search commit messages
23git log --grep="fix bug"
24
25# Search in file contents
26git log -S "functionName" -- source/
27
28# Show commits that modified a specific file
29git log -- src/app.ts
30
31# Custom format
32git log --pretty=format:"%h - %an, %ar : %s"
🔥

pro tip

Create an alias: git config --global alias.lg "log --oneline --graph --decorate --all". Then git lg gives you a beautiful ASCII graph of your entire repository history.
Inspecting Changes with git diff

git diff shows the differences between any two states in your repository. It is essential for code review before committing.

terminal
Bash
1# Unstaged changes (working dir vs staging)
2git diff
3
4# Staged changes (staging vs last commit)
5git diff --staged
6# (same as git diff --cached)
7
8# Working dir vs a specific commit
9git diff HEAD~1
10
11# Between two commits
12git diff abc123..def456
13
14# Between branches
15git diff main..feature-x
16
17# Only file names (no content)
18git diff --name-only
19
20# Summary of changes
21git diff --stat
22
23# Ignore whitespace changes
24git diff --ignore-all-space
25
26# See diff in word-level granularity
27git diff --word-diff

info

Use git diff --staged before every commit to review exactly what you are about to snapshot. This catches leftover debug statements, accidental API keys, and incomplete refactors.
.gitignore — Excluding Files

The .gitignore file tells Git which files to intentionally ignore. This keeps your repository clean of build artifacts, dependencies, environment files, and OS-specific files.

.gitignore
Bash
1# Dependencies
2node_modules/
3vendor/
4.pnp
5.pnp.js
6
7# Build outputs
8dist/
9build/
10out/
11*.tsbuildinfo
12
13# Environment files
14.env
15.env.local
16.env.production
17
18# OS files
19.DS_Store
20Thumbs.db
21
22# IDE/Editor
23.vscode/
24.idea/
25*.swp
26*.swo
27
28# Logs
29*.log
30npm-debug.log*
31
32# Runtime
33tmp/
34temp/
35*.pid
36*.seed

Global ignore patterns for your machine (e.g., .DS_Store) go into a global gitignore:

terminal
Bash
1# Set a global gitignore
2git config --global core.excludesFile ~/.gitignore_global
3
4# Good candidates for global ignore:
5.DS_Store
6Thumbs.db
7*.swp
8*.swo
9*~
PatternEffect
node_modules/Ignore directory (trailing /)
*.logIgnore all .log files
!important.logNegation — do not ignore this file
build/**/*.jsIgnore all .js in build/ and subdirs
[Tt]emp/Ignore Temp/ or temp/

warning

If a file is already tracked by Git, adding it to .gitignore will not stop Git from tracking it. You must first remove it from tracking: git rm --cached <file>. This is a common pitfall for new Git users.
Removing & Renaming Files

Git provides explicit commands for removing and renaming tracked files. These operations are also tracked in the repository history.

terminal
Bash
1# Remove from working tree + staging
2git rm old-file.js
3
4# Remove only from staging (keep on disk)
5git rm --cached config.json
6
7# Rename a file
8git mv old-name.js new-name.js
9
10# Move to different directory
11git mv src/old.js lib/new.js

info

Git automatically detects renames even without git mv. If you rename a file with mv and then git add the new path and git rm the old one, Git will show it as a rename. However, git mv is cleaner and more explicit.
Undoing Changes

Git provides multiple ways to undo changes at different levels. Understanding the difference between discarding unstaged changes, un-staging, amending commits, and reverting is critical.

terminal
Bash
1# Discard unstaged changes (restore file to last commit)
2git restore file.js
3
4# Unstage a file (keep changes in working dir)
5git restore --staged file.js
6
7# Unstage all files
8git restore --staged .
9
10# Amend last commit (fix message or add forgotten files)
11git commit --amend -m "Corrected commit message"
12
13# Add forgotten files to last commit
14git add forgotten.js
15git commit --amend --no-edit
16
17# Revert a commit (creates a new commit that undoes it)
18git revert abc123
19
20# Reset (careful! rewrite history)
21git reset --soft HEAD~1 # Move HEAD back, keep changes staged
22git reset --mixed HEAD~1 # Move HEAD back, keep changes unstaged
23git reset --hard HEAD~1 # Move HEAD back, DISCARD changes

warning

Never use git reset --hard unless you are certain you want to discard your changes permanently. There is no undo for a hard reset. If in doubt, use git stash to save changes before destructive operations.
Stashing — Temporary Shelving

git stash temporarily shelves changes so you can work on something else and come back later. It is essential when you need to switch branches mid-task.

terminal
Bash
1# Stash current changes
2git stash
3
4# Stash with a descriptive message
5git stash push -m "WIP: refactor auth middleware"
6
7# List stashes
8git stash list
9
10# Show what's in a stash
11git stash show stash@{0}
12
13# Apply last stash (keep in stash list)
14git stash apply
15
16# Apply and remove from stash list
17git stash pop
18
19# Apply a specific stash
20git stash apply stash@{2}
21
22# Create a branch from a stash
23git stash branch feature/new-branch stash@{0}
24
25# Drop a specific stash
26git stash drop stash@{1}
27
28# Clear all stashes
29git stash clear

best practice

Stashes are stored locally on your machine. They do not transfer with git push. For long-lived WIP changes, consider creating a feature branch with a partial commit instead. Use stashes for quick context switches, not permanent storage.
Git Aliases

Aliases turn long git commands into shortcuts. They significantly improve daily workflow speed.

terminal
Bash
1# Common aliases every developer should have
2git config --global alias.co checkout
3git config --global alias.br branch
4git config --global alias.st status
5git config --global alias.ci commit
6git config --global alias.df diff
7git config --global alias.lg "log --oneline --graph --decorate --all"
8git config --global alias.undo "reset --soft HEAD~1"
9git config --global alias.unstage "restore --staged ."
10git config --global alias.last "log -1 HEAD"
11git config --global alias.visual "!gitk"
12
13# Usage after aliases are set
14git st # instead of git status
15git lg # pretty log graph
16git ci -m "msg" # commit with message
17git undo # undo last commit (soft)
Common Mistakes

✗ Committing without configuring user info

git commit -m "message"

Git will use the system hostname/username, creating incorrect attribution. Always set user.name and user.email first.

✗ Committing large files

git add giant-video.mp4 && git commit -m "add video"

Git repos bloat permanently. Use .gitignore for build artifacts and Git LFS for large binary files.

✗ Adding sensitive data to a commit

git add .env && git commit -m "add config"

Secrets in Git history are hard to remove. Even after deleting the file, the secret remains in history. Use .gitignore and git-secrets to prevent this.

✗ Ignoring .gitignore after tracking

echo "node_modules" >> .gitignore

.gitignore only prevents tracking of untracked files. If node_modules is already tracked, you must run git rm --cached node_modules first.

$Blueprint — Engineering Documentation·Section ID: GIT-01·Revision: 1.0