Basic Git gets you through the day. Advanced Git makes you a wizard. Want to clean up messy commit history before sharing? Rebase. Need only specific commits from another branch? Cherry-pick. Lost commits after a bad rebase? Reflog saves the day. In this lesson, you'll master the advanced Git commands that separate novices from experts.
1. Learning Objectives
By the end of this lesson, you will be able to:
- Use interactive rebase to squash, reorder, and edit commits
- Selectively apply commits with
git cherry-pick - Recover lost commits with
git reflog - Find bugs with
git bisect - Clean up history before pushing
- Fix mistakes after pushing
2. Why This Matters
Real-world scenario: You've been working on a feature for a week with 20 messy commits. Before sharing, you want to clean up: squash small fixes, reorder commits, and write better messages. Interactive rebase makes this possible.
Another scenario: You accidentally deleted a branch with important work. Reflog lets you recover it.
3. Core Concepts
Interactive Rebase: Cleaning History
# Start interactive rebase for last 5 commits
git rebase -i HEAD~5
# An editor opens showing:
# pick f7f3f6d Add user authentication
# pick 310154e Fix typo in login form
# pick a5f4a0d Add password validation
# pick c6f9e8e Fix minor bug in validation
# pick 0d1a2b3 Improve error messages
# Commands you can use:
# pick (p) - Use commit as-is
# reword (r) - Change commit message
# edit (e) - Stop to amend commit
# squash (s) - Combine with previous commit
# fixup (f) - Combine, discard message
# drop (d) - Remove commit
# reorder - Just move lines to reorder
# Example: Squash Fix typo into Add user authentication
# pick f7f3f6d Add user authentication
# fixup 310154e Fix typo in login form
# squash a5f4a0d Add password validation
# fixup c6f9e8e Fix minor bug in validation
# reword 0d1a2b3 Improve error messages
# Save and close - Git executes the rebase
Rebase vs Merge
# Merge preserves history, creates merge commit
# Rebases rewrite history, creates linear history
# Merge (non-linear history)
git checkout feature
git merge main
# A---B---C feature
# / \
# D---E---F---G---H main
# Rebase (linear history)
git checkout feature
git rebase main
# A'--B'--C' feature
# /
# D---E---F---G main
# When to use each:
# - Merge: public branches, preserving exact history
# - Rebase: private branches before sharing
# Rebase feature branch onto updated main
git checkout feature
git rebase main
# Resolve any conflicts, then
git rebase --continue
# or
git rebase --abort
Cherry-pick: Selectively Apply Commits
# Apply a single commit to current branch
git cherry-pick abc123def
# Apply a range of commits
git cherry-pick abc123..def456
# Apply but don't auto-commit
git cherry-pick -n abc123def
# Apply multiple commits
git cherry-pick abc123 def456 ghi789
# Real-world: Backport a bug fix
git checkout release/v1.0
git cherry-pick -x abc123def # -x adds source info
# Resolve conflicts if needed
git cherry-pick --continue
git cherry-pick --abort
# Example: Extract specific commits from a feature branch
# BEFORE: feature branch has 10 commits
# AFTER: main branch has only the 3 useful commits
Reflog: Recovering Lost Commits
# View reflog (local history of HEAD movements)
git reflog
# Output example:
# abc1234 HEAD@{0}: commit: Add new feature
# def5678 HEAD@{1}: rebase -i (finish): Rebase completed
# ghi9012 HEAD@{2}: rebase -i (start): Checkout
# jkl3456 HEAD@{3}: commit: WIP
# Recover deleted branch
git checkout -b recovered-branch abc1234
# Undo a rebase
git reset --hard HEAD@{1}
# Go back in time (temporarily)
git checkout HEAD@{2}
# See reflog for specific branch
git reflog show feature-branch
# Recover after hard reset
git reflog
# Find commit before reset
git reset --hard HEAD@{5}
# Clean reflog (remove entries older than 90 days)
git reflog expire --expire=now --all
git gc --prune=now
Git Bisect: Find the Commit That Broke Everything
# Start bisect
git bisect start
# Mark current commit as bad (has the bug)
git bisect bad
# Mark a known good commit (no bug)
git bisect good v1.0
# Git checks out a commit halfway between
# Test the commit, then mark:
git bisect good # If commit is good
git bisect bad # If commit is bad
# Repeat until Git finds the bad commit
# When done, show results
git bisect log
# End bisect session
git bisect reset
# Automatic bisect with script
git bisect start HEAD v1.0
git bisect run npm test
# Example: Find where the API broke
# Run API test automatically
cat > test-api.sh << 'EOF'
#!/bin/bash
curl -f http://localhost:3000/health || exit 1
EOF
chmod +x test-api.sh
git bisect start HEAD v1.0
git bisect run ./test-api.sh
Fixing Mistakes After Push
# Scenario 1: Wrong commit message
git commit --amend -m "Correct message"
git push --force-with-lease origin main
# Scenario 2: Forgot to add a file
git add forgotten-file.txt
git commit --amend --no-edit
git push --force-with-lease
# Scenario 3: Need to remove a commit (but keep changes)
git reset --soft HEAD~1 # Keep changes in working directory
git reset --mixed HEAD~1 # Keep changes unstaged
git reset --hard HEAD~1 # Discard changes completely
# Scenario 4: Revert a pushed commit (safe way)
git revert abc123def # Creates new revert commit
git push origin main
# Scenario 5: Remove last 3 commits (if not pushed)
git reset --hard HEAD~3
# Scenario 6: Remove last 3 commits (if pushed - use with caution!)
git reset --hard HEAD~3
git push --force-with-lease
4. Complete Project: History Cleanup
#!/bin/bash
# cleanup_history.sh - Script to clean messy Git history
echo "=== Git History Cleanup Tool ==="
# Display current messy log
echo "Current messy history:"
git log --oneline -10
# Option 1: Squash recent commits
echo ""
echo "Squashing last 5 commits..."
git reset --soft HEAD~5
git commit -m "Feature: Complete implementation with all fixes"
echo "Done! Now have 1 commit instead of 5"
# Option 2: Interactive rebase for more control
echo ""
echo "For more control, use: git rebase -i HEAD~N"
echo "Commands you can use:"
echo " - squash: combine with previous"
echo " - fixup: combine, discard message"
echo " - reword: change commit message"
echo " - edit: stop to amend"
echo " - drop: delete commit"
# Option 3: Clean up after rebase
echo ""
echo "After cleaning, force push (if branch is private):"
echo "git push --force-with-lease origin feature-branch"
# Option 4: Clean up old branches
echo ""
echo "Deleting merged branches:"
git branch --merged | grep -v "\*" | grep -v "main" | xargs -n 1 git branch -d
# Option 5: Remove large files from history
echo ""
echo "To remove large files from history:"
echo "git filter-branch --tree-filter 'rm -f largefile.zip' HEAD"
echo "# or use BFG Repo-Cleaner for better performance"
5. Common Errors & Solutions
6. Summary Checklist
7. Next Steps
Next lesson: Git Lesson 3.6: GitHub Actions CI/CD
You'll learn to:
- Automate testing with GitHub Actions
- Build and push Docker images
- Deploy to cloud platforms
- Create custom workflows
Comments (0)
This is exactly what I needed! The initContainer approach solved our migration issues completely. Thanks for the detailed guide!
ReplyLeave a Comment