Advanced Git Commands
Beyond the basic Git commands, there are powerful advanced tools that can save you in critical situations and enhance your productivity. In this lesson, we'll explore cherry-pick, reflog, bisect, blame, and other advanced Git commands that every professional developer should know.
Git Cherry-Pick: Applying Specific Commits
Cherry-pick allows you to apply a specific commit from one branch to another without merging the entire branch.
Basic Cherry-Pick:
# You're on main branch
git checkout main
# Apply commit from feature branch
git cherry-pick abc123
# Commit abc123 is now on main (with new hash)
Use Cases:
✓ Apply hotfix to multiple branches
✓ Pick specific features from experimental branch
✓ Backport fixes to older release branches
✓ Move commits to correct branch after mistake
Important: Cherry-pick creates a NEW commit with the same changes but a different hash. It doesn't move the original commit.
Cherry-Pick Examples
Cherry-Pick Multiple Commits:
# Pick a range of commits
git cherry-pick abc123..def456
# Pick specific commits
git cherry-pick abc123 def456 ghi789
Cherry-Pick Without Auto-Commit:
# Stage changes without committing
git cherry-pick -n abc123
# or
git cherry-pick --no-commit abc123
# Review changes, then commit manually
git commit -m "Cherry-picked feature from abc123"
Resolve Cherry-Pick Conflicts:
# If conflict occurs
git cherry-pick abc123
# CONFLICT (content): Merge conflict in file.php
# Fix conflicts manually
# Then:
git add file.php
git cherry-pick --continue
# Or abort:
git cherry-pick --abort
Pro Tip: Use cherry-pick sparingly. If you find yourself cherry-picking many commits, consider merging or rebasing instead.
Git Reflog: The Safety Net
Reflog (reference log) records every change to HEAD. It's your safety net for recovering "lost" commits.
View Reflog:
$ git reflog
abc123 HEAD@{0}: commit: Add user authentication
def456 HEAD@{1}: checkout: moving from feature to main
ghi789 HEAD@{2}: commit: Fix payment bug
jkl012 HEAD@{3}: reset: moving to HEAD~1
mno345 HEAD@{4}: commit: Add payment feature (LOST!)
Reflog Explanation:
- HEAD@{0} = Current HEAD position
- HEAD@{1} = Previous HEAD position
- HEAD@{2} = Two moves ago
- etc.
Recovering Lost Commits with Reflog
Scenario: Accidentally Reset Hard
# You accidentally did:
git reset --hard HEAD~3
# Oh no! 3 commits are gone!
# Solution: Use reflog
git reflog
# Find the commit hash before reset
abc123 HEAD@{4}: commit: Add payment feature
# Restore to that commit
git reset --hard abc123
# Your commits are back! 🎉
Scenario: Deleted Branch Recovery
# You accidentally deleted a branch
git branch -D feature/important-work
# Find the last commit on that branch
git reflog | grep "feature/important-work"
# Recreate the branch
git branch feature/important-work abc123
git checkout feature/important-work
Note: Reflog entries expire after 90 days by default. Don't wait too long to recover lost work!
Git Bisect: Finding Bugs with Binary Search
Bisect uses binary search to find which commit introduced a bug.
Basic Bisect Workflow:
# Start bisect
git bisect start
# Mark current commit as bad (bug exists)
git bisect bad
# Mark a known good commit (bug didn't exist)
git bisect good v1.2.0
# Git checks out middle commit
# Test if bug exists
# If bug exists:
git bisect bad
# If bug doesn't exist:
git bisect good
# Repeat until Git finds the problematic commit
# When done:
git bisect reset
Automated Bisect with Tests
Run Bisect Automatically:
# Start bisect
git bisect start HEAD v1.2.0
# Run bisect with test command
git bisect run php artisan test --filter=PaymentTest
# Git will automatically test each commit
# Mark as good/bad based on test exit code
# Exit code 0 = good, non-zero = bad
# Bisect will find the exact commit that broke tests
Example Output:
abc123 is the first bad commit
commit abc123
Author: John Doe <john@example.com>
Date: Mon Jan 15 10:30:00 2024 +0000
Refactor payment calculation
This commit introduced the bug!
Power Move: Bisect can check hundreds of commits in minutes by using binary search. Manual testing would take hours!
Git Blame: Track Changes by Author
Blame shows who last modified each line of a file and when.
Basic Blame:
$ git blame app/Http/Controllers/PaymentController.php
abc123 (John Doe 2024-01-15 10:30:00 +0000 1) <?php
abc123 (John Doe 2024-01-15 10:30:00 +0000 2)
def456 (Jane Smith 2024-02-01 14:20:00 +0000 3) public function process($order) {
def456 (Jane Smith 2024-02-01 14:20:00 +0000 4) $tax = $order->total * 0.08;
ghi789 (Bob Johnson 2024-03-10 09:15:00 +0000 5) // TODO: Fix tax calculation
def456 (Jane Smith 2024-02-01 14:20:00 +0000 6) return $order->total + $tax;
abc123 (John Doe 2024-01-15 10:30:00 +0000 7) }
Useful Blame Options:
# Show line numbers and commit info
git blame -L 10,20 file.php
# Show only specific line range
git blame -L 10,+5 file.php
# Show email instead of names
git blame -e file.php
# Ignore whitespace changes
git blame -w file.php
Pro Tip: Use blame to find who wrote code, not to blame them! It's for understanding context and asking questions.
Git Grep: Search Repository Content
Grep searches file contents across your entire Git repository.
Basic Grep:
# Search for text in all tracked files
git grep "calculateTax"
# Search with line numbers
git grep -n "calculateTax"
# Case-insensitive search
git grep -i "calculatetax"
# Show count of matches per file
git grep -c "calculateTax"
# Search in specific branch
git grep "calculateTax" main
# Search in specific commit
git grep "calculateTax" abc123
Advanced Grep:
# Search with regex
git grep "function.*calculate"
# Search for whole words only
git grep -w "tax"
# Show context (3 lines before/after)
git grep -C 3 "calculateTax"
# Search only PHP files
git grep "calculateTax" -- "*.php"
# Search multiple patterns (AND)
git grep -e "tax" --and -e "calculate"
Git Submodules: Managing Dependencies
Submodules allow you to include another Git repository inside your repository.
Add Submodule:
# Add submodule
git submodule add https://github.com/vendor/library.git lib/library
# This creates .gitmodules file
Clone Repository with Submodules:
# Clone and initialize submodules
git clone --recurse-submodules https://github.com/user/repo.git
# Or if already cloned:
git submodule init
git submodule update
Update Submodules:
# Update all submodules to latest
git submodule update --remote
# Update specific submodule
git submodule update --remote lib/library
Remove Submodule:
# Remove submodule
git submodule deinit lib/library
git rm lib/library
rm -rf .git/modules/lib/library
Note: Submodules are complex and have gotchas. Consider using Composer (PHP) or npm (JavaScript) for dependency management instead.
Git Worktree: Multiple Working Directories
Worktree allows you to check out multiple branches simultaneously in different directories.
Use Case:
You're working on a feature but need to quickly fix a production bug
without losing your current work.
Create Worktree:
# Create worktree for hotfix
git worktree add ../hotfix-dir hotfix/urgent-bug
# Now you have:
# - /project (main working directory)
# - /hotfix-dir (separate directory with hotfix branch)
# Work in hotfix directory
cd ../hotfix-dir
# Make changes, commit, push
git add .
git commit -m "Fix urgent bug"
git push
# Return to main work
cd /project
# Your feature work is untouched!
Manage Worktrees:
# List all worktrees
git worktree list
# Remove worktree
git worktree remove ../hotfix-dir
# Prune deleted worktrees
git worktree prune
Benefit: Worktrees eliminate the need to stash, commit WIP, or clone the repo again. Work on multiple branches simultaneously!
Git Show: Inspect Commits and Objects
Show Commit Details:
# Show latest commit
git show
# Show specific commit
git show abc123
# Show specific file from commit
git show abc123:app/Models/User.php
# Show file from different branch
git show main:README.md
Show Tag:
# Show annotated tag details
git show v1.2.0
Show Stash:
# Show latest stash
git show stash@{0}
# Show specific stash
git show stash@{2}
Git Archive: Create Release Archives
Create Archive:
# Create zip archive of main branch
git archive --format=zip --output=release-v1.2.0.zip main
# Create tar.gz archive
git archive --format=tar.gz --output=release.tar.gz main
# Archive specific tag
git archive --format=zip --output=v1.2.0.zip v1.2.0
# Archive with prefix directory
git archive --prefix=myapp/ --format=zip --output=myapp.zip main
Archive Specific Files:
# Archive only app/ directory
git archive --format=zip --output=app-only.zip main app/
# Archive excluding vendor/
git archive --format=zip --output=no-vendor.zip main \
$(git ls-files | grep -v "^vendor/")
Git Clean: Remove Untracked Files
Clean Untracked Files:
# Dry run (show what would be deleted)
git clean -n
# Remove untracked files
git clean -f
# Remove untracked files and directories
git clean -fd
# Remove ignored files too
git clean -fdx
# Interactive clean
git clean -i
Common Use Case:
# After switching branches, remove build artifacts
git clean -fdx
# Clean but keep .env file
git clean -fdx -e .env
Danger: git clean -fdx permanently deletes files! Always run git clean -n first to preview.
Git Shortlog: Summarize Contributors
View Contributor Summary:
# Show commit counts by author
git shortlog -sn
# Output:
150 John Doe
87 Jane Smith
45 Bob Johnson
# Show with email addresses
git shortlog -sne
# Show for specific branch
git shortlog -sn main
# Show for date range
git shortlog -sn --since="2024-01-01" --until="2024-12-31"
# Show detailed commit messages
git shortlog
Git Log Advanced Queries
Powerful Log Queries:
# Commits by specific author
git log --author="John Doe"
# Commits in date range
git log --since="2024-01-01" --until="2024-12-31"
# Commits affecting specific file
git log -- app/Models/User.php
# Search commit messages
git log --grep="fix bug"
# Search commit content (code changes)
git log -S "calculateTax"
# Commits that added or removed specific text
git log -G "function.*calculate"
# Show files changed in each commit
git log --name-only
# Show stats (insertions/deletions)
git log --stat
# Custom format
git log --pretty=format:"%h - %an, %ar : %s"
# Commits on branch but not on main
git log main..feature/new-feature
# Merge commits only
git log --merges
# Non-merge commits only
git log --no-merges
Practice Exercise:
Scenario: Your production app has a bug. The bug didn't exist in v1.0.0 (released 3 months ago), but exists now. You need to find which commit introduced it.
Tasks:
- Use git bisect to find the problematic commit
- Use git blame to see who wrote the buggy line
- Use git show to examine the commit details
- Use git log to understand the context
Solution:
# 1. Start bisect
git bisect start
git bisect bad # Current version has bug
git bisect good v1.0.0 # v1.0.0 was working
# Git checks out middle commit
# Test the app...
# Bug exists:
git bisect bad
# Continue until Git finds the commit:
# abc123 is the first bad commit
# 2. Use blame to find who wrote the buggy code
git blame app/Services/PaymentService.php
# Output shows line 45 was modified in commit abc123
# 3. Show commit details
git show abc123
# See full diff and commit message
# 4. Get context with log
git log abc123~5..abc123
# See commits around the problematic one
# 5. Cherry-pick the fix to hotfix branch
git checkout -b hotfix/payment-bug
git cherry-pick def456 # The commit that fixes it
# 6. Done!
git bisect reset
Summary
In this lesson, you learned:
- git cherry-pick: Apply specific commits to another branch
- git reflog: Recover "lost" commits and branches
- git bisect: Find bug-introducing commits with binary search
- git blame: Track who modified each line of code
- git grep: Search repository content efficiently
- git worktree: Work on multiple branches simultaneously
- git clean: Remove untracked files safely
- Advanced git log: Powerful commit history queries
Congratulations! You've completed the Git & GitHub tutorial. You now have the skills to confidently use Git for version control, collaborate with teams on GitHub, and handle advanced scenarios. Keep practicing, and you'll master Git in no time!