Skip to content
All essays
CraftMarch 27, 202414 min

Advanced Git Techniques for Power Users

Master advanced Git workflows and techniques for complex version control scenarios

Ü
Ümit Uz
Mobile & Full Stack Developer

Once you've mastered the basics of Git, there's a whole world of advanced techniques that can make you more productive and help you handle complex scenarios. This guide covers advanced Git workflows and techniques.

Interactive Rebase

Interactive rebase is one of Git's most powerful features.

Cleaning Up History

Rewrite history to clean commits:

bash
# Interactive rebase for last 5 commits
git rebase -i HEAD~5

# Commands in rebase:
# p, pick = use commit
# r, reword = use commit, edit message
# e, edit = use commit, stop for amending
# s, squash = merge with previous commit
# f, fixup = like squash, but discard log message
# d, drop = remove commit

Squashing Commits

Combine multiple commits into one:

bash
# Mark commits as squash or fixup
git rebase -i HEAD~3

# Mark the commits you want to squash with 's'
# The first commit remains, others are merged into it

Reordering Commits

Change commit order:

bash
git rebase -i HEAD~5
# Reorder commits by moving lines in the editor

Reflog and Recovery

Git keeps a log of all movements HEAD makes.

Viewing Reflog

bash
# Show reflog
git reflog

# Show reflog for specific branch
git reflog feature-branch

# Show detailed reflog
git reflog show --all

Recovering Lost Commits

bash
# Find lost commit
git reflog | grep "commit message"

# Restore lost commit
git reset --hard HEAD@{n}

# Create branch from lost commit
git branch recovered-branch HEAD@{n}

Bisect for Bug Hunting

Git bisect helps find the commit that introduced a bug.

bash
# Start bisect
git bisect start

# Mark current as bad
git bisect bad

# Mark known good version
git bisect good v1.0.0

# Git will checkout a commit halfway
# Test it, then mark as good or bad
git bisect good  # or git bisect bad

# Continue until the bad commit is found
git bisect reset  # Go back to original state

Automated Bisect

bash
# Run automated bisect with script
git bisect start HEAD v1.0.0
git bisect run npm test

Submodules and Subtrees

Managing dependencies within your repository.

Submodules

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

# Clone repo with submodules
git clone --recursive https://github.com/user/repo.git

# Update submodules
git submodule update --remote

# Remove submodule
git submodule deinit path/to/repo
git rm path/to/repo

Subtrees

bash
# Add subtree
git subtree add --prefix=libs/mylib https://github.com/user/repo.git main

# Update subtree
git subtree pull --prefix=libs/mylib https://github.com/user/repo.git main

# Push subtree changes
git subtree push --prefix=libs/mylo https://github.com/user/repo.git main

Worktrees

Work with multiple branches simultaneously.

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

# List worktrees
git worktree list

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

# Prune worktree
git worktree prune

Partial Commits and Staging

Commit only parts of your changes.

Patch Mode

bash
# Interactive staging
git add -p

# Commands in patch mode:
# y - stage this hunk
# n - don't stage this hunk
# q - quit
# a - stage this and rest of file
# d - don't stage this and rest of file
# s - split into smaller hunks
# e - edit hunk manually

Resetting Specific Files

bash
# Unstage specific file
git reset HEAD path/to/file

# Discard changes in working directory
git checkout -- path/to/file

# Restore file from specific commit
git checkout abc123 -- path/to/file

Cherry-Picking

Apply specific commits from one branch to another.

bash
# Cherry-pick a commit
git cherry-pick abc123

# Cherry-pick multiple commits
git cherry-pick abc123..def456

# Cherry-pick without committing
git cherry-pick -n abc123

# Cherry-pick with conflicts
git cherry-pick --continue
git cherry-pick --abort

Git Hooks

Automate workflows with Git hooks.

Available Hooks

typescript
interface GitHooks {
  'applypatch-msg': string;
  'commit-msg': string;
  'post-merge': string;
  'post-checkout': string;
  'post-commit': string;
  'pre-commit': string;
  'pre-push': string;
  'pre-rebase': string;
  'prepare-commit-msg': string;
}

Example Pre-Commit Hook

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

# Run linting
npm run lint

# Check if linting passed
if [ $? -ne 0 ]; then
  echo "Linting failed. Commit aborted."
  exit 1
fi

# Run tests
npm test

# Check if tests passed
if [ $? -ne 0 ]; then
  echo "Tests failed. Commit aborted."
  exit 1
fi

exit 0

Example Commit Message Hook

bash
#!/bin/bash
# .git/hooks/commit-msg

commit_regex='^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}'

if ! grep -qE "$commit_regex" "$1"; then
  echo "Aborting commit. Your commit message format is invalid."
  echo "Expected format: type(scope): description"
  echo "Example: feat(auth): add OAuth2 support"
  exit 1
fi

Shallow Clones and Sparse Checkouts

Optimize repository size and download time.

Shallow Clones

bash
# Clone only latest commit
git clone --depth 1 https://github.com/user/repo.git

# Clone with shallow history
git clone --depth 100 https://github.com/user/repo.git

# Unshallow (fetch full history)
git fetch --unshallow

Sparse Checkout

bash
# Enable sparse checkout
git config core.sparseCheckout true

# Define directories to include
echo "src/" >> .git/info/sparse-checkout
echo "package.json" >> .git/info/sparse-checkout

# Clone with sparse checkout
git clone --no-checkout https://github.com/user/repo.git
cd repo
git sparse-checkout init
git checkout main

Git Attributes

Configure Git behavior for specific files.

gitattributes
# .gitattributes

# Handle line endings
* text=auto
*.bat text eol=crlf

# Mark files as binary
*.png binary
*.jpg binary

# Git LFS
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text

# Language detection
*.jsx linguist-language=JavaScript
*.tsx linguist-language=TypeScript

Advanced Merge Strategies

Handle merge conflicts more effectively.

Merge Strategies

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

# Ours strategy (always keep our changes)
git merge -s ours feature-branch

# Theirs strategy (always take their changes)
git merge -s theirs feature-branch

# Subtree strategy
git merge -s subtree --prefix=libs/mylib feature-branch

Conflict Resolution Tools

bash
# Use merge tool
git mergetool

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

# Resolve conflicts manually
git checkout --ours path/to/file  # keep our version
git checkout --theirs path/to/file  # keep their version
git add path/to/file  # mark as resolved

Git Aliases

Create shortcuts for common commands.

bash
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.lg "log --graph --oneline --decorate --all"
git config --global alias.amend 'commit --amend --no-edit'

Performance Optimization

Make Git faster with large repositories.

Performance Tuning

bash
# Enable file system monitor
git config core.fsmonitor true

# Use packed refs
git config pack.threads 4

# Increase delta cache size
git config diff.deltacachelimit 2048

# Disable common delta compression
git config --global pack.deltaCacheSize 2048m

# Use multipack index
git config core.multiPackIndex true

Conclusion

Advanced Git techniques unlock powerful workflows for handling complex version control scenarios. Master these techniques to become more productive and handle any Git situation with confidence.

Remember that with great power comes great responsibility—especially with commands that rewrite history. Always communicate with your team before using destructive operations on shared branches.

Enjoyed this essay? Share it.

Related essays

Next essay
React Server Actions Deep Dive