Git is far more powerful than most developers realize. While most users know the basics of commit, push, and pull, mastering Git’s advanced features can significantly improve your workflow and help you recover from complex situations.

This guide covers advanced Git techniques that will help you work more efficiently, maintain cleaner histories, and collaborate more effectively with teams.

Interactive Staging

When you have multiple changes in a file but only want to commit some of them, interactive staging allows you to select specific hunks.

git add -p filename

Git will show each change and prompt you with options:

  • y - stage this hunk
  • n - skip this hunk
  • s - split into smaller hunks
  • e - manually edit the hunk
  • q - quit

This is particularly useful when you’ve made multiple unrelated changes to the same file and want to create atomic commits.

Rewriting History with Interactive Rebase

Interactive rebase is one of Git’s most powerful features. It allows you to modify commits in your branch before pushing.

git rebase -i HEAD~5

This opens an editor showing the last 5 commits:

pick abc1234 First commit
pick def5678 Second commit
pick ghi9012 Third commit

Available commands:

Command Action
pick Use commit as-is
reword Change commit message
edit Stop to amend the commit
squash Merge into previous commit
fixup Like squash but discard message
drop Remove commit entirely

Squashing Commits

To combine multiple commits into one:

pick abc1234 Add user authentication
squash def5678 Fix typo in auth
squash ghi9012 Add missing import

This creates a single, clean commit from three messy ones.

Reordering Commits

Simply change the order of lines in the editor:

pick ghi9012 Third commit
pick abc1234 First commit
pick def5678 Second commit

Be cautious when reordering commits that depend on each other.

Finding Bugs with Bisect

Git bisect performs a binary search through your commit history to find the commit that introduced a bug.

# Start bisect
git bisect start

# Mark current commit as bad
git bisect bad

# Mark a known good commit
git bisect good v1.0.0

Git will checkout commits for you to test. After each test:

# If the bug is present
git bisect bad

# If the bug is not present
git bisect good

Git will eventually identify the exact commit that introduced the bug.

Automated Bisect

If you have a test script that returns 0 for good and non-zero for bad:

git bisect start HEAD v1.0.0
git bisect run ./test-script.sh

Git will automatically run the script on each commit and find the problematic one.

Stashing Work

Stash allows you to save uncommitted changes without committing them.

# Save current changes
git stash

# Save with a message
git stash save "Work in progress on feature X"

# List all stashes
git stash list

# Apply most recent stash
git stash pop

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

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

Partial Stashing

Stash only some files:

git stash push -m "Partial stash" file1.py file2.py

Stash interactively:

git stash -p

Working with Remotes

Multiple Remotes

You can have multiple remotes for different purposes:

# Add upstream remote (original repo)
git remote add upstream https://github.com/original/repo.git

# Fetch from upstream
git fetch upstream

# Merge upstream changes
git merge upstream/main

Tracking Branches

Create a local branch that tracks a remote branch:

git checkout -b feature-branch origin/feature-branch

# Or with newer Git versions
git switch -c feature-branch origin/feature-branch

Reflog: Your Safety Net

The reflog records every change to HEAD, even ones that don’t appear in normal history.

git reflog

Output:

abc1234 HEAD@{0}: commit: Add new feature
def5678 HEAD@{1}: checkout: moving from main to feature
ghi9012 HEAD@{2}: reset: moving to HEAD~3

Recovering Lost Commits

If you accidentally reset or deleted commits:

# Find the commit in reflog
git reflog

# Recover it
git checkout -b recovery-branch abc1234

Cherry-Pick

Apply specific commits from another branch:

# Apply single commit
git cherry-pick abc1234

# Apply multiple commits
git cherry-pick abc1234 def5678

# Apply range of commits
git cherry-pick abc1234..ghi9012

Useful for backporting fixes to maintenance branches.

Worktrees

Work on multiple branches simultaneously without stashing:

# Create a new worktree
git worktree add ../project-hotfix hotfix-branch

# List worktrees
git worktree list

# Remove worktree
git worktree remove ../project-hotfix

Each worktree is a separate directory with its own working copy.

Hooks

Git hooks are scripts that run at specific points in the Git workflow.

Location: .git/hooks/

Common hooks:

Hook Trigger
pre-commit Before commit is created
commit-msg After commit message is entered
pre-push Before push to remote
post-merge After merge completes

Example: Pre-commit Hook

Create .git/hooks/pre-commit:

#!/bin/bash

# Run linter before commit
if ! npm run lint; then
    echo "Linting failed. Commit aborted."
    exit 1
fi

Make it executable:

chmod +x .git/hooks/pre-commit

Aliases

Create shortcuts for common commands in ~/.gitconfig:

[alias]
    st = status
    co = checkout
    br = branch
    ci = commit
    lg = log --oneline --graph --decorate
    unstage = reset HEAD --
    last = log -1 HEAD
    amend = commit --amend --no-edit

Usage:

git lg
git st
git amend

Cleaning Up

Remove Untracked Files

# Preview what will be deleted
git clean -n

# Delete untracked files
git clean -f

# Delete untracked files and directories
git clean -fd

# Delete ignored files too
git clean -fdx

Prune Remote Branches

# Remove references to deleted remote branches
git fetch --prune

# Or configure automatic pruning
git config --global fetch.prune true

Submodules

Include other repositories within your repository:

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

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

# Update submodules
git submodule update --remote

Best Practices

Commit Messages

Write clear, descriptive commit messages:

Short summary (50 chars or less)

More detailed explanation if necessary. Wrap at 72 characters.
Explain what and why, not how. The code shows how.

- Use bullet points for multiple changes
- Reference issues: Fixes #123

Branch Naming

Use consistent naming conventions:

feature/user-authentication
bugfix/login-error
hotfix/security-patch
release/v2.0.0

Keep History Clean

  • Squash work-in-progress commits before merging
  • Use meaningful commit messages
  • Avoid committing generated files
  • Use .gitignore properly

Troubleshooting

Undo Last Commit (keep changes)

git reset --soft HEAD~1

Undo Last Commit (discard changes)

git reset --hard HEAD~1

Fix Commit to Wrong Branch

# Save the commit hash
git log -1

# Reset current branch
git reset --hard HEAD~1

# Switch and apply
git checkout correct-branch
git cherry-pick <commit-hash>

Resolve Merge Conflicts

# See conflicting files
git status

# After resolving manually
git add resolved-file.py
git commit

Conclusion

Mastering these advanced Git techniques will make you more efficient and confident when working with version control. Practice these commands in a test repository before using them on important projects.

Key takeaways:

  1. Interactive rebase keeps history clean
  2. Bisect automates bug hunting
  3. Reflog is your safety net
  4. Hooks automate quality checks
  5. Aliases save time

The more comfortable you become with these tools, the more naturally they’ll integrate into your daily workflow.