Advanced Git
Master sophisticated Git techniques, power tools, and advanced workflows for complex development scenarios.
Interactive Rebasing
Understanding Interactive Rebase
Interactive rebase allows you to modify commit history:
# Start interactive rebase
git rebase -i HEAD~3
# Rebase onto different branch
git rebase -i main
# Rebase with specific commit
git rebase -i abc123^
Rebase Commands
# Interactive rebase commands:
pick abc123 Original commit message
reword def456 Change this commit message
edit ghi789 Stop here to modify commit
squash jkl012 Combine with previous commit
fixup mno345 Combine with previous, discard message
drop pqr678 Remove this commit completely
exec npm test Run command after this commit
Common Rebase Scenarios
Squashing Commits:
# Before rebase:
# * feat: Add user authentication
# * fix: Fix typo in login
# * test: Add auth tests
# * docs: Update README
# Interactive rebase
git rebase -i HEAD~4
# Change to:
pick feat: Add user authentication
squash fix: Fix typo in login
squash test: Add auth tests
squash docs: Update README
# Result: Single commit with all changes
Reordering Commits:
# Reorder commits by changing their order in the editor
pick commit3 Third commit
pick commit1 First commit
pick commit2 Second commit
Editing Commits:
# Mark commit for editing
edit abc123 Commit to modify
# When rebase pauses:
# Make changes
git add modified-file.txt
git commit --amend --no-edit
git rebase --continue
Splitting Commits:
# Mark commit for editing
edit abc123 Large commit to split
# When rebase pauses:
git reset HEAD~1 # Unstage the commit
git add file1.txt
git commit -m "First part of change"
git add file2.txt
git commit -m "Second part of change"
git rebase --continue
Cherry-picking
Basic Cherry-picking
# Apply specific commit to current branch
git cherry-pick abc123
# Cherry-pick multiple commits
git cherry-pick abc123 def456 ghi789
# Cherry-pick range of commits
git cherry-pick abc123^..ghi789
# Cherry-pick with custom message
git cherry-pick abc123 --edit
Cherry-pick Options
# Cherry-pick without committing
git cherry-pick abc123 --no-commit
# Cherry-pick and add sign-off
git cherry-pick abc123 --signoff
# Cherry-pick only the changes (not commit info)
git cherry-pick abc123 --no-commit --no-ff
# Continue cherry-pick after resolving conflicts
git cherry-pick --continue
# Abort cherry-pick
git cherry-pick --abort
Advanced Cherry-picking
# Cherry-pick from different remote
git cherry-pick origin/feature-branch
# Cherry-pick merge commit (specify parent)
git cherry-pick -m 1 merge-commit-hash
# Cherry-pick with strategy
git cherry-pick -X theirs abc123
# Cherry-pick with empty commits
git cherry-pick --allow-empty abc123
Git Bisect
Finding Bugs with Bisect
# Start bisect
git bisect start
# Mark current commit as bad
git bisect bad
# Mark known good commit
git bisect good v1.0.0
# Git checks out middle commit
# Test the commit and mark it
git bisect good # or git bisect bad
# Continue until bug is found
# Git will identify the first bad commit
# Reset to original state
git bisect reset
Automated Bisect
# Run bisect with test script
git bisect start HEAD v1.0.0
git bisect run ./test-script.sh
# test-script.sh should exit with:
# 0 if commit is good
# 1-124 if commit is bad
# 125 if commit is untestable
Example Test Script:
#!/bin/bash
# test-script.sh
# Build the project
make clean && make
# Run tests
if ./run-tests.sh; then
exit 0 # Good commit
else
exit 1 # Bad commit
fi
Git Subtrees
Understanding Subtrees
Subtrees allow you to embed one repository inside another:
# Add subtree
git subtree add --prefix=lib/external \
https://github.com/user/library.git main --squash
# Pull updates from subtree
git subtree pull --prefix=lib/external \
https://github.com/user/library.git main --squash
# Push changes to subtree
git subtree push --prefix=lib/external \
https://github.com/user/library.git main
Subtree Operations
# Split subtree into branch
git subtree split --prefix=lib/external -b external-library
# Create subtree from existing directory
git subtree add --prefix=docs/external \
https://github.com/user/docs.git main --squash
# Merge subtree changes
git subtree merge --prefix=lib/external \
--squash external-updates
Subtree vs Submodule
Subtrees:
- Code is embedded in main repository
- Full history is included
- Easier for contributors (no submodule commands)
- Larger repository size
Submodules:
- Separate repositories with pointers
- Smaller main repository
- Requires submodule-specific commands
- More complex for contributors
Advanced Merging
Merge Strategies
# Recursive merge (default)
git merge --strategy=recursive feature-branch
# Octopus merge (multiple branches)
git merge branch1 branch2 branch3
# Ours strategy (ignore other branch completely)
git merge --strategy=ours feature-branch
# Subtree strategy
git merge --strategy=subtree feature-branch
Merge Strategy Options
# Prefer our changes in conflicts
git merge -X ours feature-branch
# Prefer their changes in conflicts
git merge -X theirs feature-branch
# Ignore whitespace changes
git merge -X ignore-space-change feature-branch
# Ignore all whitespace
git merge -X ignore-all-space feature-branch
# Patience algorithm
git merge -X patience feature-branch
Custom Merge Drivers
# Configure custom merge driver
git config merge.custom.driver "./custom-merge-script.sh %O %A %B %L"
# Apply to specific files
echo "*.config merge=custom" >> .gitattributes
# Custom merge script example
#!/bin/bash
# custom-merge-script.sh
BASE=$1
OURS=$2
THEIRS=$3
MARKER_SIZE=$4
# Custom merge logic here
# Return 0 for success, 1 for conflicts
Git Worktrees
Multiple Working Directories
# Create new worktree
git worktree add ../feature-branch feature-branch
# Create worktree with new branch
git worktree add -b new-feature ../new-feature
# List worktrees
git worktree list
# Remove worktree
git worktree remove ../feature-branch
# Prune worktrees
git worktree prune
Worktree Use Cases
Parallel Development:
# Main development in main directory
# Feature development in separate worktree
git worktree add ../feature-a feature-a
git worktree add ../feature-b feature-b
git worktree add ../hotfix hotfix-branch
# Benefits:
# - No branch switching overhead
# - Separate build artifacts
# - Parallel testing
Release Management:
# Maintain multiple versions
git worktree add ../v1.0-maintenance v1.0-maintenance
git worktree add ../v2.0-development v2.0-development
# Apply hotfixes to specific versions
cd ../v1.0-maintenance
git cherry-pick hotfix-commit
Advanced Git Plumbing
Low-Level Git Operations
# Object examination
git cat-file -t object-hash # Show object type
git cat-file -s object-hash # Show object size
git cat-file -p object-hash # Show object content
# Create objects manually
echo "Hello, World!" | git hash-object -w --stdin
# Update references
git update-ref refs/heads/new-branch commit-hash
# Symbolic references
git symbolic-ref HEAD refs/heads/main
Repository Surgery
# Remove file from entire history
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch large-file.zip' HEAD
# Change author information
git filter-branch --commit-filter '
if [ "$GIT_COMMITTER_NAME" = "Old Name" ]; then
GIT_COMMITTER_NAME="New Name"
GIT_COMMITTER_EMAIL="new@email.com"
fi
git commit-tree "$@"
' HEAD
# Remove commits by author
git filter-branch --commit-filter '
if [ "$GIT_AUTHOR_EMAIL" = "spam@example.com" ]; then
skip_commit "$@"
else
git commit-tree "$@"
fi
' HEAD
Git Attributes
Advanced Attributes
# .gitattributes examples
# Text handling
*.txt text
*.md text eol=lf
*.bat text eol=crlf
# Binary files
*.jpg binary
*.png binary
*.exe binary
# Custom diff
*.json diff=json
*.xml diff=xml
*.sql diff=sql
# Merge strategies
generated/* merge=ours
*.lock merge=binary
# Export control
secret.txt export-ignore
.env export-ignore
Custom Filters
Clean/Smudge Filters:
# Configure encrypt/decrypt filter
git config filter.encrypt.clean 'openssl enc -aes-256-cbc -e -k PASSWORD'
git config filter.encrypt.smudge 'openssl enc -aes-256-cbc -d -k PASSWORD'
# Apply to files
echo "*.secret filter=encrypt" >> .gitattributes
# Keyword expansion filter
git config filter.keyword.clean 'sed "s/\$Date[^$]*\$/\$Date\$/"'
git config filter.keyword.smudge 'sed "s/\$Date\$/\$Date: $(date) \$/"'
Git Hooks Advanced
Server-Side Hooks
Pre-receive Hook:
#!/bin/sh
# hooks/pre-receive
# Prevent force pushes
while read oldrev newrev refname; do
if [ "$oldrev" != "0000000000000000000000000000000000000000" ]; then
if ! git merge-base --is-ancestor $oldrev $newrev; then
echo "Force push detected on $refname. Rejected."
exit 1
fi
fi
done
# Check commit message format
git rev-list --reverse $oldrev..$newrev | while read commit; do
message=$(git log -1 --format=%s $commit)
if ! echo "$message" | grep -E "^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .+"; then
echo "Invalid commit message format in $commit"
exit 1
fi
done
Post-receive Hook:
#!/bin/sh
# hooks/post-receive
# Deploy specific branches
while read oldrev newrev refname; do
branch=$(git rev-parse --symbolic --abbrev-ref $refname)
case $branch in
"main")
echo "Deploying to production..."
/path/to/deploy-production.sh
;;
"staging")
echo "Deploying to staging..."
/path/to/deploy-staging.sh
;;
"develop")
echo "Running integration tests..."
/path/to/integration-tests.sh
;;
esac
done
# Send notifications
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"New push to repository"}' \
$SLACK_WEBHOOK_URL
Hook Management
# Global hooks directory
git config --global core.hooksPath ~/.githooks
# Shared hooks for team
mkdir -p .githooks
echo "#!/bin/sh" > .githooks/pre-commit
echo "npm test" >> .githooks/pre-commit
chmod +x .githooks/pre-commit
# Install hooks script
#!/bin/bash
# install-hooks.sh
for hook in .githooks/*; do
ln -sf ../../$hook .git/hooks/$(basename $hook)
done
Performance and Optimization
Advanced Performance Techniques
# Multi-pack index
git multi-pack-index write
git multi-pack-index verify
# Commit graph
git commit-graph write --reachable
git commit-graph verify
# Bitmap index
git repack -adb
# Optimize repository
git gc --aggressive --prune=now
git repack -adf --window=250 --depth=250
Large Repository Handling
# Partial clone
git clone --filter=blob:none --filter=tree:0 large-repo.git
# Sparse checkout
git sparse-checkout init --cone
git sparse-checkout set important-directory/
# LFS for large files
git lfs track "*.zip"
git lfs track "assets/videos/*"
Advanced Troubleshooting
Repository Recovery
# Recover deleted branch
git reflog --all | grep branch-name
git branch recovered-branch commit-hash
# Recover deleted commits
git fsck --lost-found
git show dangling-commit-hash
# Fix corrupted repository
git fsck --full
git prune
git gc --aggressive
# Reset to clean state
git reset --hard HEAD
git clean -fd
git checkout HEAD -- .
Advanced Debugging
# Trace Git operations
GIT_TRACE=1 git command
GIT_TRACE_PERFORMANCE=1 git command
GIT_TRACE_SETUP=1 git command
# Debug merge conflicts
git log --merge --oneline
git diff HEAD...MERGE_HEAD
# Debug rebase issues
git rebase --show-current-patch
git am --show-current-patch
Best Practices for Advanced Features
When to Use Advanced Features
- Interactive Rebase - Clean up history before sharing
- Cherry-pick - Apply specific fixes across branches
- Bisect - Find regression bugs efficiently
- Subtrees - Embed external repositories
- Worktrees - Parallel development workflows
- Hooks - Automate quality checks
- Plumbing - Repository maintenance scripts
Safety Guidelines
- Backup before rewriting history - Always have recovery plan
- Don't rewrite shared history - Avoid force push to shared branches
- Test advanced operations - Practice on test repositories
- Document complex workflows - Help team understand processes
- Use version control for scripts - Track hook and tool changes
Advanced Workflow Integration
# Automated workflow script
#!/bin/bash
# advanced-workflow.sh
# Sync with upstream
git fetch upstream
git rebase upstream/main
# Interactive cleanup
git rebase -i HEAD~$(git rev-list --count HEAD ^upstream/main)
# Run tests
npm test || exit 1
# Push to feature branch
git push --force-with-lease origin feature-branch
# Create pull request
gh pr create --title "Feature: $(git log -1 --format='%s')" \
--body "$(git log upstream/main..HEAD --format='- %s')"
Advanced Git Aliases
Complex Aliases
# Advanced log formats
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"
# Work in progress
git config --global alias.wip '!git add -A && git commit -m "WIP: $(date)"'
git config --global alias.unwip '!git reset --soft HEAD~1'
# Sync with upstream
git config --global alias.sync '!git fetch upstream && git rebase upstream/main'
# Find commits
git config --global alias.find '!git log --all --grep="$1" --oneline #'
# Show contributors
git config --global alias.contributors 'shortlog -sn'
# Clean merged branches
git config --global alias.cleanup '!git branch --merged | grep -v "\\*\\|main\\|develop" | xargs -n 1 git branch -d'
Workflow Aliases
# Feature branch workflow
git config --global alias.feature '!git checkout main && git pull origin main && git checkout -b feature/$1 #'
git config --global alias.finish '!git checkout main && git pull origin main && git merge --no-ff feature/$1 && git branch -d feature/$1 #'
# Release workflow
git config --global alias.release '!git checkout main && git pull origin main && git checkout -b release/$1 && git push -u origin release/$1 #'
# Hotfix workflow
git config --global alias.hotfix '!git checkout main && git pull origin main && git checkout -b hotfix/$1 #'
See Configuration for setting up these advanced features and Integration for incorporating them into your development workflow.