Skip to main content

Git Troubleshooting Guide

Solutions to common Git problems you'll encounter during daily development work.

Overview

This guide provides practical solutions to Git problems organized by scenario. Each solution includes step-by-step commands and explanations.

When to Ask for Help

If you're unsure about a solution, especially one involving --force or reset --hard, ask a teammate first. It's better to ask than to lose work!


Merge Conflicts

Understanding Merge Conflicts

Merge conflicts occur when Git's three-way merge algorithm cannot automatically resolve differences. The algorithm compares three commits: the common ancestor (merge base), your current branch (HEAD), and the incoming branch. If both branches modified the same lines differently since the common ancestor, Git cannot determine which change to keep and marks the file with conflict markers. Git uses content-based merging at the line level, so even changes to different parts of the same line will conflict.

Conflict markers in files:

<<<<<<< HEAD (Current Change)
public void processPayment(Payment payment) {
validatePayment(payment);
// ... existing code ...
=======
public void processPayment(PaymentRequest payment) {
validateRequest(payment);
// ... incoming code ...
>>>>>>> feature/JIRA-1234 (Incoming Change)
}

Resolving Merge Conflicts During Pull

Scenario: Conflicts when pulling latest develop

$ git pull origin develop
Auto-merging src/services/PaymentService.java
CONFLICT (content): Merge conflict in src/services/PaymentService.java
Automatic merge failed; fix conflicts and then commit the result.

Solution:

# 1. Check which files have conflicts
git status
# Output shows: "both modified: src/services/PaymentService.java"

# 2. Open conflicted file in editor
# Look for conflict markers: <<<<<<<, =======, >>>>>>>

# 3. Resolve conflicts manually
# Choose HEAD (your changes), incoming changes, or combine both
# Remove conflict markers

# 4. After fixing all conflicts, stage resolved files
git add src/services/PaymentService.java

# 5. Complete the merge
git commit -m "Merge branch 'develop' into feature/JIRA-1234

Resolved conflicts in PaymentService:
- Kept new validation logic from both branches
- Combined payment processing improvements"

# 6. Push the merge
git push origin feature/JIRA-1234-add-payment-retry

Resolving Conflicts During Rebase

Scenario: Conflicts when rebasing on develop

$ git rebase develop
CONFLICT (content): Merge conflict in src/services/PaymentService.java
error: could not apply abc1234... feat(payments): add retry logic

Solution:

# 1. Check current status
git status
# Shows current rebase state and conflicted files

# 2. Resolve conflicts in the file (same as above)

# 3. Stage resolved files
git add src/services/PaymentService.java

# 4. Continue rebase (NOT git commit!)
git rebase --continue

# 5. If more conflicts, repeat steps 2-4
# If all resolved, rebase completes automatically

# 6. Force push (your feature branch only!)
git push --force-with-lease origin feature/JIRA-1234-add-payment-retry

Abort rebase if needed:

# Cancel rebase and return to state before rebase started
git rebase --abort

Accepting All Changes from One Side

Take all changes from develop (theirs):

# During merge
git checkout --theirs src/services/PaymentService.java
git add src/services/PaymentService.java

# During rebase
git checkout --theirs src/services/PaymentService.java
git add src/services/PaymentService.java
git rebase --continue

Keep all your changes (ours):

# During merge
git checkout --ours src/services/PaymentService.java
git add src/services/PaymentService.java

# During rebase
git checkout --ours src/services/PaymentService.java
git add src/services/PaymentService.java
git rebase --continue

Using Merge Tool

# Configure merge tool (one-time setup)
git config --global merge.tool vimdiff
# Or: meld, kdiff3, p4merge, etc.

# Launch merge tool for conflicts
git mergetool

# After resolving, clean up backup files
rm *.orig

# Complete merge/rebase
git commit # for merge
git rebase --continue # for rebase

Conflict Resolution Decision Tree


Committed to Wrong Branch

Scenario 1: Committed to develop Instead of Feature Branch

Problem:

$ git branch
* develop # Oh no! Should be on feature branch

$ git log --oneline -1
abc1234 feat(payments): add new feature # This commit shouldn't be here

Solution (if NOT yet pushed):

# 1. Create feature branch from current state
git checkout -b feature/JIRA-1234-add-feature

# 2. Go back to develop
git checkout develop

# 3. Remove commit from develop (moves HEAD back one commit)
git reset --hard HEAD~1

# 4. Verify develop is clean
git log --oneline -1

# 5. Return to feature branch (has your commit)
git checkout feature/JIRA-1234-add-feature

# 6. Push feature branch
git push -u origin feature/JIRA-1234-add-feature

Solution (if ALREADY pushed to develop):

# 1. Create feature branch with the commit
git checkout -b feature/JIRA-1234-add-feature

# 2. Push feature branch
git push -u origin feature/JIRA-1234-add-feature

# 3. Go back to develop and revert
git checkout develop
git revert HEAD
git push origin develop

# Note: This creates a revert commit in develop
# Your actual feature will be merged properly via MR later

Scenario 2: Committed to Wrong Feature Branch

Solution using cherry-pick:

# 1. Note the commit hash
git log --oneline -1
# Output: abc1234 feat(payments): add validation

# 2. Switch to correct branch
git checkout feature/JIRA-1234-correct-feature

# 3. Cherry-pick the commit
git cherry-pick abc1234

# 4. Go back to wrong branch
git checkout feature/JIRA-9999-wrong-feature

# 5. Remove the commit
git reset --hard HEAD~1

# 6. Push both branches
git checkout feature/JIRA-1234-correct-feature
git push origin feature/JIRA-1234-correct-feature

git checkout feature/JIRA-9999-wrong-feature
git push --force-with-lease origin feature/JIRA-9999-wrong-feature

Undoing Commits

Undo Last Commit (Not Yet Pushed)

Keep changes in working directory:

# Undo commit, keep changes unstaged
git reset HEAD~1

# Or keep changes staged
git reset --soft HEAD~1

# Make corrections, then recommit
git add .
git commit -m "feat(payments): corrected implementation"

Discard changes completely:

# DANGEROUS: Permanently deletes changes
git reset --hard HEAD~1

Undo Multiple Commits

# Undo last 3 commits, keep changes
git reset HEAD~3

# Undo to specific commit
git reset <commit-hash>

# Example: Reset to state before feature work
git reset abc1234

Undo Commit After Pushing

Use revert (creates new commit):

# Revert last commit
git revert HEAD

# Revert specific commit
git revert abc1234

# Push the revert
git push origin feature/JIRA-1234-add-payment-retry

Example revert commit message:

git revert abc1234 -m "revert: undo payment retry feature

Production issues with external gateway timeout.
Will reintroduce after configuration fixes.

Related to JIRA-1234"
Reset vs Revert

Understanding the fundamental difference between reset and revert is critical for safe Git operations:

  • Reset: Moves the branch pointer backward, effectively "deleting" commits from history. Technically, the commits still exist temporarily (accessible via reflog) but are orphaned - no branch references them. Git's garbage collector will eventually permanently delete these unreachable commits (after ~90 days). Use only on unpushed commits to avoid desynchronizing team members' local copies.

  • Revert: Creates a new commit with inverse changes that undo a previous commit. The original commit remains in history unchanged. This preserves the complete audit trail, which is essential for compliance and understanding how bugs were introduced and fixed. Safe for pushed commits because it adds history rather than rewriting it.

Never reset commits that others might have pulled! If teammate Alice has commits A-B-C and you reset to remove C, Alice's next push will re-introduce C, creating confusion. Reset forces everyone to reset their copies or create divergent histories.


Rebasing Issues

Branch Has Diverged After Rebase

Problem:

$ git push origin feature/JIRA-1234
! [rejected] feature/JIRA-1234 -> feature/JIRA-1234 (non-fast-forward)
error: failed to push some refs

Solution:

# Force push with safety check
git push --force-with-lease origin feature/JIRA-1234

# If force-with-lease fails (someone else pushed):
# 1. Pull their changes first
git pull origin feature/JIRA-1234

# 2. Then push
git push origin feature/JIRA-1234

Lost Commits After Rebase

Solution using reflog:

# 1. View reflog to find lost commit
git reflog
# Output shows:
# abc1234 HEAD@{0}: rebase finished
# def5678 HEAD@{1}: commit: feat(payments): lost feature
# ...

# 2. Create new branch from lost commit
git checkout -b feature/JIRA-1234-recovered def5678

# Or cherry-pick specific commit
git checkout feature/JIRA-1234
git cherry-pick def5678

Rebase Keeps Showing Same Conflict

Problem: Conflict appears for multiple commits during rebase

Solution:

# Option 1: Resolve conflict for each commit
# (tedious if conflict appears many times)

# Option 2: Abort and use merge instead
git rebase --abort
git merge develop

# Option 3: Squash commits first, then rebase
git rebase -i HEAD~5 # Interactive rebase
# Mark commits as 'squash' to combine them
# Then rebase on develop
git rebase develop

Branch Management Issues

Can't Delete Branch

Problem:

$ git branch -d feature/JIRA-1234
error: The branch 'feature/JIRA-1234' is not fully merged.

Solution:

# Check if branch is actually merged
git branch --merged develop | grep feature/JIRA-1234

# If merged but Git doesn't recognize it (after rebase):
git branch -D feature/JIRA-1234 # Force delete

# If not merged and you want to keep it:
# Don't delete! Push to remote first
git push origin feature/JIRA-1234

Accidentally Deleted Branch

Solution using reflog:

# 1. Find the deleted branch in reflog
git reflog | grep "feature/JIRA-1234"
# Output: abc1234 HEAD@{5}: checkout: moving from feature/JIRA-1234 to develop

# 2. Recreate branch at that commit
git checkout -b feature/JIRA-1234 abc1234

# 3. Push to remote
git push -u origin feature/JIRA-1234

Can't Switch Branches (Uncommitted Changes)

Problem:

$ git checkout develop
error: Your local changes to the following files would be overwritten by checkout:
src/services/PaymentService.java
Please commit your changes or stash them before you switch branches.

Solution 1: Stash changes:

git stash save "WIP: payment validation"
git checkout develop
# ... do work on develop ...
git checkout feature/JIRA-1234
git stash pop

Solution 2: Commit changes:

git add .
git commit -m "WIP: payment validation (incomplete)"
git checkout develop

Solution 3: Force checkout (DANGEROUS - loses changes):

git checkout -f develop

Remote Repository Issues

Push Rejected (Non-Fast-Forward)

Problem:

$ git push origin develop
! [rejected] develop -> develop (non-fast-forward)

Solution:

# 1. Pull latest changes
git pull origin develop

# 2. Resolve any conflicts if they occur

# 3. Push again
git push origin develop

Can't Pull (Uncommitted Changes)

Problem:

$ git pull origin develop
error: Your local changes to the following files would be overwritten by merge:
src/services/PaymentService.java

Solution:

# Option 1: Stash, pull, pop
git stash
git pull origin develop
git stash pop

# Option 2: Commit first
git add .
git commit -m "WIP: save before pull"
git pull origin develop

Remote Branch Deleted But Still Shows Locally

Problem:

$ git branch -r
# Shows: origin/feature/JIRA-1234 (but it's deleted on GitLab)

Solution:

# Prune remote tracking branches
git fetch --prune origin

# Or set to always prune
git config --global fetch.prune true

Wrong Remote URL

Problem: Pushing to wrong repository

Solution:

# Check current remote
git remote -v

# Update remote URL
git remote set-url origin [email protected]:company/correct-repo.git

# Verify
git remote -v

File and Change Issues

Accidentally Added Files

Before commit:

# Unstage specific file
git reset HEAD src/config/secrets.properties

# Unstage all files
git reset HEAD

After commit but before push:

# Remove file from commit but keep in working directory
git rm --cached src/config/secrets.properties
git commit --amend --no-edit

After pushing (sensitive data!):

# URGENT: Remove sensitive data from history
# Use BFG Repo-Cleaner or git-filter-repo

# Quick fix for recent commit:
git rm src/config/secrets.properties
git commit -m "fix: remove accidentally committed secrets"
git push origin feature/JIRA-1234

# Then rotate/invalidate the exposed secrets immediately!
Leaked Secrets

If you accidentally commit secrets (passwords, API keys, tokens), act immediately - Git commits are immutable and distributed:

  1. Remove from Git history immediately: Use git filter-repo or BFG Repo-Cleaner to rewrite all commits that touched the secret file. Simple git rm is insufficient because the secret remains in commit history accessible via git log -p or git show <old-commit>.

  2. Rotate/invalidate the secrets: Even after removal from Git, assume the secret was compromised. If pushed to GitLab, the secret existed in the remote repository (potentially cached, backed up, or accessed by automated scanners). Immediately regenerate the secret in the source system (database passwords, API keys, etc.).

  3. Notify security team: Security must assess if logs, backups, or monitoring systems captured the exposed secret. They can also check for unauthorized access attempts using the leaked credential.

  4. Update secret management practices: Implement pre-commit hooks to scan for secrets (tools like git-secrets or trufflehog), use environment variables instead of hardcoded secrets, and adopt secret management tools (Vault, AWS Secrets Manager).

Assume compromised secrets are already exposed! Git history is public once pushed, and automated bots scan public repositories for secrets within minutes of commit.

Committed Wrong Files

Solution:

# Undo commit, keep changes
git reset --soft HEAD~1

# Unstage wrong files
git reset HEAD wrong-file.txt

# Commit correct files
git add correct-file.txt
git commit -m "feat(payments): add validation"

# Handle wrong files
git stash # or git checkout -- wrong-file.txt

Case Sensitivity Issues (Renamed Files)

Problem: Renamed PaymentService.javapaymentService.java but Git doesn't detect

Solution:

# Force Git to recognize case change
git mv --force PaymentService.java paymentService.java
git commit -m "refactor: rename PaymentService file to fix case"

History and Log Issues

Find When Bug Was Introduced

Git bisect performs binary search through commit history to identify which commit introduced a bug. Instead of testing every commit linearly (O(n) complexity), bisect divides the commit range in half with each test, achieving O(log n) complexity. For example, finding the culprit in 1000 commits requires only ~10 tests instead of potentially 500 tests with linear search. Bisect maintains a range of "known good" and "known bad" commits, checking out the midpoint commit for testing, then narrowing the range based on your good/bad feedback.

Use git bisect (binary search):

# 1. Start bisect
git bisect start

# 2. Mark current commit as bad
git bisect bad

# 3. Mark last known good commit
git bisect good v1.4.0 # or commit hash

# 4. Git checks out middle commit
# Test if bug exists:
# - If bug exists: git bisect bad
# - If no bug: git bisect good

# 5. Repeat until Git finds the culprit commit
# Output: "abc1234 is the first bad commit"

# 6. End bisect
git bisect reset

# 7. Investigate the bad commit
git show abc1234

Automated bisect:

# Use script to automatically test each commit
git bisect start HEAD v1.4.0
git bisect run npm test # or any command that exits 0 if good

Find Who Changed a Line

# Show who last modified each line
git blame src/services/PaymentService.java

# Show changes for specific line range
git blame -L 50,75 src/services/PaymentService.java

# Ignore whitespace changes
git blame -w src/services/PaymentService.java

View File from Previous Commit

# View file as it was in specific commit
git show abc1234:src/services/PaymentService.java

# View file from previous commit
git show HEAD~1:src/services/PaymentService.java

# View file from specific tag
git show v1.4.0:src/services/PaymentService.java

Performance Issues

Slow Git Operations

Solution 1: Garbage collection:

# Clean up unnecessary files and optimize repository
git gc --aggressive --prune=now

Solution 2: Reduce repository size:

# Find large files in history
git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| sort -n -k 3 \
| tail -20

# Remove large files from history (use with caution!)
# Consider using BFG Repo-Cleaner

Solution 3: Shallow clone:

# Clone only recent history (faster for large repos)
git clone --depth 50 [email protected]:company/repo.git

# Later, fetch full history if needed
git fetch --unshallow

Large .git Folder

Solution:

# Check .git folder size
du -sh .git

# Clean up
git gc --aggressive --prune=now
git repack -ad

# Remove old reflog entries
git reflog expire --expire=30.days.ago --all
git gc --prune=now

Submodule Issues

Submodule Not Updated

Problem: Pulled repo but submodule still shows old commit

Solution:

# Initialize and update all submodules
git submodule update --init --recursive

# Or update specific submodule
git submodule update --init path/to/submodule

Changes in Submodule Not Showing

Solution:

# Update submodule to latest
cd path/to/submodule
git fetch origin
git checkout main
git pull origin main

# Go back to main repo
cd ../..

# Commit submodule update
git add path/to/submodule
git commit -m "chore: update submodule to latest"
git push origin feature/JIRA-1234

Configuration Issues

Wrong Author Name/Email

Fix for last commit:

# Change author of last commit
git commit --amend --author="Jane Doe <[email protected]>" --no-edit
git push --force-with-lease origin feature/JIRA-1234

Fix globally:

# Set correct author for future commits
git config --global user.name "Jane Doe"
git config --global user.email "[email protected]"

# Verify
git config --global user.name
git config --global user.email

Fix for multiple commits:

# Interactive rebase to change author
git rebase -i HEAD~3
# Mark commits as 'edit'
# For each commit:
git commit --amend --author="Jane Doe <[email protected]>" --no-edit
git rebase --continue

Line Ending Issues (Windows/Mac/Linux)

Configure globally:

# Windows
git config --global core.autocrlf true

# Mac/Linux
git config --global core.autocrlf input

# Force checkout with correct line endings
git rm --cached -r .
git reset --hard

Emergency Procedures

Completely Messed Up - Start Fresh

Solution:

# 1. Backup current work
cp -r project-dir project-dir-backup

# 2. Check what's committed vs uncommitted
git status
git diff > uncommitted-changes.patch
git stash

# 3. Delete local branch and recreate from remote
git fetch origin
git checkout develop
git branch -D feature/JIRA-1234
git checkout -b feature/JIRA-1234 origin/feature/JIRA-1234

# 4. Re-apply uncommitted changes if needed
git apply uncommitted-changes.patch
# or
git stash pop

Recover Lost Commits (Reflog)

The reflog (reference log) records every time HEAD or branch refs change in your local repository, independent of the commit graph. Unlike regular Git history which follows parent-child commit relationships, reflog is a chronological log of where HEAD has pointed. This includes commits that are no longer reachable from any branch (orphaned commits), making reflog essential for recovering "lost" work. Each reflog entry has a timestamp and is stored in .git/logs/refs/. Git garbage collection eventually removes reflog entries older than 90 days (configurable via gc.reflogExpire).

Reflog shows all actions on repository:

# View reflog
git reflog

# Output:
# abc1234 HEAD@{0}: commit: feat(payments): add validation
# def5678 HEAD@{1}: checkout: moving from develop to feature
# 1234567 HEAD@{2}: commit: fix(auth): token expiration
# ...

# Recover lost commit
git checkout -b recovery-branch abc1234

# Or cherry-pick
git cherry-pick abc1234
Reflog Retention

Reflog entries expire after 90 days by default. Don't rely on reflog for long-term recovery!

Repository Corrupted

Solution:

# 1. Check for corruption
git fsck --full

# 2. If errors found, try recovery
git fsck --full --no-dangling

# 3. If still corrupted, clone fresh and cherry-pick your work
cd ..
git clone [email protected]:company/repo.git repo-fresh
cd repo-fresh
git cherry-pick <your-commits>

Preventive Measures

Avoid Common Mistakes

Enable helpful warnings:

# Warn before pushing to main/develop
git config --global alias.push-check '!git rev-parse --abbrev-ref HEAD | grep -qE "^(main|develop)$" && echo "Warning: Pushing to protected branch!" || true && git push'

# Use push-check instead of push
git push-check origin feature-branch

Set up pre-commit hooks:

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

# Prevent commits to main/develop
branch="$(git rev-parse --abbrev-ref HEAD)"
if [ "$branch" = "main" ] || [ "$branch" = "develop" ]; then
echo "ERROR: Direct commits to $branch are not allowed!"
echo "Create a feature branch instead."
exit 1
fi

# Check for debug statements
if git diff --cached | grep -E 'console\.log|debugger|TODO|FIXME'; then
echo "WARNING: Debug statements found in commit!"
read -p "Commit anyway? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi

Enable commit signing:

# Configure GPG signing
git config --global user.signingkey <your-gpg-key>
git config --global commit.gpgsign true

Diagnostic Commands

Check Repository Health

# Verify repository integrity
git fsck --full

# Check for uncommitted changes
git status

# View recent actions
git reflog -10

# Check remote configuration
git remote -v

# List all branches and their tracking
git branch -vv

Debug Git Commands

# Show detailed output of Git command
GIT_TRACE=1 git pull origin develop

# Debug network issues
GIT_CURL_VERBOSE=1 git fetch origin

# Debug SSH authentication
GIT_SSH_COMMAND="ssh -vvv" git fetch origin

Getting Help

When to Ask for Assistance

Ask a teammate if:

  • About to run git push --force on shared branch
  • Considering git reset --hard on important commits
  • Dealing with sensitive data in Git history
  • Multiple conflicts affecting many files
  • Repository appears corrupted
  • Unsure about impact of a command

Before Asking for Help

Provide context:

  1. What were you trying to do?
  2. What command did you run?
  3. What was the output/error?
  4. What is current state? (git status, git log --oneline -5)

Example help request:

I was trying to rebase my feature branch on develop.

Command: git rebase develop
Error: CONFLICT (content): Merge conflict in PaymentService.java

Current state:
$ git status
rebase in progress; onto abc1234
You are currently rebasing branch 'feature/JIRA-1234' on 'abc1234'.

I'm not sure how to resolve the conflict without breaking things.
Can someone help?

Further Reading

External Resources


Summary

Key Takeaways:

  1. Merge conflicts: Resolve manually, test thoroughly before completing merge
  2. Wrong branch: Use cherry-pick to move commits; reset to remove from wrong branch
  3. Undo commits: Use reset for unpushed, revert for pushed commits
  4. Rebase issues: Abort with git rebase --abort if stuck; use reflog to recover
  5. Force push: Only on your own feature branches with --force-with-lease
  6. Lost commits: Use git reflog to find and recover
  7. Sensitive data: Remove immediately and rotate secrets
  8. Corruption: Verify with git fsck; reclone if needed
  9. Ask for help: When unsure, especially with destructive commands
  10. Preventive measures: Use pre-commit hooks and Git aliases