some git stuff to remember

solutions to tricky git situations and advanced git operations that are easy to forget

History Manipulation

Interactive Rebase Operations

# Rewrite multiple commits
git rebase -i HEAD~5  # Last 5 commits

# Common operations:
# fixup - combine with previous commit, discard message
# squash - combine with previous, keep both messages
# reword - change commit message
# drop - remove commit entirely
# edit - stop for amending

# Force push with lease (safer than force push)
git push --force-with-lease  # Fails if remote has new commits

Cherry-picking and Patching

# Cherry-pick specific commits
git cherry-pick <commit-hash>  # Single commit
git cherry-pick <hash1>..<hash2>  # Range of commits

# Create patch files
git format-patch -1 HEAD  # Last commit
git format-patch -n <commit>  # Last n commits
git format-patch master..feature  # Branch differences

# Apply patches
git apply --check my.patch  # Test if patch applies
git am < my.patch  # Apply patch with commit info

Recovery Operations

Recovering Lost Work

# Find lost commits (after reset --hard)
git reflog
git checkout -b recovery-branch <hash>

# Recover deleted branch
git reflog | grep -A 1 'to <branch-name>'
git checkout -b <branch-name> <hash>

# Recover stashed changes
git fsck --unreachable | grep commit | cut -d' ' -f3 | xargs git show

Advanced Reset Operations

# Reset specific paths
git reset --hard origin/master -- path/to/file

# Clean working directory but keep specific files
git stash --keep-index
git stash drop

# Unstage parts of a file
git reset -p HEAD <file>

Advanced Workflows

Bisect for Bug Hunting

git bisect start
git bisect bad  # Current commit is broken
git bisect good <commit>  # Last known good commit

# Automate with test script
git bisect run ./test-script.sh

# After finding the culprit
git bisect reset

Worktrees for Multiple Checkouts

# Create new worktree
git worktree add ../path/to/folder branch-name

# List worktrees
git worktree list

# Remove worktree
git worktree remove ../path/to/folder

Advanced Merge Strategies

# Recursive strategy with options
git merge -X ignore-space-change feature
git merge -X theirs feature  # Prefer their changes
git merge -X patience feature  # Better handling of renamed files

# Octopus merge (multiple branches)
git merge branch1 branch2 branch3

Git Hooks and Automation

Advanced Pre-commit Configuration

# .pre-commit-config.yaml
default_language_version:
    python: python3.9
default_stages: [commit, push]
fail_fast: true

repos:
  - repo: local
    hooks:
      - id: custom-script
        name: Custom Validation
        entry: ./scripts/validate.sh
        language: script
        files: \\.py$
        stages: [commit]
        additional_dependencies: ['pytest']

  - repo: https://github.com/psf/black
    rev: 22.10.0
    hooks:
      - id: black
        args: ['--check']
        exclude: ^(venv/|docs/)

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v0.982
    hooks:
      - id: mypy
        additional_dependencies: 
          - 'types-requests'
          - 'types-PyYAML'

Custom Git Hooks

#!/bin/bash
# .git/hooks/pre-push

protected_branches=('main' 'master' 'production')
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

for branch in "${protected_branches[@]}"; do
    if [[ $current_branch = $branch ]]; then
        read -p "You're about to push to $branch, is that what you intended? [y|n] " -n 1 -r < /dev/tty
        echo
        if echo $REPLY | grep -E '^[Nn]$' > /dev/null; then
            exit 1
        fi
    fi
done
exit 0

Submodules and Subtrees

Advanced Submodule Operations

# Update specific submodule to latest
git submodule update --remote --merge specific-submodule

# Execute command in each submodule
git submodule foreach 'git checkout -b feature'

# Remove a submodule
git submodule deinit -f path/to/submodule
git rm -f path/to/submodule
rm -rf .git/modules/path/to/submodule

Git Subtree (Alternative to Submodules)

# Add subtree
git subtree add --prefix=lib/core https://github.com/org/lib.git master

# Update subtree
git subtree pull --prefix=lib/core https://github.com/org/lib.git master

# Push changes back to subtree remote
git subtree push --prefix=lib/core https://github.com/org/lib.git master

Debugging Git Issues

# Debug git commands
GIT_TRACE=1 git push origin master

# Debug specific areas
GIT_TRACE_PACKET=1  # Network operations
GIT_TRACE_PERFORMANCE=1  # Performance data
GIT_TRACE_SETUP=1  # Setup info

# Find large files in history
git rev-list --objects --all \
  | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
  | sed -n 's/^blob //p' \
  | sort -k2nr \
  | head -10

Useful Resources