Skip to content

Git Advanced Operations

This chapter introduces advanced Git features and techniques, including rebase, stash, submodule, hooks, and more, helping you use Git more efficiently.

Git Rebase Explained

What is Rebase?

Rebase is the operation of reapplying a series of commits on top of another base commit. It can create a cleaner project history.

Before Rebase:
A---B---C  (main)
     \
      D---E  (feature)

After Rebase:
A---B---C---D'---E'  (feature)

Basic Rebase Operations

bash
# Rebase current branch onto main
git rebase main

# Rebase feature branch onto main
git rebase main feature

# Interactive rebase
git rebase -i HEAD~3

# Continue rebase (after resolving conflicts)
git rebase --continue

# Skip current commit
git rebase --skip

# Abort rebase
git rebase --abort

Demonstrating Rebase Operations

bash
# Create demo environment
mkdir git-rebase-demo
cd git-rebase-demo
git init

# Create commits on main branch
echo "Main branch file 1" > main1.txt
git add main1.txt
git commit -m "Main commit 1"

echo "Main branch file 2" > main2.txt
git add main2.txt
git commit -m "Main commit 2"

# Create feature branch
git checkout -b feature
echo "Feature file 1" > feature1.txt
git add feature1.txt
git commit -m "Feature commit 1"

echo "Feature file 2" > feature2.txt
git add feature2.txt
git commit -m "Feature commit 2"

# Add new commit on main branch
git checkout main
echo "Main branch file 3" > main3.txt
git add main3.txt
git commit -m "Main commit 3"

# Rebase feature branch onto latest main branch
git checkout feature
git rebase main

# View history
git log --oneline --graph

Interactive Rebase

Interactive rebase allows you to modify commit history:

bash
# Start interactive rebase
git rebase -i HEAD~3

You can perform the following operations in the editor:

  • pick: Use commit
  • reword: Edit commit message
  • edit: Use commit, but stop for amending
  • squash: Use commit, but meld into previous commit
  • fixup: Like "squash", but discard this commit's log message
  • drop: Remove commit
bash
# Example: Squash last 3 commits
git rebase -i HEAD~3

# Modify in editor:
pick abc1234 First commit
squash def5678 Second commit
squash ghi9012 Third commit

Rebase vs Merge

bash
# Merge preserves branch history
git checkout main
git merge feature

# Rebase creates linear history
git checkout feature
git rebase main
git checkout main
git merge feature  # This will be a fast-forward merge

Git Stash Explained

What is Stash?

Stash allows you to temporarily save changes in your working directory and staging area, so you can quickly switch branches or pull updates.

Basic Stash Operations

bash
# Save current changes
git stash

# Save with description
git stash push -m "Temporarily save login feature"

# View stash list
git stash list

# Apply latest stash
git stash pop

# Apply specific stash
git stash apply stash@{1}

# Drop stash
git stash drop stash@{0}

# Clear all stashes
git stash clear

Demonstrating Stash Operations

bash
# Make some changes
echo "Feature in progress" > work_in_progress.txt
echo "Modifying existing file" >> existing_file.txt

# Add to staging area
git add work_in_progress.txt

# Save to stash
git stash push -m "Save feature in progress"

# View stash
git stash list

# Switch branch to handle urgent issue
git checkout -b hotfix
echo "Urgent fix" > hotfix.txt
git add hotfix.txt
git commit -m "Urgent fix"

# Return to original branch and restore work
git checkout main
git stash pop

# Continue development
git add .
git commit -m "Complete feature development"

Advanced Stash Operations

bash
# Stash only working directory changes, keep index (staging area)
git stash --keep-index

# Include untracked files
git stash -u

# Include ignored files
git stash -a

# Interactive stash
git stash -p

# Create branch from stash
git stash branch new-feature stash@{0}

# View stash content
git stash show stash@{0}
git stash show -p stash@{0}  # Show detailed diff

Git Submodule

What is Submodule?

Submodule allows you to keep a Git repository as a subdirectory of another Git repository.

Adding Submodule

bash
# Add submodule
git submodule add https://github.com/user/repo.git path/to/submodule

# Add submodule from specific branch
git submodule add -b branch-name https://github.com/user/repo.git path/to/submodule

# Commit submodule configuration
git add .gitmodules path/to/submodule
git commit -m "Add submodule"

Cloning Repository with Submodules

bash
# Clone main repository
git clone https://github.com/user/main-repo.git

# Initialize and update submodule
git submodule init
git submodule update

# Or do it all at once
git clone --recursive https://github.com/user/main-repo.git

# Or after cloning
git submodule update --init --recursive

Updating Submodule

bash
# Enter submodule directory to update
cd path/to/submodule
git pull origin main

# Update submodule in main repository
git submodule update --remote

# Update specific submodule
git submodule update --remote path/to/submodule

# Commit submodule update
git add path/to/submodule
git commit -m "Update submodule"

Demonstrating Submodule Operations

bash
# Create main project
mkdir main-project
cd main-project
git init

# Create a sub-project (simulate external library)
mkdir ../library
cd ../library
git init
echo "Library functions" > lib.js
git add lib.js
git commit -m "Initial library commit"

# Return to main project, add submodule
cd ../main-project
git submodule add ../library lib

# View status
git status
cat .gitmodules

# Commit submodule configuration
git add .
git commit -m "Add library as submodule"

# Make changes in submodule
cd lib
echo "New feature" >> lib.js
git add lib.js
git commit -m "Add new feature"

# Update submodule reference in main project
cd ..
git add lib
git commit -m "Update library to latest version"

Git Hooks

What are Hooks?

Hooks are scripts that are automatically executed when specific Git events occur.

Common Hooks

bash
# Client-side hooks (in .git/hooks/ directory)
pre-commit      # Executed before commit
prepare-commit-msg  # Executed when preparing commit message
commit-msg      # Executed to validate commit message
post-commit     # Executed after commit
pre-push        # Executed before push

# Server-side hooks
pre-receive     # Executed before receiving push
update          # Executed when updating references
post-receive    # Executed after receiving push

Creating Pre-commit Hook

bash
# Create pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash

# Check code style
echo "Checking code style..."

# Check JavaScript files
js_files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$')
if [ -n "$js_files" ]; then
    echo "Checking JavaScript files: $js_files"
    # Can add ESLint check here
    # eslint $js_files
fi

# Check Python files
py_files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.py$')
if [ -n "$py_files" ]; then
    echo "Checking Python files: $py_files"
    # Can add flake8 check here
    # flake8 $py_files
fi

# Check if commit contains debug code
if git diff --cached | grep -E "(console\.log|debugger|pdb\.set_trace)"; then
    echo "Error: Commit contains debug code"
    exit 1
fi

echo "Code check passed"
exit 0
EOF

# Make script executable
chmod +x .git/hooks/pre-commit

Creating Commit-msg Hook

bash
# Create commit-msg hook to validate commit message format
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/bash

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 should be: type(scope): description"
    echo "Types: feat, fix, docs, style, refactor, test, chore"
    echo "Example: feat(auth): Add user login function"
    exit 1
fi
EOF

chmod +x .git/hooks/commit-msg

Demonstrating Hooks Usage

bash
# Test pre-commit hook
echo "console.log('debug');" > debug.js
git add debug.js
git commit -m "Add debug code"  # Should be blocked

# Remove debug code
echo "function hello() { return 'Hello World'; }" > debug.js
git add debug.js
git commit -m "feat: Add hello function"  # Should succeed

# Test invalid commit message format
git commit --allow-empty -m "Wrong format"  # Should be blocked

# Correct commit message format
git commit --allow-empty -m "docs: Update README"  # Should succeed

Git Worktree

What is Worktree?

Worktree allows you to check out multiple branches of the same repository into different directories simultaneously.

Worktree Operations

bash
# Create new worktree
git worktree add ../feature-branch feature-branch

# Create worktree for new branch
git worktree add -b new-feature ../new-feature

# List all worktrees
git worktree list

# Remove worktree
git worktree remove ../feature-branch

# Prune invalid worktrees
git worktree prune

Demonstrating Worktree Usage

bash
# Work in main directory
pwd  # /path/to/main-project

# Create worktree for feature branch
git worktree add ../feature-work feature-branch

# Now can work in two directories simultaneously
cd ../feature-work
# Develop feature branch here

# Return to main directory
cd ../main-project
# Handle main branch work here

# View all worktrees
git worktree list

Git Bisect

What is Bisect?

Bisect uses binary search to help you find the commit that introduced a bug.

Bisect Operations

bash
# Start bisect
git bisect start

# Mark current commit as bad
git bisect bad

# Mark known good commit
git bisect good commit_hash

# Git will automatically switch to the middle commit
# Mark result after testing
git bisect good  # or git bisect bad

# Continue until problem commit is found
# End bisect
git bisect reset

Automating Bisect

bash
# Use script to automate testing
git bisect start HEAD v1.0
git bisect run ./test_script.sh

# Example test_script.sh
#!/bin/bash
make test
exit $?  # Return 0 means good, non-0 means bad

Git Filter-branch and Filter-repo

Rewriting History

bash
# Remove file from history (using filter-branch)
git filter-branch --tree-filter 'rm -f passwords.txt' HEAD

# Using git-filter-repo (Recommended)
pip install git-filter-repo
git filter-repo --path passwords.txt --invert-paths

# Rewrite author information
git filter-repo --mailmap mailmap.txt

# mailmap.txt format:
# New Name <new@email.com> Old Name <old@email.com>

Advanced Configuration and Aliases

Useful Git Aliases

bash
# Set advanced aliases
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit

# Complex aliases
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'

# Find alias
git config --global alias.find '!git ls-files | xargs grep -l'

# Count alias
git config --global alias.count 'shortlog -sn'

# Cleanup alias
git config --global alias.cleanup '!git branch --merged | grep -v "\\*\\|main\\|master" | xargs -n 1 git branch -d'

Advanced Configuration

bash
# Set default editor
git config --global core.editor "code --wait"

# Set diff tool
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'

# Set merge tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

# Auto-correct typos
git config --global help.autocorrect 1

# Set push policy
git config --global push.default simple

# Enable rerere (reuse recorded resolution)
git config --global rerere.enabled true

# Set long path support (Windows)
git config --global core.longpaths true

Performance Optimization

Large Repository Optimization

bash
# Shallow clone
git clone --depth 1 <url>

# Partial clone
git clone --filter=blob:none <url>

# Sparse checkout
git config core.sparseCheckout true
echo "src/" > .git/info/sparse-checkout
git read-tree -m -u HEAD

# Garbage collection
git gc --aggressive --prune=now

# Repack
git repack -ad

# Clean untracked files
git clean -fd

Network Optimization

bash
# Set proxy
git config --global http.proxy http://proxy.company.com:8080

# Increase buffer size
git config --global http.postBuffer 524288000

# Enable parallel transfer
git config --global http.maxRequestBuffer 100M
git config --global http.threads 5

Troubleshooting and Debugging

Git Debugging Tips

bash
# Enable verbose output
GIT_TRACE=1 git status
GIT_TRACE_PACKET=1 git push
GIT_TRACE_PERFORMANCE=1 git log

# Check repository integrity
git fsck --full

# View object info
git cat-file -t commit_hash  # View object type
git cat-file -p commit_hash  # View object content

# View references
git show-ref

# View config
git config --list --show-origin

Common Issues Resolution

bash
# Issue 1: Push rejected
git pull --rebase origin main
git push origin main

# Issue 2: Merge conflict
git status
git mergetool
git commit

# Issue 3: Detached HEAD state
git checkout -b new-branch
git checkout main
git merge new-branch

# Issue 4: File permission issue
git config core.filemode false

# Issue 5: Line ending issue
git config core.autocrlf true  # Windows
git config core.autocrlf input # macOS/Linux

Summary

Key points of Git Advanced Operations:

Important Tools

bash
rebase    # Rewrite history, create linear commits
stash     # Temporarily save changes
submodule # Manage sub-projects
hooks     # Automate workflows
worktree  # Parallel work on multiple branches
bisect    # Binary search for issues

Best Practices

  • ✅ Use rebase to maintain clean history
  • ✅ Utilize stash to switch tasks flexibly
  • ✅ Automate checks via hooks
  • ✅ Manage dependencies reasonably with submodule
  • ✅ Configure useful aliases to improve efficiency

Performance Optimization

  • 🚀 Shallow clone large repositories
  • 🚀 Use sparse checkout
  • 🚀 Regular garbage collection
  • 🚀 Optimize network configuration

After mastering these advanced operations, you will be able to:

  • 🔧 Efficiently manage complex project history
  • ⚡ Automate common workflows
  • 🎯 Quickly locate and resolve issues
  • 📈 Optimize Git usage performance

In the next chapter, we will learn Git Best Practices.

Content is for learning and research only.