Initializing Repositories and Making Commits
Initializing Repositories and Making Commits
Creating a Repository
# Initialize a new repo
git init
git init my-project && cd my-project
# Clone an existing repo
git clone https://github.com/user/repo.git
git clone git@github.com:user/repo.git # SSH
git clone --depth 1 https://github.com/user/repo.git # Shallow clone
The Three Areas
Git has three main areas:
- Working Directory — Your actual files
- Staging Area (Index) — Files marked for the next commit
- Repository (.git) — The committed history
Working Directory → git add → Staging Area → git commit → Repository
← git checkout ← ← git reset ←
Staging and Committing
# Check status
git status
git status -s # Short format
# Stage specific files
git add file.txt
git add src/app.js src/utils.js
# Stage all changes
git add .
git add -A # All changes including deletions
# Stage parts of a file (interactive)
git add -p file.txt # Shows hunks, you choose what to stage
# Commit with a message
git commit -m "Add user authentication module"
# Commit with detailed message
git commit -m "Add user authentication module" -m "- Implement JWT token generation
- Add login/logout endpoints
- Add password hashing with bcrypt"
# Stage and commit in one step (only for modified tracked files)
git commit -am "Fix memory leak in connection pool"
# Amend the last commit
git commit --amend -m "Updated commit message"
git commit --amend --no-edit # Keep the same message, add staged files
Writing Good Commit Messages
# Format: <type>(<scope>): <subject>
feat(auth): add JWT token validation middleware
fix(db): handle connection timeout in pool
docs(readme): add installation instructions
refactor(api): extract validation into middleware
test(auth): add unit tests for login endpoint
chore(deps): upgrade express to v4.18.2
# Subject line:
# - Use imperative mood ("add feature" not "added feature")
# - Keep under 50 characters
# - No period at the end
Inspecting the Repository
Inspecting the Repository
git log
# Full log
git log
# One line per commit
git log --oneline
# Graphical branch visualization
git log --oneline --graph --all --decorate
# Filter by author
git log --author="John"
git log --author="john@example.com"
# Filter by date
git log --since="2 weeks ago"
git log --since="2024-01-01" --until="2024-01-31"
# Filter by message
git log --grep="fix" --grep="bug" --all-match
git log --grep="login"
# Show file changes per commit
git log --stat
git log --name-only
# Show actual diffs
git log -p # Full diff
git log -p -- src/app.js # Only changes to src/app.js
# Pretty format
git log --pretty=format:"%h %s (%an, %ar)"
git log --pretty=format:"%C(yellow)%h%C(reset) %s%C(red)(%an%C(reset) %ar)"
# Limit results
git log --oneline -20 # Last 20 commits
git log --oneline --follow -- src/app.js # Follow file renames
git diff
# Unstaged changes (working directory vs staging)
git diff
# Staged changes (staging area vs last commit)
git diff --staged
git diff --cached
# Specific file
git diff -- src/app.js
# Between two commits
git diff abc1234 def5678
# Between branches
git diff main..feature-branch
# Summary only
git diff --stat
# Ignore whitespace changes
git diff -w
# Show only file names that changed
git diff --name-only
# Compare with a specific commit
git diff HEAD~3 # Changes in last 3 commits
git diff HEAD~1 # Changes in last commit only
git show and git status
# Show a specific commit
git show abc1234
git show abc1234:src/app.js # Show file at that commit
# Show file at a specific commit
git show HEAD:package.json
git show main:README.md
# Detailed status
git status -sb # Short + branch info
# Check what's untracked
git ls-files --others --exclude-standard
# Find which commit last modified a line
git blame src/app.js
git blame -L 10,20 src/app.js # Lines 10-20 only
Undoing Changes
Undoing Changes
Understanding the Options
| Command | Working Dir | Staging | Repository | Use When |
|---|---|---|---|---|
git restore |
Yes | Yes | No | Discard changes |
git reset |
Yes | Yes | Yes | Undo commits |
git revert |
No | No | Yes | Undo with new commit |
Discarding Working Directory Changes
# Discard changes to a file
git restore file.txt
# Discard all unstaged changes
git restore .
# Unstage a file (move from staging to working dir)
git restore --staged file.txt
# Unstage all
git restore --staged .
# Discard ALL changes (working + staged) — DANGEROUS
git restore --staged --worktree .
Reset (Moving HEAD)
# Soft reset: move HEAD, keep staged changes
git reset --soft HEAD~1 # Undo last commit, keep staged
# Mixed reset (default): move HEAD, unstage changes
git reset HEAD~1 # Undo last commit, keep in working dir
# Hard reset: move HEAD, discard everything — DANGEROUS
git reset --hard HEAD~1 # Complete undo
# Reset to a specific commit
git reset --hard abc1234
# Reset a specific file
git restore --source=HEAD~1 file.txt
Revert (Safe Undo)
# Create a new commit that undoes a previous commit
git revert abc1234
# Revert multiple commits
git revert abc1234 def5678
# Revert without committing (stage the changes)
git revert --no-commit abc1234
# Revert merge commit
git revert -m 1 abc1234 # -m 1 keeps parent side
Practical Examples
# I added a file but want to remove it from the commit
git restore --staged unwanted-file.txt
# I committed secrets — remove from history
git reset --soft HEAD~1
git restore --staged .env
echo '.env' >> .gitignore
git add .gitignore
git commit -m "Remove .env and add to gitignore"
# I want to go back 3 commits but keep changes
git reset --soft HEAD~3
# Accidentally committed to wrong branch
git log --oneline -1 # Note the commit hash
git checkout main
git cherry-pick abc1234 # Apply the commit here
git checkout feature-branch
git reset --hard HEAD~1 # Remove from wrong branch
Git Ignore and Configuration
Git Ignore and Configuration
.gitignore Patterns
# Create .gitignore
touch .gitignore
# Common patterns
.env
.env.local
.env.production
# Build output
dist/
build/
*.min.js
*.min.css
# Dependencies
node_modules/
venv/
__pycache__/
*.pyc
# IDE files
.vscode/
.idea/
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db
# Logs
*.log
logs/
# Specific file
/secrets.json
# Files ending in .bak
*.bak
# Negation: include a file normally ignored
!important.log
# Match directories
build/
# Match files with specific name
TODO
Global Git Configuration
# Set your identity
git config --global user.name "John Doe"
git config --global user.email "john@example.com"
# Set default branch name
git config --global init.defaultBranch main
# Set editor
git config --global core.editor "code --wait"
git config --global core.editor "vim"
# Set diff tool
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
# Enable color output
git config --global color.ui auto
# Set pull strategy
git config --global pull.rebase true
# Set push strategy
git config --global push.default current
# Useful aliases
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.unstage "restore --staged"
git config --global alias.last "log -1 HEAD"
git config --global alias.amend "commit --amend --no-edit"
# View all config
git config --list
git config --list --show-origin
# Remove a setting
git config --global --unset alias.st
Git Hooks
# Hooks live in .git/hooks/
# Common hooks:
# pre-commit - runs before commit (lint, format)
# commit-msg - validates commit message
# pre-push - runs before push (tests)
# Example pre-commit hook (.git/hooks/pre-commit)
#!/bin/bash
set -e
echo "Running linting..."
npm run lint
echo "Running tests..."
npm test -- --passWithNoTests
echo "All checks passed"
# Make it executable
chmod +x .git/hooks/pre-commit
# Use Husky for Node.js projects
npx husky init
npx husky add .husky/pre-commit "npm run lint"
Git Attributes and LFS
# .gitattributes — handle line endings, binary files
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
*.png binary
*.jpg binary
# Git LFS for large files
git lfs install
git lfs track "*.zip"
git lfs track "*.mp4"
git lfs track "bin/**"
git add .gitattributes
Working with Remotes
Working with Remotes
Remote Basics
# Add a remote
git remote add origin https://github.com/user/repo.git
git remote add upstream https://github.com/original/repo.git
# List remotes
git remote -v
# Show remote details
git remote show origin
# Rename a remote
git remote rename origin origin-old
# Remove a remote
git remote remove upstream
Fetching and Pulling
# Fetch: download remote changes (don't merge)
git fetch origin
git fetch --all # Fetch all remotes
# View fetched changes
git log origin/main..HEAD # Commits you have that remote doesn't
git log HEAD..origin/main # Commits remote has that you don't
# Pull: fetch + merge
git pull origin main
git pull --rebase origin main # Fetch + rebase
# Pull with autosquash
git pull --rebase --autostash origin main
Pushing
# Push to remote
git push origin main
# Push and set upstream
git push -u origin feature-branch
# Force push (DANGEROUS)
git push --force origin main
# Force push with lease (safer)
git push --force-with-lease origin main
# Push all branches
git push --all origin
# Push tags
git push origin --tags
git push origin v1.0.0
Fork Workflow
# 1. Fork on GitHub, then clone your fork
git clone https://github.com/YOUR-USER/repo.git
cd repo
# 2. Add upstream remote
git remote add upstream https://github.com/ORIGINAL-USER/repo.git
# 3. Create feature branch
git checkout -b feature/new-feature
# 4. Make changes, commit
git add .
git commit -m "Add new feature"
# 5. Push to your fork
git push origin feature/new-feature
# 6. Create PR on GitHub
# 7. Keep fork updated
git fetch upstream
git checkout main
git merge upstream/main
git push origin main