Git Complete Cheat Sheet
Master Version Control – Commands, Workflows & Best Practices
Git is a distributed version control system created by Linus Torvalds in 2005. It’s the most widely used modern version control system in the world, powering millions of projects from small personal repositories to massive enterprise applications. Git tracks changes in source code during software development, enabling multiple developers to work together on non-linear development.
Unlike centralized version control systems, Git gives every developer a complete copy of the project history, making most operations extremely fast and allowing work to continue even when offline. This distributed nature makes Git incredibly powerful for collaboration, branching, and merging workflows.
Fast & Efficient
Lightning-fast operations with local repository access
Distributed
Every clone is a full backup of all data
Data Integrity
Cryptographic hashing ensures data authenticity
Installing Git
- Download Git from git-scm.com
- Run the installer and follow the setup wizard
- Select “Git Bash Here” and “Git GUI Here” context menu options
- Choose default editor (VS Code, Vim, Notepad++, etc.)
- Select “Use Git from the command line and also from 3rd-party software”
- Verify installation:
git --version
# Output: git version 2.43.0.windows.1
Using Homebrew (Recommended):
# Install Homebrew first if not installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install Git
brew install git
# Verify installation
git --version
Alternative: Xcode Command Line Tools
xcode-select --install
Debian/Ubuntu:
sudo apt update
sudo apt install git
Fedora/RHEL/CentOS:
sudo dnf install git
# or for older versions
sudo yum install git
Arch Linux:
sudo pacman -S git
Initial Configuration
After installation, configure your identity. This information is used in every commit:
# Set your name
git config --global user.name "Your Name"
# Set your email
git config --global user.email "your.email@example.com"
# Set default branch name to 'main'
git config --global init.defaultBranch main
# Set default editor
git config --global core.editor "code --wait" # VS Code
# git config --global core.editor "vim" # Vim
# git config --global core.editor "nano" # Nano
# Enable colored output
git config --global color.ui auto
# View all configurations
git config --list
# View specific configuration
git config user.name
The Three States
Git has three main states that your files can be in:
Modified
You have changed the file but haven’t committed it yet to your database.
Staged
You have marked a modified file to go into your next commit snapshot.
Committed
The data is safely stored in your local database (repository).
The Three Areas
| Area | Description | Purpose |
|---|---|---|
| Working Directory | A single checkout of one version of the project | Where you modify files |
| Staging Area (Index) | A file storing information about what will go into your next commit | Prepare commits selectively |
| Git Directory (Repository) | Where Git stores metadata and object database | Store project history |
Key Terminology
Basic Workflow
# 1. Initialize a new repository
git init
# 2. Check status of your files
git status
# 3. Add files to staging area
git add filename.txt
git add . # Add all files
# 4. Commit staged changes
git commit -m "Descriptive commit message"
# 5. View commit history
git log
# 6. Connect to remote repository
git remote add origin https://github.com/username/repo.git
# 7. Push changes to remote
git push -u origin main
Repository Creation & Cloning
# Initialize a new Git repository
git init
git init project-name # Creates directory and initializes
# Clone an existing repository
git clone https://github.com/username/repository.git
git clone https://github.com/username/repository.git new-folder-name
# Clone a specific branch
git clone -b branch-name https://github.com/username/repository.git
# Clone with depth (shallow clone - faster for large repos)
git clone --depth 1 https://github.com/username/repository.git
File Status & Changes
# Check status of working directory
git status
git status -s # Short format
git status -b # Show branch info
# View differences
git diff # Unstaged changes
git diff --staged # Staged changes
git diff HEAD # All changes since last commit
git diff branch1..branch2 # Compare branches
git diff commit1 commit2 # Compare commits
# View file at specific commit
git show commit-hash:path/to/file
Adding & Committing
# Add files to staging area
git add filename.txt # Add specific file
git add . # Add all files in current directory
git add *.js # Add all JavaScript files
git add -A # Add all changes (new, modified, deleted)
git add -u # Add only modified and deleted files (not new)
git add -p # Interactive staging (patch mode)
# Remove files from staging area
git reset HEAD filename.txt # Unstage specific file
git reset HEAD . # Unstage all files
# Commit changes
git commit -m "Commit message" # Basic commit
git commit -am "Message" # Add and commit tracked files
git commit --amend -m "New message" # Modify last commit
git commit --amend --no-edit # Amend without changing message
git commit -m "Title" -m "Description" # Multi-line commit
# Empty commit (useful for triggering CI/CD)
git commit --allow-empty -m "Empty commit"
- Use imperative mood: “Add feature” not “Added feature”
- Keep first line under 50 characters
- Separate subject from body with blank line
- Explain what and why, not how
- Reference issue numbers when applicable
Viewing History
# View commit history
git log # Full log
git log --oneline # Condensed view
git log --graph --oneline --all # Visual branch graph
git log -n 5 # Last 5 commits
git log --since="2 weeks ago" # Time-based
git log --author="John Doe" # By author
git log --grep="bug fix" # Search commit messages
git log -- filename.txt # History of specific file
git log -p # Show patches (changes)
git log --stat # Show statistics
# Beautiful log format
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
# Show commits unique to branch
git log main..feature-branch
# Show who changed what
git blame filename.txt
git blame -L 10,20 filename.txt # Specific lines
Undoing Changes
# Discard changes in working directory
git checkout -- filename.txt # Restore single file
git checkout -- . # Restore all files
git restore filename.txt # Newer syntax (Git 2.23+)
git restore . # Restore all
# Unstage files
git reset HEAD filename.txt # Remove from staging
git restore --staged filename.txt # Newer syntax
# Undo commits
git reset --soft HEAD~1 # Undo last commit, keep changes staged
git reset --mixed HEAD~1 # Undo last commit, unstage changes
git reset --hard HEAD~1 # Undo last commit, discard changes
git reset --hard commit-hash # Reset to specific commit
# Revert a commit (creates new commit)
git revert commit-hash # Safe for public branches
git revert HEAD # Revert last commit
git revert HEAD~3..HEAD # Revert range of commits
File Management
# Remove files
git rm filename.txt # Delete and stage removal
git rm --cached filename.txt # Remove from Git, keep locally
git rm -r directory/ # Remove directory recursively
# Move/Rename files
git mv old-name.txt new-name.txt # Rename file
git mv file.txt directory/ # Move file
# Ignore files (.gitignore)
# Create .gitignore file with patterns:
*.log # Ignore all .log files
node_modules/ # Ignore directory
!important.log # Exception (don't ignore)
build/**/*.js # Nested patterns
# Ignore already tracked files
git rm --cached filename.txt
# Then add to .gitignore
Understanding Branches
Branches are one of Git’s most powerful features. They allow you to diverge from the main line of development and work independently without affecting the main codebase. Branches are lightweight pointers to commits, making them fast to create and switch between.
Branch Operations
# List branches
git branch # Local branches
git branch -r # Remote branches
git branch -a # All branches
git branch -v # Show last commit on each branch
git branch --merged # Branches merged into current
git branch --no-merged # Branches not merged
# Create branches
git branch feature-name # Create branch
git checkout -b feature-name # Create and switch
git switch -c feature-name # Newer syntax (Git 2.23+)
# Create branch from specific commit
git branch branch-name commit-hash
# Switch branches
git checkout branch-name # Classic syntax
git switch branch-name # Newer syntax
git checkout - # Switch to previous branch
# Rename branches
git branch -m old-name new-name # Rename any branch
git branch -m new-name # Rename current branch
# Delete branches
git branch -d branch-name # Delete (safe - checks if merged)
git branch -D branch-name # Force delete
git push origin --delete branch-name # Delete remote branch
Merging Strategies
# Basic merge
git checkout main
git merge feature-branch # Merge feature into main
# Merge with no fast-forward (creates merge commit)
git merge --no-ff feature-branch
# Fast-forward merge only
git merge --ff-only feature-branch
# Squash merge (combine all commits into one)
git merge --squash feature-branch
git commit -m "Squashed feature commits"
# Abort merge during conflict
git merge --abort
# Continue merge after resolving conflicts
git merge --continue
Handling Merge Conflicts
Merge conflicts occur when Git can’t automatically resolve differences between branches. Here’s how to handle them:
# When conflict occurs, check status
git status
# View conflicted files
git diff --name-only --diff-filter=U
# Conflict markers in file:
# <<<<<<< HEAD
# Current branch content
# =======
# Incoming branch content
# >>>>>>> feature-branch
# After manually resolving conflicts:
git add resolved-file.txt
git commit -m "Resolve merge conflicts"
# Use merge tools
git mergetool # Launch configured merge tool
# Choose a version
git checkout --ours filename.txt # Keep current branch version
git checkout --theirs filename.txt # Take incoming branch version
# View conflict resolution log
git log --merge --left-right
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
Cherry-Pick
Apply specific commits from one branch to another:
# Cherry-pick single commit
git cherry-pick commit-hash
# Cherry-pick multiple commits
git cherry-pick commit1 commit2 commit3
# Cherry-pick range of commits
git cherry-pick commit1^..commit2
# Cherry-pick without committing
git cherry-pick -n commit-hash
# Continue after resolving conflicts
git cherry-pick --continue
# Abort cherry-pick
git cherry-pick --abort
Popular Branching Models
Git Flow is a branching model that uses multiple long-lived branches and specific naming conventions:
-
main/master: Production-ready code
-
develop: Integration branch for features
-
feature/*: New features (branch from develop)
-
release/*: Release preparation (branch from develop)
-
hotfix/*: Emergency fixes (branch from main)
# Feature workflow
git checkout develop
git checkout -b feature/user-authentication
# ... work on feature ...
git checkout develop
git merge --no-ff feature/user-authentication
git branch -d feature/user-authentication
# Release workflow
git checkout -b release/1.0.0 develop
# ... bug fixes, version bump ...
git checkout main
git merge --no-ff release/1.0.0
git tag -a v1.0.0
git checkout develop
git merge --no-ff release/1.0.0
git branch -d release/1.0.0
# Hotfix workflow
git checkout -b hotfix/critical-bug main
# ... fix bug ...
git checkout main
git merge --no-ff hotfix/critical-bug
git tag -a v1.0.1
git checkout develop
git merge --no-ff hotfix/critical-bug
git branch -d hotfix/critical-bug
A simpler alternative to Git Flow, ideal for continuous deployment:
-
Single main branch (usually ‘main’)
-
Feature branches created from main
-
Pull requests for code review
-
Merge to main and deploy immediately
# GitHub Flow workflow
git checkout main
git pull origin main
git checkout -b feature/add-payment-method
# ... work on feature ...
git push -u origin feature/add-payment-method
# Create Pull Request on GitHub
# After approval and CI passes:
# Merge via GitHub interface
git checkout main
git pull origin main
git branch -d feature/add-payment-method
Combines Git Flow and GitHub Flow with environment branches:
-
main: Latest deployed to production
-
pre-production: Staging environment
-
production: Production environment (optional)
Features are merged into main, then promoted through environments.
Developers work in short-lived branches or directly on trunk/main:
-
Very short-lived feature branches (hours or days)
-
Frequent integration to main
-
Feature flags for incomplete features
-
Strong CI/CD pipeline required
# Trunk-based workflow
git checkout main
git pull
git checkout -b quick-feature
# ... make small changes ...
git push -u origin quick-feature
# Quick review and merge
git checkout main
git pull
git branch -d quick-feature
- Git Flow: Large projects with scheduled releases
- GitHub Flow: Continuous deployment, web applications
- GitLab Flow: Multiple deployment environments
- Trunk-Based: Mature teams, strong CI/CD, rapid deployment
Rebase
Rebasing is an alternative to merging that rewrites commit history by moving commits to a new base. It creates a linear history but should be used carefully on shared branches.
# Basic rebase
git checkout feature-branch
git rebase main # Rebase feature onto main
# Interactive rebase (rewrite history)
git rebase -i HEAD~5 # Last 5 commits
git rebase -i commit-hash # From specific commit
# Interactive rebase commands:
# pick = use commit
# reword = use commit, but edit message
# edit = use commit, but stop for amending
# squash = combine with previous commit
# fixup = like squash, but discard commit message
# drop = remove commit
# Continue rebase after resolving conflicts
git rebase --continue
# Skip problematic commit
git rebase --skip
# Abort rebase
git rebase --abort
# Rebase onto different branch
git rebase --onto new-base old-base feature-branch
Rebase vs Merge
| Aspect | Merge | Rebase |
|---|---|---|
| History | Preserves complete history | Creates linear history |
| Commits | Creates merge commit | Rewrites commit history |
| Safety | Non-destructive | Can lose commits if misused |
| Use Case | Public branches, collaboration | Local cleanup, feature branches |
| Traceability | Shows when branches merged | Loses merge context |
Squashing Commits
# Squash last 3 commits into one
git rebase -i HEAD~3
# In editor, change 'pick' to 'squash' for commits to combine
# Alternative: reset and recommit
git reset --soft HEAD~3
git commit -m "Combined commit message"
# Squash during merge
git merge --squash feature-branch
git commit -m "Feature: Add user authentication"
# Squash all commits from branch
git checkout main
git merge --squash feature-branch
git commit
Bisect (Binary Search for Bugs)
Use bisect to find which commit introduced a bug:
# Start bisect
git bisect start
git bisect bad # Current commit is bad
git bisect good v1.0 # Known good commit
# Git checks out middle commit, you test:
git bisect good # If current commit is good
git bisect bad # If current commit is bad
# Repeat until bug is found
# Git will tell you the first bad commit
# Reset after bisect
git bisect reset
# Automated bisect with script
git bisect start HEAD v1.0
git bisect run npm test # Run tests automatically
Submodules
Include external Git repositories as subdirectories:
# Add submodule
git submodule add https://github.com/user/repo.git path/to/submodule
# Clone repository with submodules
git clone --recursive https://github.com/user/repo.git
# Initialize submodules in existing clone
git submodule init
git submodule update
# Update submodules
git submodule update --remote
# Update all submodules
git submodule foreach git pull origin main
# Remove submodule
git submodule deinit path/to/submodule
git rm path/to/submodule
rm -rf .git/modules/path/to/submodule
Git Tags
# Lightweight tags
git tag v1.0.0
git tag v1.0.0 commit-hash
# Annotated tags (recommended)
git tag -a v1.0.0 -m "Release version 1.0.0"
git tag -a v1.0.0 commit-hash -m "Tag message"
# List tags
git tag
git tag -l "v1.*" # Pattern matching
# Show tag information
git show v1.0.0
# Push tags to remote
git push origin v1.0.0 # Single tag
git push origin --tags # All tags
# Delete tags
git tag -d v1.0.0 # Local
git push origin --delete v1.0.0 # Remote
# Checkout tag
git checkout v1.0.0 # Detached HEAD state
git checkout -b branch-name v1.0.0 # Create branch from tag
Git Stash
Stash allows you to temporarily save uncommitted changes and revert to a clean working directory. Perfect for switching contexts quickly.
# Stash changes
git stash # Stash modified tracked files
git stash save "Work in progress" # Stash with message
git stash -u # Include untracked files
git stash -a # Include ignored files too
# List stashes
git stash list
# Output:
# stash@{0}: On main: Work in progress
# stash@{1}: WIP on feature: 1234567 Fix bug
# View stash contents
git stash show # Summary of latest stash
git stash show -p # Full diff
git stash show stash@{1} # Specific stash
# Apply stashes
git stash apply # Apply latest, keep in stash
git stash apply stash@{1} # Apply specific stash
git stash pop # Apply and remove from stash
git stash pop stash@{1} # Pop specific stash
# Create branch from stash
git stash branch new-branch-name
# Remove stashes
git stash drop stash@{1} # Remove specific
git stash clear # Remove all stashes
# Stash specific files
git stash push -m "Message" file1.txt file2.txt
# Stash interactively
git stash -p # Choose hunks to stash
git stash
git checkout other-branch
# ... do work ...
git checkout original-branch
git stash pop
Git Reflog
Reflog records all changes to HEAD, allowing you to recover lost commits, reset branches, and undo mistakes. It’s your safety net!
# View reflog
git reflog
git reflog show # Same as above
git reflog show branch-name # Reflog for specific branch
# Output format:
# a1b2c3d HEAD@{0}: commit: Add feature
# e4f5g6h HEAD@{1}: checkout: moving from main to feature
# i7j8k9l HEAD@{2}: commit: Fix bug
# Recover lost commits
git reflog
git checkout HEAD@{2} # Go to specific state
git cherry-pick a1b2c3d # Recover specific commit
# Undo reset
git reset --hard HEAD@{1} # Go back one step
# Restore deleted branch
git reflog
git checkout -b recovered-branch HEAD@{5}
# Find when file was deleted
git log --all --full-history -- path/to/file
git reflog -- path/to/file
# Reflog for all references
git reflog show --all
# Expire reflog entries
git reflog expire --expire=30.days.ago --all
# Clean up old reflog entries
git reflog delete HEAD@{5}
Recovery Scenarios
# You accidentally did:
git reset --hard HEAD~3
# To recover:
git reflog
# Find the commit before reset (e.g., HEAD@{1})
git reset --hard HEAD@{1}
# Or use the commit hash
git reset --hard a1b2c3d
# You accidentally deleted a branch:
git branch -D feature-branch
# To recover:
git reflog
# Find the last commit on that branch
# Look for: "checkout: moving from feature-branch to main"
git checkout -b feature-branch HEAD@{X}
# Or
git branch feature-branch commit-hash
# Find lost commits
git fsck --lost-found
git reflog --all
# View dangling commits
git show commit-hash
# Recover specific commit
git cherry-pick commit-hash
# Or create branch from it
git branch recovered commit-hash
Working with Remotes
Remote repositories are versions of your project hosted on the internet or network. They enable collaboration and backup.
# View remotes
git remote # List remote names
git remote -v # Show URLs
git remote show origin # Detailed info
# Add remote
git remote add origin https://github.com/user/repo.git
git remote add upstream https://github.com/original/repo.git
# Change remote URL
git remote set-url origin https://github.com/user/new-repo.git
# Rename remote
git remote rename origin destination
# Remove remote
git remote remove origin
# Prune deleted remote branches
git remote prune origin
git fetch --prune
Fetching & Pulling
# Fetch (download without merging)
git fetch # Fetch all remotes
git fetch origin # Fetch specific remote
git fetch origin branch-name # Fetch specific branch
git fetch --all # Fetch all remotes
git fetch --prune # Remove deleted remote branches
# Pull (fetch + merge)
git pull # Pull current branch
git pull origin main # Pull specific branch
git pull --rebase # Pull and rebase instead of merge
git pull --no-commit # Fetch and merge without committing
git pull --all # Pull all branches
# Pull with specific strategy
git pull --ff-only # Fast-forward only
git pull --no-ff # Always create merge commit
# Set upstream branch
git branch --set-upstream-to=origin/main main
# Or shorter:
git branch -u origin/main
Pushing
# Basic push
git push # Push current branch
git push origin main # Push to specific branch
git push -u origin feature-branch # Set upstream and push
# Push all branches
git push --all origin
# Push tags
git push origin v1.0.0 # Specific tag
git push --tags # All tags
git push --follow-tags # Push tags with commits
# Force push (dangerous!)
git push --force # Overwrite remote
git push --force-with-lease # Safer force push
# Delete remote branch
git push origin --delete branch-name
git push origin :branch-name # Alternative syntax
# Push to multiple remotes
git remote set-url --add --push origin https://github.com/user/repo1.git
git remote set-url --add --push origin https://github.com/user/repo2.git
git push origin main # Pushes to both
Tracking Branches
# Create tracking branch
git checkout -b feature origin/feature
git checkout --track origin/feature # Automatically names branch
# Set upstream for existing branch
git branch -u origin/main
# View tracking branches
git branch -vv
# Push and set upstream
git push -u origin feature-branch
# Unset upstream
git branch --unset-upstream
Working with Forks
# Clone your fork
git clone https://github.com/your-username/repo.git
cd repo
# Add upstream remote (original repository)
git remote add upstream https://github.com/original-owner/repo.git
# Verify remotes
git remote -v
# origin https://github.com/your-username/repo.git (fetch)
# origin https://github.com/your-username/repo.git (push)
# upstream https://github.com/original-owner/repo.git (fetch)
# upstream https://github.com/original-owner/repo.git (push)
# Sync with upstream
git fetch upstream
git checkout main
git merge upstream/main
# Or rebase:
git rebase upstream/main
# Push updates to your fork
git push origin main
# Create feature branch for contribution
git checkout -b feature/new-feature
# ... make changes ...
git push -u origin feature/new-feature
# Create Pull Request on GitHub/GitLab
SSH vs HTTPS
| Aspect | HTTPS | SSH |
|---|---|---|
| URL Format | https://github.com/user/repo.git | git@github.com:user/repo.git |
| Authentication | Username + Personal Access Token | SSH Key |
| Setup | Easier (no key generation) | Requires SSH key setup |
| Firewall | Works through most firewalls | May be blocked (port 22) |
| Security | Secure with token | More secure, no passwords |
# Switch from HTTPS to SSH
git remote set-url origin git@github.com:username/repo.git
# Switch from SSH to HTTPS
git remote set-url origin https://github.com/username/repo.git
# Generate SSH key
ssh-keygen -t ed25519 -C "your_email@example.com"
# Add to ssh-agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# Copy public key and add to GitHub/GitLab
cat ~/.ssh/id_ed25519.pub
Pull Request Workflow
Pull Requests (GitHub) or Merge Requests (GitLab) are the primary way to propose and review changes:
# 1. Create feature branch
git checkout -b feature/add-user-profile
# 2. Make changes and commit
git add .
git commit -m "Add user profile page with avatar upload"
# 3. Push to remote
git push -u origin feature/add-user-profile
# 4. Create Pull Request on GitHub/GitLab
# Via web interface or CLI:
gh pr create --title "Add user profile page" --body "Description"
# 5. Address review feedback
# Make changes based on reviews
git add .
git commit -m "Address review feedback: improve validation"
git push
# 6. After approval, merge (via web interface)
# Or from command line:
git checkout main
git merge --no-ff feature/add-user-profile
git push origin main
# 7. Clean up
git branch -d feature/add-user-profile
git push origin --delete feature/add-user-profile
Code Review Best Practices
For Authors
- Keep PRs small and focused
- Write clear descriptions
- Add tests for new features
- Self-review before requesting
- Respond to feedback promptly
For Reviewers
- Be constructive and kind
- Focus on important issues
- Explain your reasoning
- Approve if good enough
- Test the changes locally
Reviewing Pull Requests
# Fetch PR locally for testing
git fetch origin pull/123/head:pr-123
git checkout pr-123
# Or add PR refs to config
git config --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*"
git fetch origin
git checkout origin/pr/123
# Test the changes
npm test # or your test command
# View changes
git diff main...pr-123
# Check out PR with GitHub CLI
gh pr checkout 123
# Leave review comments
gh pr review 123 --comment -b "Looks good!"
gh pr review 123 --approve
gh pr review 123 --request-changes -b "Please fix X"
Resolving Conflicts in PRs
# Method 1: Merge main into feature branch
git checkout feature-branch
git fetch origin
git merge origin/main
# Resolve conflicts
git add .
git commit
git push
# Method 2: Rebase on main (cleaner history)
git checkout feature-branch
git fetch origin
git rebase origin/main
# Resolve conflicts
git add .
git rebase --continue
git push --force-with-lease
# Update branch from web interface (GitHub/GitLab)
# Click "Update branch" button on PR page
Pair Programming with Git
# Co-authored commits
git commit -m "Implement feature X
Co-authored-by: Jane Doe
Co-authored-by: John Smith "
# Share work in progress
git add .
git commit -m "WIP: Feature in progress"
git push origin feature-branch
# Continue work on different machine
git pull origin feature-branch
# Make changes
git commit --amend # Amend WIP commit
git push --force-with-lease
What are Git Hooks?
Git hooks are scripts that run automatically at certain points in the Git workflow. They’re stored in the .git/hooks directory and can enforce policies, run tests, or automate tasks.
Client-Side Hooks
| Hook | When It Runs | Common Uses |
|---|---|---|
| pre-commit | Before commit is created | Linting, formatting, tests |
| prepare-commit-msg | Before commit message editor | Auto-generate commit messages |
| commit-msg | After commit message entered | Validate commit message format |
| post-commit | After commit is created | Notifications, logging |
| pre-push | Before pushing to remote | Run full test suite |
| pre-rebase | Before rebasing | Prevent rebasing published commits |
Creating a Pre-Commit Hook
# Create pre-commit hook
# File: .git/hooks/pre-commit
#!/bin/bash
# Run linter
echo "Running ESLint..."
npm run lint
if [ $? -ne 0 ]; then
echo "❌ Linting failed. Please fix errors before committing."
exit 1
fi
# Run tests
echo "Running tests..."
npm test
if [ $? -ne 0 ]; then
echo "❌ Tests failed. Please fix before committing."
exit 1
fi
echo "✅ All checks passed!"
exit 0
# Make hook executable
chmod +x .git/hooks/pre-commit
# Skip hooks temporarily
git commit --no-verify -m "Emergency fix"
git commit -n -m "Skip hooks"
Commit Message Hook
# File: .git/hooks/commit-msg
#!/bin/bash
commit_msg_file=$1
commit_msg=$(cat "$commit_msg_file")
# Check message format: TYPE: message
pattern="^(feat|fix|docs|style|refactor|test|chore): .+"
if ! echo "$commit_msg" | grep -qE "$pattern"; then
echo "❌ Invalid commit message format!"
echo "Format: TYPE: message"
echo "Types: feat, fix, docs, style, refactor, test, chore"
echo "Example: feat: Add user authentication"
exit 1
fi
# Check message length
if [ ${#commit_msg} -lt 10 ]; then
echo "❌ Commit message too short (minimum 10 characters)"
exit 1
fi
echo "✅ Commit message validated"
exit 0
Using Husky (Recommended)
Husky makes Git hooks easy to share across teams:
# Install Husky
npm install --save-dev husky
npx husky install
# Add to package.json
npm set-script prepare "husky install"
# Create pre-commit hook
npx husky add .husky/pre-commit "npm test"
npx husky add .husky/pre-commit "npm run lint"
# Create commit-msg hook
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
# Install commitlint
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Create commitlint.config.js
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
Server-Side Hooks
| Hook | When It Runs | Common Uses |
|---|---|---|
| pre-receive | Before accepting push | Enforce policies, run CI/CD |
| update | Once per branch being pushed | Branch-specific policies |
| post-receive | After push is accepted | Deploy, notifications, backups |
GPG Commit Signing
Signing commits with GPG proves that commits actually came from you. GitHub and GitLab show a “Verified” badge for signed commits.
# Generate GPG key
gpg --full-generate-key
# Choose: RSA and RSA, 4096 bits, no expiration
# List GPG keys
gpg --list-secret-keys --keyid-format=long
# Output:
# sec rsa4096/3AA5C34371567BD2 2024-01-15 [SC]
# The key ID is: 3AA5C34371567BD2
# Export public key
gpg --armor --export 3AA5C34371567BD2
# Copy output and add to GitHub/GitLab
# Configure Git to use GPG
git config --global user.signingkey 3AA5C34371567BD2
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# Sign individual commit
git commit -S -m "Signed commit"
# Sign tags
git tag -s v1.0.0 -m "Signed tag"
# Verify signatures
git log --show-signature
git verify-commit HEAD
git verify-tag v1.0.0
SSH Commit Signing (Newer Method)
# Use existing SSH key or generate new one
ssh-keygen -t ed25519 -C "your_email@example.com"
# Configure Git to use SSH signing
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
# Add allowed signers file
git config --global gpg.ssh.allowedSignersFile ~/.config/git/allowed_signers
# Create allowed signers file
echo "your_email@example.com $(cat ~/.ssh/id_ed25519.pub)" > ~/.config/git/allowed_signers
# Sign commit
git commit -S -m "SSH signed commit"
Security Best Practices
Protect Sensitive Data
- Never commit passwords or API keys
- Use .gitignore for secrets
- Use environment variables
- Scan for secrets with tools
- Use git-crypt for encryption
Account Security
- Enable 2FA on GitHub/GitLab
- Use SSH keys instead of passwords
- Use Personal Access Tokens
- Sign commits with GPG/SSH
- Regularly audit access
Removing Sensitive Data from History
# Using BFG Repo-Cleaner (Recommended - Faster)
# Download from: https://rtyley.github.io/bfg-repo-cleaner/
# Remove passwords/secrets from all history
bfg --replace-text passwords.txt repo.git
# Remove large files
bfg --strip-blobs-bigger-than 50M repo.git
# Delete specific files
bfg --delete-files id_rsa repo.git
# Clean up
cd repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# Force push (careful!)
git push --force
# Using git filter-branch (Manual method)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch path/to/secret-file" \
--prune-empty --tag-name-filter cat -- --all
# Alternative: git filter-repo (Modern tool)
pip install git-filter-repo
# Remove file from history
git filter-repo --path path/to/secret-file --invert-paths
# Remove all files matching pattern
git filter-repo --path-glob '*.key' --invert-paths
Git Security Tools
# git-secrets (Prevent committing secrets)
git clone https://github.com/awslabs/git-secrets
cd git-secrets
make install
# Install hooks in repository
git secrets --install
git secrets --register-aws
# Scan repository
git secrets --scan
git secrets --scan-history
# gitleaks (Find secrets in repo)
# Install: https://github.com/gitleaks/gitleaks
gitleaks detect --source . --verbose
gitleaks protect --staged
# TruffleHog (Find secrets in history)
pip install truffleHog
trufflehog --regex --entropy=True https://github.com/user/repo.git
# Pre-commit hook with multiple tools
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
Credential Management
# Configure credential helper (Linux)
git config --global credential.helper cache
git config --global credential.helper 'cache --timeout=3600'
# macOS (Keychain)
git config --global credential.helper osxkeychain
# Windows (Windows Credential Manager)
git config --global credential.helper wincred
# Or with Git Credential Manager
git config --global credential.helper manager
# Store credentials (NOT RECOMMENDED for production)
git config --global credential.helper store
# Use Personal Access Token (GitHub)
# Generate: GitHub Settings → Developer Settings → Personal Access Tokens
# Use token as password when prompted
# SSH Key for authentication (Recommended)
ssh-keygen -t ed25519 -C "your_email@example.com"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# Add public key to GitHub/GitLab
# Test SSH connection
ssh -T git@github.com
Commit Best Practices
Commit Message Convention
# Conventional Commits Format
type(scope): subject
body (optional)
footer (optional)
# Types:
feat: New feature
fix: Bug fix
docs: Documentation changes
style: Code style (formatting, semicolons, etc.)
refactor: Code refactoring (no feature/fix)
perf: Performance improvements
test: Adding or updating tests
chore: Maintenance tasks, dependencies
ci: CI/CD changes
build: Build system changes
# Examples:
feat(auth): add OAuth2 authentication
fix(api): resolve race condition in user creation
Closes #123
docs: update installation guide for Windows
refactor(database): optimize query performance
test(auth): add unit tests for login flow
chore(deps): update dependencies to latest versions
BREAKING CHANGE: authentication now requires OAuth2
Branching Best Practices
Repository Best Practices
Repository Structure
- Include comprehensive README.md
- Add LICENSE file
- Create CONTRIBUTING.md
- Use .gitignore templates
- Document in CODE_OF_CONDUCT.md
Configuration
- Set up CI/CD pipelines
- Configure branch protection
- Enable required reviews
- Use issue templates
- Set up automated testing
Performance Best Practices
# Keep repository size manageable
# Avoid committing large binary files
# Use Git LFS for large files
git lfs install
git lfs track "*.psd"
git lfs track "*.mp4"
git add .gitattributes
# Shallow clone for faster downloads
git clone --depth 1 https://github.com/user/repo.git
# Partial clone (Git 2.22+)
git clone --filter=blob:none https://github.com/user/repo.git
# Clean up repository
git gc --aggressive --prune=now
git repack -a -d --depth=250 --window=250
# Remove unused objects
git prune
git prune-packed
# Check repository size
git count-objects -vH
Common Anti-Patterns to Avoid
- Committing generated files (node_modules, build/, *.pyc)
- Using vague commit messages (“fix”, “update”, “changes”)
- Making massive commits with unrelated changes
- Force pushing to shared branches
- Committing directly to main/production
- Leaving TODO or debug code in commits
- Rebasing public/shared branches
- Ignoring merge conflicts (accepting without review)
- Not pulling before pushing
- Committing sensitive data (passwords, keys)
Git Aliases for Productivity
# Add useful Git aliases
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual 'log --graph --oneline --all'
git config --global alias.aliases 'config --get-regexp alias'
# Beautiful log
git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
# Show branches sorted by last commit
git config --global alias.recent 'branch --sort=-committerdate'
# Amend without editing message
git config --global alias.amend 'commit --amend --no-edit'
# Undo last commit but keep changes
git config --global alias.undo 'reset HEAD~1 --soft'
# Show file changes
git config --global alias.changed 'diff --name-only'
Common Problems & Solutions
Problem: You checked out a commit directly and now you’re in “detached HEAD” state.
# If you want to keep your changes
git checkout -b new-branch-name
# If you want to discard changes
git checkout main
# If you made commits in detached state
git branch temp-branch
git checkout main
git merge temp-branch
Problem: Push rejected because remote has changes you don’t have locally.
# Pull and merge
git pull origin main
git push origin main
# Or pull with rebase (cleaner history)
git pull --rebase origin main
git push origin main
# If you're sure your changes should override (careful!)
git push --force-with-lease origin main
# Move commit to new branch
git branch feature-branch
git reset --hard HEAD~1
git checkout feature-branch
# Or move to existing branch
git checkout existing-branch
git cherry-pick main
git checkout main
git reset --hard HEAD~1
# Keep changes, undo commit
git reset --soft HEAD~1
# Undo commit and staging
git reset HEAD~1
# Undo commit and discard changes (dangerous!)
git reset --hard HEAD~1
# If already pushed (creates new commit)
git revert HEAD
# Fix last commit message
git commit --amend -m "New commit message"
# Fix older commit message
git rebase -i HEAD~3
# Change 'pick' to 'reword' for commits to edit
# Save and edit messages in following screens
# If already pushed (not recommended for shared branches)
git push --force-with-lease
# Remove file from last commit
git reset HEAD~1 filename.txt
git commit --amend --no-edit
# Or alternative method
git rm --cached filename.txt
git commit --amend --no-edit
Problem: Git commands fail because you’re not in a Git repository.
# Check if you're in a Git repo
git status
# Navigate to repository root
cd /path/to/your/repository
# If no .git folder exists, initialize
git init
# If .git was accidentally deleted
# You'll need to re-clone or restore from backup
# Test SSH connection
ssh -T git@github.com
# Generate new SSH key
ssh-keygen -t ed25519 -C "your_email@example.com"
# Start ssh-agent
eval "$(ssh-agent -s)"
# Add SSH key
ssh-add ~/.ssh/id_ed25519
# Copy public key to clipboard (macOS)
pbcopy < ~/.ssh/id_ed25519.pub
# Copy public key to clipboard (Linux)
xclip -selection clipboard < ~/.ssh/id_ed25519.pub
# Add key to GitHub/GitLab settings
# Then test again
ssh -T git@github.com
Merge Conflict Resolution Tips
- Understand both versions before choosing
- Test the code after resolving conflicts
- Communicate with teammate if unsure
- Use visual merge tools for complex conflicts
- Consider keeping both changes when applicable
- Document resolution decisions in commit message
Performance Issues
# Check repository health
git fsck
# Optimize repository
git gc --aggressive
# Clean up unnecessary files
git clean -fd
# Remove untracked files (preview first)
git clean -n
git clean -f
# Clear Git cache
git rm -r --cached .
git add .
# Fix slow git status
git config --global core.preloadindex true
git config --global core.fscache true
git config --global gc.auto 256
Powerful Git Commands
# Find which commit introduced a bug
git bisect start
git bisect bad HEAD
git bisect good v1.0
# Test each commit git provides
git bisect good/bad
# Automate with script
git bisect run npm test
# Search commit messages
git log --grep="bug fix"
git log --grep="feature" --author="John"
# Find when a string was introduced
git log -S "function_name" --source --all
# Show commits that changed specific function
git log -L :function_name:file.js
# Find who deleted a file
git log --full-history -- path/to/file
# Show commits unique to current branch
git log main..feature-branch
# Compare branches
git diff main...feature-branch
# Show changes in stash
git stash show -p stash@{0}
# Create patch file
git format-patch -1 HEAD
git format-patch main..feature-branch
# Apply patch
git apply patch-file.patch
git am patch-file.patch
Time-Saving Shortcuts
# Quick commit all changes
git commit -am "Message"
# Stage and commit specific files
git commit file1.txt file2.txt -m "Message"
# Push current branch
git push origin HEAD
# Create and switch to branch in one command
git checkout -b feature-name
# Switch to previous branch
git checkout -
# Discard all changes
git checkout .
git restore .
# Update all submodules
git submodule update --init --recursive
# Clone specific branch
git clone -b branch-name --single-branch url
# Reuse recorded conflict resolutions
git config --global rerere.enabled true
# Auto-correct mistyped commands
git config --global help.autocorrect 20
Git Configuration Tips
# Edit global config
git config --global --edit
# Use different config per project
git config user.name "Work Name"
git config user.email "work@email.com"
# Set default pull behavior
git config --global pull.rebase false # merge (default)
git config --global pull.rebase true # rebase
git config --global pull.ff only # fast-forward only
# Set default push behavior
git config --global push.default simple
# Enable auto-stash during rebase
git config --global rebase.autoStash true
# Show original branch name after rebase
git config --global rebase.abbreviateCommands false
# Auto-prune on fetch
git config --global fetch.prune true
# Use meld as diff tool
git config --global diff.tool meld
git config --global difftool.prompt false
# Better diff algorithm
git config --global diff.algorithm histogram
# Show moved code differently
git config --global diff.colorMoved zebra
Productivity Workflows
# Morning routine
git checkout main
git pull --prune
git branch -vv # Check branches
# Start new work
git checkout -b feature/new-work
# During work
git add -p # Review changes interactively
git commit -m "feat: add feature"
git push -u origin HEAD
# Before lunch/end of day
git add .
git stash save "WIP: working on feature"
# Resume work
git stash pop
# Keep feature branch updated
git fetch origin
git rebase origin/main
# Cleanup merged branches
git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
Advanced Search & Inspection
# Search for string in all branches
git grep "search_term" $(git rev-list --all)
# Find large files in repository
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sed -n 's/^blob //p' | \
sort --numeric-sort --key=2 | \
tail -n 10
# List files in specific commit
git ls-tree -r commit-hash --name-only
# Show file content at specific commit
git show commit-hash:path/to/file
# Find commits that touch a file
git log --follow -- path/to/file
# Show commits between dates
git log --since="2024-01-01" --until="2024-12-31"
# Show commits by author
git shortlog -sn --all --no-merges
# Statistics about repository
git log --shortstat --author="Your Name" | \
grep -E "fil(e|es) changed" | \
awk '{files+=$1; inserted+=$4; deleted+=$6} END \
{print "files changed:", files, "lines inserted:", inserted, "lines deleted:", deleted}'
# Find commits that modified a specific line
git log -L 15,20:path/to/file.js
# Show all files changed between commits
git diff --name-only commit1 commit2
Interactive Staging
# Interactive add (patch mode)
git add -p
# Commands in patch mode:
# y - stage this hunk
# n - do not stage this hunk
# q - quit; do not stage this or remaining hunks
# a - stage this and all remaining hunks in the file
# d - do not stage this or remaining hunks in the file
# s - split hunk into smaller hunks
# e - manually edit the hunk
# Interactive mode for all operations
git add -i
# Stage parts of files
git add --patch file.txt
# Unstage parts of files
git reset --patch file.txt
# Discard parts of changes
git checkout --patch file.txt
Git Worktrees
Work on multiple branches simultaneously without switching:
# Create worktree for another branch
git worktree add ../project-feature feature-branch
# List worktrees
git worktree list
# Remove worktree
git worktree remove ../project-feature
# Prune deleted worktrees
git worktree prune
# Use case: Fix bug while working on feature
git worktree add ../project-hotfix hotfix
cd ../project-hotfix
# Fix bug, commit, push
cd ../project-main
git worktree remove ../project-hotfix
Git Sparse Checkout
Clone only specific directories from a large repository:
# Initialize repository
git clone --filter=blob:none --sparse https://github.com/user/repo.git
cd repo
# Add specific directories
git sparse-checkout init --cone
git sparse-checkout set docs src/components
# Add more directories
git sparse-checkout add tests
# List sparse directories
git sparse-checkout list
# Disable sparse checkout
git sparse-checkout disable
Essential Git Tools
GitHub CLI
Official GitHub command-line tool
# Install
brew install gh
# Authenticate
gh auth login
# Create PR
gh pr create
# View issues
gh issue list
GitKraken
Visual Git client with intuitive interface
- • Visual commit history
- • Built-in merge conflict editor
- • GitHub/GitLab integration
- • Cross-platform support
SourceTree
Free Git GUI for Windows & Mac
- • Visualize branches easily
- • Interactive rebase
- • Submodule support
- • Git flow integration
Tig
Text-mode interface for Git
# Install
brew install tig
# Launch
tig
# View specific file
tig path/to/file
Delta
Better diff viewer with syntax highlighting
# Install
brew install git-delta
# Configure
git config --global core.pager delta
git config --global delta.side-by-side true
Lazygit
Terminal UI for Git commands
# Install
brew install lazygit
# Launch
lazygit
IDE Git Integration
VS Code Git Extensions
- • GitLens: Supercharge Git in VS Code
- • Git Graph: View repository graph
- • Git History: View and search history
- • GitHub Pull Requests: Manage PRs
IntelliJ IDEA Git Features
- • Built-in visual diff and merge
- • Local history tracking
- • Shelf changes (like stash)
- • Interactive rebase dialog
Learning Resources
Git Hosting Platforms
| Platform | Best For | Key Features |
|---|---|---|
| GitHub | Open source, collaboration | Actions, Discussions, Copilot, Pages |
| GitLab | DevOps, CI/CD | Built-in CI/CD, Container Registry |
| Bitbucket | Atlassian ecosystem | Jira integration, Pipelines |
| Azure DevOps | Enterprise, Microsoft stack | Boards, Pipelines, Artifacts |
| Gitea | Self-hosted, lightweight | Open source, minimal resources |
Useful Git Commands Reference
# Quick command reference
git help # Get help
git --help # Detailed help
man git- # Man pages
# Configuration locations
~/.gitconfig # Global config
.git/config # Local repo config
/etc/gitconfig # System config
# Environment variables
export GIT_AUTHOR_NAME="Your Name"
export GIT_AUTHOR_EMAIL="your@email.com"
export GIT_COMMITTER_NAME="Your Name"
export GIT_COMMITTER_EMAIL="your@email.com"
# Git directory structure
.git/
├── HEAD # Current branch pointer
├── config # Repository config
├── description # Repository description
├── hooks/ # Hook scripts
├── objects/ # Git objects (commits, trees, blobs)
├── refs/ # Branch and tag references
└── logs/ # Reflog data
Community & Support
Stack Overflow
Search and ask Git questions
Discord Communities
Real-time help and discussions
Reddit r/git
Community discussions and tips
Git is the version control system - software you install locally. GitHub is a cloud-based hosting service for Git repositories with additional collaboration features like pull requests, issues, and project management.
Use merge for: public/shared branches, preserving complete history, team collaboration. Use rebase for: cleaning up local commits before pushing, maintaining linear history, feature branches before merging to main.
Use git revert HEAD to create a new commit that undoes changes (safe for shared branches). Avoid git reset on pushed commits as it rewrites history and causes problems for others.
It depends on your team and project. GitHub Flow works well for continuous deployment. Git Flow suits projects with scheduled releases. Trunk-Based Development is ideal for mature teams with strong CI/CD.
Commit whenever you complete a logical unit of work. Each commit should be atomic (one purpose), functional (code works), and meaningful (has clear message). Typically several times per day.
Yes! Use git reflog to find the commit hash, then git checkout commit-hash or git cherry-pick commit-hash. Reflog keeps commits for 90 days by default.
.gitignore specifies files Git should ignore. Always ignore: dependencies (node_modules/), build outputs (dist/, build/), logs, OS files (.DS_Store), IDE configs (.vscode/), environment files (.env), and sensitive data.
git remote add upstream https://github.com/original/repo.git
git fetch upstream
git checkout main
git merge upstream/main
git push origin main
HEAD is a pointer to your current location in the repository - usually the tip of your current branch. HEAD~1 means one commit before HEAD, HEAD~2 means two commits before, etc.
SSH is recommended for regular use (no password prompts, more secure). HTTPS works well for occasional access or restrictive networks. Both are secure when properly configured.