Interactive rebase is like having a time machine that lets you reorganize, edit, and clean up your commit history before sharing it with others.
git rebase -i HEAD~5 # Rebase last 5 commits # This opens your editor with: pick abc123 Add feature pick def456 WIP pick ghi789 Fix typo pick jkl012 More WIP pick mno345 Final fix # Change to: pick abc123 Add feature squash def456 WIP # Combine with previous fixup ghi789 Fix typo # Combine, discard message squash jkl012 More WIP reword mno345 Final fix # Change commit message
| Command | Action | Use Case |
|---|---|---|
pick |
Use commit as-is | Keep good commits |
reword |
Change commit message | Fix typos or clarify |
edit |
Stop to amend commit | Add forgotten files |
squash |
Combine with previous, keep messages | Group related changes |
fixup |
Combine with previous, discard message | Hide "oops" commits |
drop |
Remove commit entirely | Delete unwanted changes |
Git bisect is like playing "20 questions" with your code to find exactly when a bug was introduced.
# Start bisecting git bisect start git bisect bad # Current version is broken git bisect good v1.0 # v1.0 was working # Git checks out a commit in the middle # You test it... npm test # Run your tests # Tell git the result git bisect bad # This commit is also broken # Git narrows it down, checks out another npm test git bisect good # This one works! # Continue until git finds the exact commit Bisecting: 0 revisions left to test b47c3a2 is the first bad commit # Clean up git bisect reset
# Create a test script echo 'npm test | grep "passing"' > test.sh chmod +x test.sh # Let git automatically find the bad commit git bisect start HEAD v1.0 git bisect run ./test.sh # Git will automatically test each commit!
The reflog is like a flight recorder for your repository - it tracks every move you make, even "lost" commits!
# View the reflog git reflog abc123 HEAD@{0}: reset: moving to HEAD~3 def456 HEAD@{1}: commit: Important feature I accidentally deleted! ghi789 HEAD@{2}: commit: Another commit # Recover the "lost" commit git checkout def456 # View the lost commit git branch recovered-work # Create branch from it # Or restore directly git reset --hard HEAD@{1} # Go back to that state
Git hooks are like security checkpoints or automatic tasks that run at specific moments in your Git workflow.
#!/bin/sh # .git/hooks/pre-commit # Format all JavaScript files files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$') if [ "$files" != "" ]; then echo "Formatting JavaScript files..." npx prettier --write $files git add $files fi # Run linter echo "Running ESLint..." npx eslint . || exit 1 echo "✅ Pre-commit checks passed!"
#!/bin/sh # .git/hooks/commit-msg commit_regex='^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}' if ! grep -qE "$commit_regex" "$1"; then echo "❌ Invalid commit message format!" echo "📝 Format: type(scope): description" echo "Example: feat(auth): add login functionality" exit 1 fi
| Reset Type | Changes | Use Case | Example |
|---|---|---|---|
--soft |
Only moves HEAD | Undo commits but keep changes staged | Combining multiple commits |
--mixed (default) |
Moves HEAD and clears staging | Undo commits and unstage | Start over with staging |
--hard |
Discards all changes | Complete reset to previous state | Abandon all work |
Stash is like pressing pause on your current work to handle something urgent, then resuming exactly where you left off.
# Save with a descriptive message git stash push -m "WIP: new authentication flow" # Stash only specific files git stash push -m "navbar changes" -- src/navbar.js src/navbar.css # List all stashes git stash list stash@{0}: On main: WIP: new authentication flow stash@{1}: On feature: navbar changes stash@{2}: WIP on feature: 3a4b5c6 Previous commit # Apply specific stash without removing it git stash apply stash@{1} # Create branch from stash git stash branch new-feature-branch stash@{0} # Show stash contents git stash show -p stash@{0} # Clear all stashes (careful!) git stash clear
Submodules let you include other Git repositories within your project, perfect for shared libraries or components.
# Add a submodule git submodule add https://github.com/company/shared-ui.git libs/ui git commit -m "Add UI library submodule" # Clone a project with submodules git clone --recurse-submodules https://github.com/user/project.git # Or initialize after cloning git submodule init git submodule update # Update all submodules to latest git submodule update --remote --merge # Work within a submodule cd libs/ui git checkout main git pull origin main cd ../.. git add libs/ui git commit -m "Update UI library to latest version"
# Oh no! Deleted important branch git branch -D feature-important # Don't panic! Check reflog git reflog abc123 HEAD@{5}: checkout: moving from feature-important to main # Recreate the branch git branch feature-important abc123 ✅ Branch recovered!
# Made commits to main instead of feature branch # Create new branch with the commits git branch feature-branch # Reset main back (keep changes in working directory) git reset --soft HEAD~3 # Or reset hard if you want to discard git reset --hard origin/main # Switch to feature branch with your commits git checkout feature-branch
# Option 1: If haven't pushed yet git reset --hard HEAD~1 # Option 2: If already pushed (creates new commit) git revert -m 1 HEAD # Option 3: Find pre-merge state git reflog git reset --hard HEAD@{2}
Worktrees let you have multiple branches checked out simultaneously in different directories - perfect for quick bug fixes!
# Add a new worktree for a hotfix git worktree add ../project-hotfix hotfix-branch # List all worktrees git worktree list /home/user/project abc123 [main] /home/user/project-hotfix def456 [hotfix-branch] # Work in different directories simultaneously! cd ../project-hotfix # Fix bug here while feature work continues in main directory # Remove worktree when done git worktree remove ../project-hotfix
# Clone only recent history git clone --depth 1 https://github.com/large/repo.git # Get more history later if needed git fetch --deepen=100
# Clone without blobs initially git clone --filter=blob:none https://github.com/large/repo.git # Clone only specific paths git clone --filter=blob:none --sparse https://github.com/large/repo.git cd repo git sparse-checkout init --cone git sparse-checkout set src/frontend
# Optimize repository git gc --aggressive # Enable automatic maintenance git maintenance start # Pack refs for better performance git pack-refs --all
Incredible work! You've mastered advanced Git techniques that many developers never learn. In our final lesson, we'll cover:
🎯 You now have the power tools to handle any Git situation! Remember: with great power comes great responsibility. Always think before using destructive commands, and when in doubt, make a backup branch first!