Git Troubleshooting Guide: Step-by-Step Problem Resolution

The Systematic Approach to Git Troubleshooting

Git problems can be frustrating, but most have systematic solutions. This guide takes a symptom-based approachβ€”you identify what's going wrong, and we provide step-by-step diagnostic commands and solutions. From authentication failures to merge conflicts, corrupted indexes to slow performance, you'll find practical fixes for real-world problems.

Core principle: Always diagnose before fixing. Git provides extensive debugging tools (GIT_TRACE, git fsck, git remote -v show) that reveal what's actually happening. Use these to understand the problem before applying solutions.

Quick Reference: Common Error Messages

Error Message Likely Cause Quick Fix
fatal: not a git repository Not in a Git repo or .git folder corrupted Run git init or check parent directories
Permission denied (publickey) SSH key issues Check SSH agent and key permissions
! [rejected] main -> main (non-fast-forward) Remote has changes you don't have git pull first, then push
error: failed to push some refs Branch protection or divergence git pull --rebase then push
fatal: refusing to merge unrelated histories Branches with no common ancestor git merge --allow-unrelated-histories
CONFLICT (content): Merge conflict Same file changed differently Resolve conflicts manually

Diagnostic Tools: Understanding What's Wrong

1. Git Trace Mode

Enable verbose debugging to see exactly what Git is doing:

# Trace all Git operations
$ GIT_TRACE=1 git status

# Trace network operations
$ GIT_CURL_VERBOSE=1 git push
$ GIT_SSH_COMMAND="ssh -vvv" git fetch

# Trace packfile operations
$ GIT_TRACE_PACKET=1 git fetch

What to look for: The trace output shows every command Git executes internally, network requests, and where failures occur. This is invaluable for authentication and protocol issues.

2. Repository Integrity Check

# Check for corruption
$ git fsck --full

# Check for dangling objects (lost data)
$ git fsck --lost-found

# Verify packfiles
$ git verify-pack -v .git/objects/pack/*.idx

3. Remote Connection Diagnostics

# Test remote connectivity
$ git ls-remote origin

# Show remote details
$ git remote -v show origin

# Check SSH connection
$ ssh -T git@github.com # GitHub test
$ ssh -T git@gitlab.com # GitLab test

Symptom Category 1: Authentication and Access Problems

πŸ” Symptom: "Permission denied (publickey)" or "Could not read from remote repository"

Diagnosis Steps:

# 1. Check if SSH agent is running
$ eval "$(ssh-agent -s)"

# 2. List loaded keys
$ ssh-add -l

# 3. Test SSH connection
$ ssh -T git@github.com
# Expected: "Hi username! You've successfully authenticated"

# 4. Check key permissions
$ ls -la ~/.ssh/
$ chmod 600 ~/.ssh/id_rsa # Private key must be 600
$ chmod 644 ~/.ssh/id_rsa.pub # Public key can be 644

Solutions:

  1. Add your key to SSH agent: ssh-add ~/.ssh/your_key
  2. Add key to GitHub/GitLab: Copy cat ~/.ssh/id_rsa.pub to hosting service
  3. Check remote URL: git remote -v should use git@, not https://
  4. Fix remote URL: git remote set-url origin git@github.com:user/repo.git
  5. Create config file: ~/.ssh/config with Host-specific settings
# ~/.ssh/config example
Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/github_key
  IdentitiesOnly yes
πŸ” Symptom: "fatal: Authentication failed" (HTTPS)

Diagnosis:

# Check credential helper
$ git config --global credential.helper

# On macOS, check Keychain
$ git credential-osxkeychain get

# On Windows, check Credential Manager
$ cmdkey /list

Solutions:

  1. Update credential helper: git config --global credential.helper osxkeychain (macOS)
  2. Use personal access token: GitHub no longer accepts passwords
  3. Cache credentials: git config --global credential.helper 'cache --timeout=3600'
  4. Switch to SSH: git remote set-url origin git@github.com:user/repo.git

Symptom Category 2: Push/Pull Problems

πŸ“€ Symptom: "! [rejected] main -> main (non-fast-forward)"

What's happening:

The remote branch has commits you don't have locally. Git refuses to overwrite them.

Diagnosis:

# See what's on remote
$ git fetch origin
$ git log origin/main --oneline

# Compare local and remote
$ git log HEAD..origin/main --oneline # Commits you're missing

Solutions:

  1. Merge approach:
    $ git pull origin main
    $ git push origin main
  2. Rebase approach (cleaner history):
    $ git pull --rebase origin main
    $ git push origin main
  3. If you're sure you want to overwrite (use with caution):
    $ git push --force-with-lease origin main

⚠️ Never use --force on shared branches. Use --force-with-lease which checks that your local branch matches the remote before force-pushing.

πŸ“₯ Symptom: "error: Your local changes would be overwritten by merge"

What's happening:

You have uncommitted changes that conflict with incoming changes. Git protects you from losing work.

Solutions:

  1. Commit your changes (recommended):
    $ git add .
    $ git commit -m "WIP: local changes"
  2. Stash temporarily:
    $ git stash push -m "temp-work"
    $ git pull
    $ git stash pop # May cause conflicts
  3. Discard changes (careful!):
    $ git reset --hard HEAD # Loses uncommitted work

View stash contents before applying:

$ git stash list
$ git stash show -p stash@{0}
πŸ”€ Symptom: "fatal: refusing to merge unrelated histories"

What's happening:

You're trying to merge two branches that don't share a common commit. Common when merging different repositories or after --orphan branches.

Solutions:

  1. Allow unrelated histories (if intentional):
    $ git pull origin main --allow-unrelated-histories
  2. If merging different repositories:
    $ git remote add other ../other-repo
    $ git fetch other
    $ git merge other/main --allow-unrelated-histories
  3. First, verify this is what you want: Check that you're not accidentally mixing projects.

Symptom Category 3: Merge and Rebase Conflicts

βš”οΈ Symptom: "CONFLICT (content): Merge conflict in [file]"

Understanding conflict markers:

# In conflicted file:
<<<<<<< HEAD
This is your current change
=======
This is the incoming change
>>>>>>> branch-name

Step-by-step resolution:

  1. Identify conflicted files: git status
  2. Open each conflicted file in your editor
  3. Choose the correct version:
    • Keep your changes (before ======)
    • Keep their changes (after ======)
    • Combine both (edit manually)
  4. Remove conflict markers (<<<, ===, >>>)
  5. Mark as resolved: git add [file]
  6. Complete the merge: git commit

Using merge tools:

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

# Launch merge tool
$ git mergetool

Abort if things go wrong:

$ git merge --abort
$ git rebase --abort
πŸ”„ Symptom: "interactive rebase stopped" or "rebase in progress"

Common situations:

  • You're in the middle of a rebase with conflicts
  • Git shows "rebase in progress" when you try other commands

Solutions:

  1. Continue after resolving conflicts:
    $ git add [resolved-files]
    $ git rebase --continue
  2. Skip this commit:
    $ git rebase --skip
  3. Abort entirely:
    $ git rebase --abort

Symptom Category 4: Index and Working Tree Issues

πŸ“‡ Symptom: "fatal: index file corrupt" or weird git status behavior

What's happening:

The Git index (.git/index) is corrupted. This file tracks staged changes.

Solution:

# Backup current index (just in case)
$ cp .git/index .git/index.backup

# Remove corrupted index
$ rm .git/index

# Rebuild index from HEAD
$ git reset

# Restage any unstaged changes
$ git status # Check what needs re-adding
πŸ“ Symptom: "Untracked files" that should be ignored

Diagnosis:

# Check what's being ignored
$ git check-ignore -v node_modules/

# See why a file isn't being ignored
$ git status --ignored

Solutions:

  1. Update .gitignore:
    $ echo "node_modules/" >> .gitignore
    $ git add .gitignore
  2. Remove already tracked files that should be ignored:
    $ git rm -r --cached node_modules/
    $ git commit -m "Remove node_modules from git"
  3. Global gitignore for all repos:
    $ git config --global core.excludesfile ~/.gitignore_global

Symptom Category 5: Repository Corruption

πŸ’” Symptom: "error: object file is empty" or "fatal: bad object"

Diagnosis:

$ git fsck --full
error: object file .git/objects/ab/cdef123... is empty

Solutions (in order of safety):

Option 1: Restore from remote (if available)
# Backup your work first
$ cp -r . ../repo-backup

# Clone fresh copy
$ cd ..
$ git clone [remote-url] fresh-repo

# Copy over uncommitted changes
$ cp -r repo-backup/* fresh-repo/ (except .git)
Option 2: Repair from other clones
# Add healthy repo as remote
$ git remote add healthy ../healthy-repo
$ git fetch healthy

# Replace missing objects
$ git fsck --full # Check if fixed
Option 3: Manual object recovery
# Find missing objects
$ git fsck --full > missing.txt

# Try to restore from packfiles
$ git unpack-objects < .git/objects/pack/pack-[name].pack

Symptom Category 6: Performance Issues

🐒 Symptom: Git commands are very slow

Diagnosis:

# Check repository size
$ git count-objects -vH

# Find large files
$ git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | grep "^blob" | sort -k3 -n -r | head -10

Solutions:

  1. Run garbage collection:
    $ git gc --aggressive --prune=now
  2. Enable filesystem monitor:
    $ git config core.fsmonitor true
  3. Use shallow clone for CI:
    $ git clone --depth 1 [url]
  4. Move large files to Git LFS:
    $ git lfs track "*.psd"
    $ git add .gitattributes

Symptom Category 7: Hook and Script Issues

πŸ”Œ Symptom: Git hooks not executing

Diagnosis:

# Check hook permissions
$ ls -la .git/hooks/
$ chmod +x .git/hooks/pre-commit

# Test hook directly
$ .git/hooks/pre-commit

Solutions:

  1. Make hooks executable: chmod +x .git/hooks/*
  2. Check shebang line: First line should be #!/bin/sh or #!/usr/bin/env bash
  3. Bypass hooks temporarily: git commit --no-verify
  4. Use hook managers: husky for npm, pre-commit framework

Symptom Category 8: Submodule Problems

πŸ“¦ Symptom: Submodule issues (dirty, not updated, etc.)

Common submodule problems:

Problem: Submodule shows as modified but no changes
# Submodule points to different commit
$ git submodule update --init --recursive
Problem: Submodule not updating
$ git submodule foreach git pull origin main
$ git add .
$ git commit -m "Update submodules"
Problem: Cloned repo missing submodules
$ git clone --recursive [url]
# Or after clone:
$ git submodule update --init --recursive

Symptom Category 9: Environment and Configuration

βš™οΈ Symptom: Git using wrong user/email

Diagnosis:

# Check all config levels
$ git config --list --show-origin

# Check specific values
$ git config user.name
$ git config user.email

Solutions:

# Set globally
$ git config --global user.name "Your Name"
$ git config --global user.email "your@email.com"

# Set per repository
$ git config user.name "Project Specific Name"

# Override for specific directory
$ git config --global includeIf.gitdir:~/work/.path ~/.gitconfig-work

Git Troubleshooting Cheat Sheet

Problem Diagnostic Command Fix Command
Can't push git fetch; git log HEAD..origin/main git pull --rebase
Wrong author git log --pretty=full git commit --amend --reset-author
Lost commits git reflog git branch recover [hash]
SSH issues ssh -vT git@github.com ssh-add ~/.ssh/key
Merge conflicts git status Manual resolution or git mergetool
Corrupt index git fsck rm .git/index; git reset

Git Debugging Environment Variables

Variable Purpose
GIT_TRACE=1 Trace all Git commands
GIT_CURL_VERBOSE=1 Debug HTTP/HTTPS operations
GIT_SSH_COMMAND="ssh -vvv" Debug SSH connections
GIT_TRACE_PACKET=1 Debug network protocol
GIT_TRACE_PERFORMANCE=1 Debug performance issues
GIT_TRACE_SETUP=1 Debug repository discovery

Emergency Recovery Script

#!/bin/bash
# git-emergency.sh - Run when things go wrong

echo "=== GIT EMERGENCY DIAGNOSTIC ==="
echo "1. Repository status:"
git status

echo "2. Recent reflog entries:"
git reflog | head -10

echo "3. Repository integrity:"
git fsck --full

echo "4. Remote connectivity:"
git remote -v
git ls-remote origin HEAD

echo "5. Configuration:"
git config --list | head -20

echo "6. Unreachable objects:"
git fsck --unreachable | head -10

echo "7. Large files:"
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | grep "^blob" | sort -k3 -n -r | head -5
You try to push but get "! [rejected] main -> main (non-fast-forward)". What's the safest first step?
  • git fetch then git pull --rebase
  • git push --force
  • git reset --hard origin/main
  • git branch -d main and try again

Frequently Asked Questions

How do I recover from a failed rebase?

If you're in the middle of a rebase and things go wrong, you have several options:

  • Abort completely: git rebase --abort - returns to pre-rebase state
  • Skip current commit: git rebase --skip - if you want to omit this commit
  • Continue after fixes: git add . && git rebase --continue
  • If you already completed the rebase but want to undo: git reflog to find pre-rebase commit, then git reset --hard [hash]
Why does Git keep asking for my password?

This typically happens with HTTPS remotes. Solutions:

  1. Cache credentials: git config --global credential.helper cache
  2. Use credential manager: On Windows: Git Credential Manager; on macOS: osxkeychain
  3. Switch to SSH: Generate SSH key and update remote URL to git@github.com:user/repo.git
  4. Use personal access token: GitHub no longer accepts passwords; use tokens instead
How do I fix "fatal: reference is not a tree" error?

This error means Git can't find a tree object. Recovery steps:

  1. Run git fsck --full to identify missing objects
  2. If you have another clone, fetch missing objects: git remote add backup ../other-repo; git fetch backup
  3. If the missing object is in a packfile, try: git unpack-objects < .git/objects/pack/*.pack
  4. As last resort, clone fresh from remote and reapply local changes
How do I resolve "error: RPC failed; curl 56 OpenSSL SSL_read" ?

This is usually a network/SSL issue. Try these solutions:

  1. Increase buffer size: git config http.postBuffer 524288000
  2. Disable SSL verification (temporary): git config http.sslVerify false
  3. Use SSH instead of HTTPS
  4. Check network stability and VPN/proxy settings
  5. Try shallow clone: git clone --depth 1 [url]
How do I debug slow Git operations?

Use Git's performance tracing:

  1. GIT_TRACE_PERFORMANCE=1 git status - shows timing of each operation
  2. GIT_TRACE=1 git fetch - shows detailed operation log
  3. Check repository size: git count-objects -vH
  4. Enable filesystem monitor: git config core.fsmonitor true
  5. Run garbage collection: git gc --aggressive
Previous: Git Log Analysis Next: Advanced Rebase