Skip to main content

Git Interview & Scenarios

 Git Interview & Scenarios: The Complete DevOps Interview Preparation Guide

Master Git interview questions and real-world troubleshooting scenarios that separate junior from senior DevOps engineers.

📅 Published: Feb 2026
⏱️ Estimated Reading Time: 25 minutes
🏷️ Tags: Git Interview, DevOps Interview, Git Scenarios, Version Control, Troubleshooting


🎯 Common Git Interview Questions: From Basics to Expert

Level 1: Foundation Questions

These questions test whether you understand Git fundamentals. Interviewers ask these to establish baseline knowledge.


Q1: What's the difference between Git and GitHub/GitLab?

Why interviewers ask this: Many beginners confuse Git (the tool) with GitHub (the platform). This tests your fundamental understanding.

Answer:
Git is a version control system that runs locally on your computer. It tracks changes to files and manages your repository history. GitHub, GitLab, and Bitbucket are web-based platforms that host Git repositories and add collaboration features like pull requests, issue tracking, and CI/CD.

Think of it like email:

  • Git = The email protocol (SMTP/IMAP) - the underlying technology

  • GitHub = Gmail/Hotmail - the service that makes it accessible

bash
# Git works offline - no internet needed
git commit -m "Work on plane"  # Works perfectly

# GitHub requires internet to push/pull
git push origin main  # Needs internet connection

Q2: Explain the difference between git pull and git fetch.

Why interviewers ask this: This reveals whether you understand how Git synchronizes with remote repositories.

Answer:
git fetch downloads changes from the remote repository but does not integrate them into your working files. It's like checking what's new without bringing it into your workspace.

git pull downloads and immediately integrates changes. It's actually git fetch followed by git merge (or git rebase if configured).

bash
# Fetch - safe, no changes to working directory
git fetch origin
git log origin/main  # See what's new
git diff main origin/main  # Compare before merging

# Pull - downloads AND merges
git pull origin main  # Fetch + merge
# or
git pull --rebase origin main  # Fetch + rebase

Real-world scenario:
You're on a feature branch and want to see if teammates have pushed changes without disrupting your work-in-progress:

bash
git fetch origin
git log main..origin/main  # View commits not in your local main
# Now decide when to merge

Q3: What's the difference between git merge and git rebase?

Why interviewers ask this: This is the classic Git interview question. Your answer reveals how you think about history management.

Answer:
Both commands integrate changes from one branch into another, but they create different commit histories:

git merge creates a merge commit that joins two branches. It preserves the exact history of when branches diverged and were rejoined. It's non-destructive - you never lose context.

git rebase rewrites history by reapplying commits on top of another branch. It creates a linear, cleaner history but changes commit SHAs.

bash
# Merge preserves context
git checkout feature
git merge main
# Creates: ... A --- B --- C --- D (feature)
#                \               /
#                 X --- Y --- Z (main)

# Rebase creates linear history
git checkout feature
git rebase main
# Creates: ... X --- Y --- Z (main) --- A' --- B' --- C' (feature)

When to use each:

  • Merge: Public branches, preserving historical truth, when rebase would be disruptive

  • Rebase: Local feature branches before PR, creating clean, readable history

Golden rule: Never rebase commits that have been pushed to a shared repository.


Q4: How do you undo changes in Git? Explain resetrevert, and checkout.

Why interviewers ask this: Recovery skills separate beginners from professionals. Everyone makes mistakes; professionals know how to fix them.

Answer:
Each undo command serves a different purpose:

git reset moves the branch pointer backward, effectively "erasing" commits. Use it for local, unpushed changes only.

bash
# Soft reset - keep changes staged
git reset --soft HEAD~1  # Undo commit, keep changes ready to commit

# Mixed reset - keep changes working (default)
git reset HEAD~1  # Undo commit, unstage changes

# Hard reset - discard changes completely
git reset --hard HEAD~1  # Undo commit, DELETE changes (DANGER!)

git revert creates a new commit that undoes a previous commit. It's safe for public branches because it doesn't rewrite history.

bash
git revert HEAD  # Create new commit that undoes last commit
git revert abc123  # Revert specific commit

git checkout restores files or switches branches.

bash
# Discard changes in working directory
git checkout -- file.txt  # Restore file to last committed state

# Switch to previous commit (detached HEAD)
git checkout abc123

Decision tree for undoing changes:

  1. Not committed yet? → git checkout -- file or git restore file

  2. Committed but not pushed? → git reset --soft/hard HEAD~1

  3. Already pushed to shared branch? → git revert


Q5: What is a detached HEAD state and how do you recover from it?

Why interviewers ask this: This tests whether you understand Git's internal pointer system.

Answer:
Detached HEAD means your HEAD pointer is attached directly to a commit instead of a branch. You're no longer on a named branch.

Why it happens:

  • Checking out a specific commit: git checkout abc123

  • Checking out a tag: git checkout v1.0.0

  • During interactive rebase

Why it's dangerous: Any commits made in detached HEAD can be lost when you switch branches (they'll be garbage collected after 30 days).

Recovery methods:

bash
# 1. Create a branch immediately (SAFEST)
git checkout -b saved-work

# 2. Cherry-pick the commit to an existing branch
git checkout main
git cherry-pick abc123

# 3. Find lost commits in reflog
git reflog
git checkout -b recovered-branch HEAD@{2}

Level 2: Intermediate Questions

These questions test practical experience and problem-solving ability.


Q6: How do you find a bug using Git bisect?

Why interviewers ask this: This tests whether you know Git's debugging tools, not just basic commands.

Answer:
git bisect performs a binary search through your commit history to find which commit introduced a bug.

bash
# Step 1: Start bisect
git bisect start

# Step 2: Mark current version as bad
git bisect bad

# Step 3: Mark known good commit (where bug didn't exist)
git bisect good v1.0.0

# Step 4: Git checks out middle commit - test it
# If bug exists: git bisect bad
# If bug doesn't exist: git bisect good

# Step 5: Repeat until Git identifies the culprit
# Output: abc1234 is the first bad commit

# Step 6: End bisect
git bisect reset

Real-world scenario:

bash
# Automate with test script
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run npm test  # Automatically test each commit

Pro tip: Create a script that returns 0 for good, 1 for bad, and let Git run it automatically.


Q7: How do you recover a deleted branch or lost commit?

Why interviewers ask this: This tests your knowledge of Git's safety mechanisms and recovery tools.

Answer:
Git never immediately deletes commits—they linger in the reflog and garbage collection. Use git reflog as your recovery tool.

bash
# 1. Find the lost commit
git reflog
# abc1234 HEAD@{0}: commit: Critical feature implementation
# def5678 HEAD@{1}: checkout: moving from feature to main

# 2. Recreate the branch
git checkout -b recovered-feature abc1234

# 3. Or cherry-pick the commit
git checkout main
git cherry-pick abc1234

# 4. If you know the commit hash but it's not in reflog
git fsck --lost-found  # Find dangling commits
git show .git/lost-found/commit/abc1234

Prevention: Push feature branches frequently, even work-in-progress branches.


Q8: How do you clean up a messy commit history before a pull request?

Why interviewers ask this: This tests your ability to present clean, reviewable work.

Answer:
Use interactive rebase to squash, reorder, and rewrite commits.

bash
# Before cleanup (messy history)
git log --oneline
# a1b2c3d Fix typo
# b2c3d4e Actually fix the bug
# c3d4e5f Oops, forgot semicolon
# d4e5f6g Add feature implementation
# e5f6g7h Initial commit

# Interactive rebase on the last 5 commits
git rebase -i HEAD~5

# In editor, change 'pick' to:
# pick e5f6g7h Initial commit
# squash d4e5f6g Add feature implementation
# fixup c3d4e5f Oops, forgot semicolon
# fixup b2c3d4e Actually fix the bug
# fixup a1b2c3d Fix typo

# After cleanup (clean history)
git log --oneline
# x1y2z3a Add feature implementation with tests
# e5f6g7h Initial commit

Best practice script:

bash
#!/bin/bash
# cleanup-pr.sh

echo "=== Cleaning up PR branch ==="

# Rebase on latest main
git fetch origin main
git rebase origin/main

# Squash fixup commits
git rebase -i origin/main

# Verify commit messages follow convention
git log --oneline origin/main..HEAD

# Force push (since history changed)
git push --force-with-lease origin HEAD

echo "✅ Branch ready for PR review"

Q9: How do you handle large files in Git?

Why interviewers ask this: This tests experience with real-world repository management issues.

Answer:
Git struggles with large files (>50MB) because it stores the entire history of every file. Solutions:

1. Prevent large files from being committed:

bash
# .gitignore
*.iso
*.zip
*.tar.gz
node_modules/

# Pre-commit hook
find . -type f -size +5M ! -path ".git/*" | while read file; do
    echo "❌ Large file detected: $file"
    exit 1
done

2. Remove large files from history (BFG Repo-Cleaner):

bash
# Download BFG
java -jar bfg.jar --strip-blobs-bigger-than 50M
git reflog expire --expire=now --all
git gc --prune=now --aggressive

3. Use Git LFS (Large File Storage) for binaries:

bash
# Install Git LFS
git lfs install

# Track file types
git lfs track "*.psd"
git lfs track "*.zip"
git add .gitattributes

# Commit as normal
git add file.psd
git commit -m "feat: add design assets"
git push

Q10: What's your Git branching strategy and why?

Why interviewers ask this: This tests your ability to design and justify workflows, not just follow patterns.

Answer:
"I adapt my branching strategy to the team's needs, but my preferred approach is GitHub Flow with these adaptations:"

markdown
## Branch Strategy

**main** - Always deployable, protected branch
- Direct commits prohibited
- Requires PR with 1-2 reviewers
- Must pass all CI checks
- Deployed automatically

**feat/** - New features
- Branched from main
- Deleted after merge
- Naming: `feat/JIRA-123-description`
- Squash merge to main

**fix/** - Bug fixes
- Same rules as feat/
- Includes regression tests
- Cherry-picked to release branches if needed

**hotfix/** - Production emergencies
- Branched from tagged release
- Urgent review process
- Merged to main AND develop
- Tagged with hotfix version

**release/** - Version preparation
- Branched from develop
- Only bug fixes, no new features
- Final testing and version bumps
- Merged to main and tagged

Why this works:

  1. Simple - Easy for new team members to understand

  2. Safe - Protected branches and required reviews

  3. Fast - Short-lived branches, continuous integration

  4. Traceable - JIRA tickets in branch names connect code to requirements


Level 3: Expert Questions

These questions test deep understanding of Git internals and complex troubleshooting.


Q11: Explain how Git stores data internally.

Why interviewers ask this: This separates users from masters. Understanding internals helps you debug and recover from any situation.

Answer:
Git is fundamentally a content-addressable filesystem with a VCS interface. It stores data as key-value pairs where the key is a SHA-1 hash of the content.

Four object types:

bash
# 1. Blob - File contents
git hash-object -w file.txt  # Creates blob

# 2. Tree - Directory structure
git cat-file -p HEAD^{tree}  # View tree

# 3. Commit - Snapshot with metadata
git cat-file -p HEAD  # View commit object

# 4. Tag - Named reference to commit
git cat-file -p v1.0.0  # View tag object

Storage mechanics:

bash
# View Git's internal storage
ls -la .git/objects/
# 12/ 34/ 56/  # First 2 chars = directory, rest = filename

# View object type and content
git cat-file -t abc1234  # blob, tree, commit, tag
git cat-file -p abc1234  # Pretty-print content

# Git's compression
git gc  # Garbage collect, pack objects
ls -la .git/objects/pack/  # Packed files are delta-compressed

The magic of SHA-1:

  • Content + header = hash

  • Same content = same hash anywhere in the universe

  • This is how Git detects changes and duplicates


Q12: How do you recover from a force-push that overwrote your branch?

Why interviewers ask this: This tests your ability to handle catastrophic team scenarios.

Answer:
This is every team's nightmare. Here's a systematic recovery approach:

bash
# 1. STAY CALM - Don't push anything else

# 2. Find the original commit using reflog (on ANY machine that had the branch)
git reflog show origin/branch-name  # If you have remote reflog
git reflog show branch-name         # Local reflog

# 3. If you have the commit hash, recreate the branch
git checkout -b recovered-branch abc1234
git push origin recovered-branch

# 4. If no one else has the hash, check other developers' machines
# They can push the branch back
git push origin local-branch:remote-branch

# 5. Use Git's data recovery tools
git fsck --full --no-reflogs --unreachable
git show unreachable-commit-hash

# 6. As a last resort, reconstruct from PR (GitHub/GitLab)
# GitHub stores all PR commits permanently
# Find the PR, look for "merged commit" hash

# 7. Prevention: Configure branch protection
git push --force-with-lease  # NEVER use --force

Team recovery protocol:

bash
#!/bin/bash
# emergency-branch-recovery.sh

echo "🚨 EMERGENCY: Branch overwritten"
echo "Time: $(date)"
echo "Branch: $1"
echo

# 1. Identify affected developers
echo "1. Identifying affected work..."
git reflog | grep $1 | head -20

# 2. Create recovery branch
echo "2. Creating recovery branch..."
git checkout -b $1-recovery $2
git push origin $1-recovery

# 3. Notify team
echo "3. Sending team alert..."
echo "Subject: Git Recovery Needed for $1"
echo "Recovery branch: $1-recovery"
echo "Please cherry-pick your commits to new feature branch"

# 4. Post-mortem
echo "4. Root cause analysis required"

Q13: How do you implement Git hooks for compliance in regulated industries?

Why interviewers ask this: This tests experience with enterprise Git, compliance, and automation.

Answer:
In regulated industries (finance, healthcare, government), you need enforceable, auditable Git workflows:

bash
#!/bin/bash
# compliance-hooks.sh

# pre-commit - Prevent secrets and compliance violations
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
echo "🔒 Compliance Check - $(date)" >> .git/compliance.log

# 1. Check for hardcoded secrets
SECRET_PATTERNS="password|secret|key|token|credential|PRIVATE"
if git diff --cached | grep -iE "$SECRET_PATTERNS"; then
    echo "❌ SECURITY VIOLATION: Hardcoded secrets detected"
    exit 1
fi

# 2. Check for TODO/FIXME in production code
if git diff --cached | grep -iE "\+.*todo|\+.*fixme"; then
    echo "⚠️  COMPLIANCE WARNING: TODO/FIXME in committed code"
    echo "Add JIRA ticket reference: // TODO(JIRA-123)"
fi

# 3. License headers (required by legal)
for file in $(git diff --cached --name-only); do
    if ! grep -q "Copyright $(date +%Y) Company Name" "$file"; then
        echo "❌ LEGAL VIOLATION: Missing copyright header in $file"
        exit 1
    fi
done
EOF

# commit-msg - Enforce regulatory ticket references
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/bash
commit_msg=$(cat "$1")

# REGULATORY-123: Description
if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|chore)\([a-z]+\): \[[A-Z]+-[0-9]+\]"; then
    echo "❌ COMPLIANCE: Commit must include JIRA ticket in format [PROJECT-123]"
    exit 1
fi
EOF

# pre-push - Required signatures and approvals
cat > .git/hooks/pre-push << 'EOF'
#!/bin/bash
# HIPAA/SOX compliance requires signed commits
if ! git log -1 --format=%B | grep -q "Signed-off-by"; then
    echo "❌ COMPLIANCE: Commits must be signed off (git commit -s)"
    exit 1
fi

# Verify GPG signature
if ! git verify-commit HEAD; then
    echo "❌ SECURITY: Commits must be GPG signed"
    exit 1
fi
EOF

Audit trail requirements:

bash
# Every action must be logged
git config --global alias.commit '!f() { \
    echo "[$(date)] commit: $@" >> ~/.git-audit.log; \
    git -c commit.gpgsign=true commit -s -S "$@"; \
}; f'

Q14: How do you optimize Git performance for monorepos?

Why interviewers ask this: This tests experience with large-scale Git repositories.

Answer:
Monorepos (single repository for entire company) create unique Git challenges:

bash
# 1. Partial clone (Git 2.19+) - Download only what you need
git clone --filter=blob:none <url>  # No file contents
git clone --filter=tree:0 <url>     # No trees
git sparse-checkout set /service-a  # Only checkout specific directories

# 2. Shallow clone for CI/CD
git clone --depth 1 <url>  # Only last commit
git fetch --depth 1 origin <commit-sha>  # Fetch specific commit

# 3. Git GC optimization
git gc --aggressive --prune=now
git repack -a -d --depth=250 --window=250

# 4. Configure Git for large repos
git config core.preloadindex true     # Faster git status
git config core.fscache true         # Filesystem cache (Windows)
git config gc.auto 256               # Less frequent GC
git config pack.threads 8           # Parallel compression

# 5. Use Git worktrees for parallel work
git worktree add ../project-hotfix hotfix
git worktree add ../project-feature feature
# Each worktree shares .git folder but has separate working directory

# 6. Monorepo management tools
# - git-submodules (built-in)
# - git-subtree (built-in)
# - Google's repo tool
# - Facebook's EdenFS

Enterprise monorepo strategy:

yaml
# .gitattributes - Path-specific settings
/service-a/** linguist-generated=true
/service-b/** -diff
*.pbxproj merge=union

# .gitignore patterns
**/node_modules/
**/.env
**/dist/

🔧 Real-world Git Issues: Case Studies

Case Study 1: The Deleted Production Branch

Scenario: A junior developer accidentally deleted the main branch on GitHub. Your team is panicking, and deployment is blocked.

Root cause: Branch protection wasn't enabled. The developer had admin rights and clicked "Delete branch" after merging a PR.

Recovery steps:

bash
# 1. CHECK REFLOG ON ANY LOCAL COPY
git reflog show origin/main
# If you find the last commit hash, recreate branch

# 2. IF NO REFLOG, CHECK PULL REQUESTS
# GitHub stores all PR commits permanently
# Find the last merged PR, copy commit SHA

# 3. RECREATE BRANCH LOCALLY
git checkout -b main abc1234
git push origin main

# 4. ENABLE BRANCH PROTECTION
# Settings → Branches → Add rule
# ☑ Require pull request reviews
# ☑ Dismiss stale reviews
# ☑ Require status checks
# ☑ Require signed commits
# ☑ Do not allow bypassing settings

# 5. POST-MORTEM
# Document incident, adjust permissions
# Remove admin rights from developer accounts
# Implement backup strategy for critical branches

Prevention script:

bash
#!/bin/bash
# protect-critical-branches.sh

# Enable branch protection via GitHub API
REPO="company/production"
BRANCHES=("main" "develop" "staging" "production")

for BRANCH in "${BRANCHES[@]}"; do
    curl -X PUT \
        -H "Authorization: token $GITHUB_TOKEN" \
        -H "Accept: application/vnd.github.v3+json" \
        "https://api.github.com/repos/$REPO/branches/$BRANCH/protection" \
        -d '{
            "required_status_checks": {
                "strict": true,
                "contexts": ["continuous-integration"]
            },
            "enforce_admins": true,
            "required_pull_request_reviews": {
                "required_approving_review_count": 2,
                "dismiss_stale_reviews": true
            },
            "restrictions": null
        }'
done

Case Study 2: The 10GB Repository

Scenario: Your repository has grown to 10GB. git clone takes 30 minutes, git status takes 10 seconds, and developers are complaining.

Root cause: Multiple issues:

  • Accidentally committed 500MB video files (removed but still in history)

  • 5 years of binary build artifacts

  • No Git LFS strategy

  • Every build artifact committed "just in case"

Diagnosis:

bash
# 1. Find largest files in history
git rev-list --objects --all | \
    git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
    sed -n 's/^blob //p' | \
    sort --numeric-sort --key=2 | \
    tail -10 | \
    cut -c 1-12,41- | \
    $(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

# 2. Check pack file size
du -sh .git/objects/pack/

# 3. Count objects
git count-objects -vH

Recovery strategy:

bash
# Phase 1: Emergency cleanup
# Remove large files from history using BFG
java -jar bfg.jar --delete-files "*.mp4" --delete-files "*.zip"
java -jar bfg.jar --strip-blobs-bigger-than 50M

# Phase 2: Garbage collection
git reflog expire --expire=now --all
git gc --prune=now --aggressive

# Phase 3: Force push (COORDINATE WITH TEAM!)
git push --force --all
git push --force --tags

# Phase 4: Implement Git LFS
git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "*.zip"
git add .gitattributes
git commit -m "chore: add Git LFS tracking for binary files"
git push

# Phase 5: Migrate existing binaries to LFS
git lfs migrate import --include="*.psd,*.mp4,*.zip" --everything

Prevention policy:

yaml
# .github/workflows/validate-size.yml
name: Validate File Sizes
on: [pull_request]
jobs:
  check-files:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Check file sizes
        run: |
          LARGE_FILES=$(find . -type f -size +5M -not -path "./.git/*")
          if [ -n "$LARGE_FILES" ]; then
            echo "❌ Large files detected:"
            echo "$LARGE_FILES"
            exit 1
          fi

Case Study 3: The Divergent Histories Disaster

Scenario: Two teams worked on the same repository for 6 months without syncing. Now you have two completely divergent main branches that Git refuses to merge.

Root cause: Team A used rebase workflow, Team B used merge workflow. No one communicated. Now there are 5,000 commits with overlapping changes, and git merge produces 2,000 conflicts.

Recovery strategy:

bash
# Phase 1: Assessment
# Create backup branches
git branch backup/team-a origin/team-a/main
git branch backup/team-b origin/team-b/main

# Analyze differences
git log --oneline backup/team-a ^backup/team-b | wc -l  # Commits only in A
git log --oneline backup/team-b ^backup/team-a | wc -l  # Commits only in B

# Phase 2: Create merge base
# Find common ancestor
BASE_COMMIT=$(git merge-base backup/team-a backup/team-b)
git checkout -b integration $BASE_COMMIT

# Phase 3: Strategic merge (not tactical)
# Don't try to merge everything at once - use "strategy merge"

# First merge team A with ours strategy (keep all our changes)
git merge -s ours backup/team-a --no-commit
git commit -m "chore: integrate team A history"

# Then merge team B with recursive and patience algorithm
git merge backup/team-b -X patience -X rename-threshold=30

# Phase 4: Break into phases
# Create integration branches for each module
git checkout -b integration/auth $BASE_COMMIT
git merge --squash backup/team-a -- src/auth/
git commit -m "feat(auth): integrate team A auth module"
git merge --squash backup/team-b -- src/auth/
# Resolve conflicts for just this module
git commit -m "fix(auth): resolve integration conflicts"

# Repeat for each module
# Phase 5: Final integration
git checkout -b final-integration main
for module in auth api frontend; do
    git merge integration/$module --no-ff -m "feat: integrate $module"
done

Lessons learned document:

markdown
# Post-Mortem: Repository Divergence Incident

## Timeline
- Month 1: Teams started working independently
- Month 3: First signs of divergence (ignored)
- Month 6: Deployment blocked, unable to merge

## Root Causes
1. No shared branch strategy
2. No regular integration meetings
3. No CI on feature branches
4. Different rebase/merge preferences

## Prevention Measures
✅ Weekly "integration sync" meetings
✅ CI required on all branches
✅ Branch protection rules enforced
✅ Shared Git strategy documented
✅ Monthly "rebase day" for long-running branches

## Recovery Status
✅ All modules successfully integrated
✅ 95% automatic merge, 5% manual resolution
✅ 2 weeks of focused effort
✅ All tests passing

Case Study 4: The CI/CD Pipeline That Deleted History

Scenario: Your CI/CD pipeline runs git push --force after successful builds. One day, a build succeeds but the force push overwrites the wrong branch, deleting 3 days of work from the release branch.

Root cause: CI script used git push --force instead of git push --force-with-lease. The script also didn't validate which branch it was pushing.

The dangerous script:

bash
#!/bin/bash
# BAD - DO NOT USE
git checkout $BRANCH
git merge --no-ff feature/$FEATURE
git push --force origin $BRANCH  # DANGER!

Recovery:

bash
# 1. IMMEDIATELY: Identify who has the lost commits
# Check all developers' local repositories
# Use the reflog on any machine that had the branch
git reflog show origin/release | head -20

# 2. RECOVER: Restore from local copy
git checkout -b release-recovery abc1234
git push origin release-recovery

# 3. NOTIFY: Team to cherry-pick from recovery branch
echo "Release branch recovered at release-recovery"
echo "Please cherry-pick your commits to new release branch"

# 4. FIX: Update CI/CD pipeline
cat > .github/workflows/deploy.yml << 'EOF'
name: Safe Deploy
on: [push]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0  # Full history needed for safety check
      
      - name: Validate branch
        run: |
          if [[ "$GITHUB_REF" != "refs/heads/release"* ]] && \
             [[ "$GITHUB_REF" != "refs/heads/hotfix"* ]]; then
            echo "❌ Cannot force push to $GITHUB_REF"
            exit 1
          fi
      
      - name: Push with lease
        run: |
          git push --force-with-lease origin HEAD:$GITHUB_REF
EOF

Prevention checklist:

markdown
## CI/CD Git Safety Checklist

- [ ] Never use `git push --force`
- [ ] Always use `git push --force-with-lease`
- [ ] Validate branch names before force push
- [ ] Only allow force push to feature branches
- [ ] Enable branch protection on main/develop/release
- [ ] Require linear history on protected branches
- [ ] Log all force push operations
- [ ] Alert team when force push occurs

📝 Hands-on Practice Tasks

Task 1: Git Bisect Detective

Objective: Find which commit introduced a specific bug using binary search.

bash
# Setup
mkdir git-detective && cd git-detective
git init

# Create buggy script
cat > app.js << 'EOF'
function calculateTotal(price, tax) {
    // Bug introduced somewhere in history
    return price + tax;  // Should be price * (1 + tax)
}
EOF

git add app.js
git commit -m "feat: add tax calculation"

# Create 20 commits, introducing bug at commit 10
for i in {1..20}; do
    if [ $i -eq 10 ]; then
        # Bug version
        cat > app.js << 'EOF'
function calculateTotal(price, tax) {
    return price + tax;  // WRONG! Should multiply
}
EOF
    else
        # Correct version
        cat > app.js << 'EOF'
function calculateTotal(price, tax) {
    return price * (1 + tax);  // CORRECT
}
EOF
    fi
    git add app.js
    git commit -m "chore: update iteration $i"
done

# TASK: Find commit 10 using git bisect

Solution:

bash
# Start bisect
git bisect start

# Mark current as bad
git bisect bad

# Mark first commit as good
git bisect good $(git rev-list --max-parents=0 HEAD)

# Git will checkout middle commits - test each
# If function returns price + tax (bad): git bisect bad
# If function returns price * (1+tax) (good): git bisect good

# Automate with test script
cat > test.sh << 'EOF'
#!/bin/bash
if grep -q "price + tax" app.js; then
    exit 1  # Bad
else
    exit 0  # Good
fi
EOF
chmod +x test.sh

git bisect run ./test.sh

Task 2: Rewriting History Safely

Objective: Clean up a messy feature branch without losing work.

bash
# Setup
mkdir git-cleanup && cd git-cleanup
git init

# Create messy history
touch file1.txt && git add . && git commit -m "wip"
touch file2.txt && git add . && git commit -m "fix"
touch file3.txt && git add . && git commit -m "actually fix"
touch file4.txt && git add . && git commit -m "add feature"
touch file5.txt && git add . && git commit -m "oops"
touch file6.txt && git add . && git commit -m "add tests"
touch file7.txt && git add . && git commit -m "fix tests"
touch file8.txt && git add . && git commit -m "documentation"
touch file9.txt && git add . && git commit -m "style"
touch file10.txt && git add . && git commit -m "chore"

# TASK: Clean to 3 meaningful commits:
# 1. "feat: add core feature implementation"
# 2. "test: add test suite"
# 3. "docs: update documentation"

Solution:

bash
# 1. Create backup branch (SAFETY FIRST!)
git branch backup/messy-history

# 2. Interactive rebase
git rebase -i --root

# In editor, reorganize commits:
# pick 1st commit - "feat: add core feature implementation"
# squash 2-4 into it
# fixup 5-7 into it

# pick "add tests" - "test: add test suite"
# squash/fixup test-related commits

# pick "documentation" - "docs: update documentation"
# squash/fixup remaining

# 3. Force push with lease (to your feature branch only!)
git push --force-with-lease origin feature-branch

Task 3: Git Surgery - Splitting a Commit

Objective: Split one large commit into multiple focused commits.

bash
# Setup
mkdir git-surgery && cd git-surgery
git init

# Create one large commit
cat > auth.js << 'EOF'
function login(username, password) {
    // authentication logic
}
EOF

cat > profile.js << 'EOF'
function getProfile(userId) {
    // profile retrieval
}
EOF

cat > utils.js << 'EOF'
function formatDate(date) {
    return date.toISOString().split('T')[0];
}
EOF

git add .
git commit -m "feat: add authentication, profiles, and utilities"

# TASK: Split this commit into 3 logical commits

Solution:

bash
# 1. Start interactive rebase
git rebase -i HEAD~1
# Change 'pick' to 'edit'

# 2. Reset to previous commit, keeping changes
git reset HEAD^

# 3. Commit each file separately
git add auth.js
git commit -m "feat(auth): add user authentication"

git add profile.js
git commit -m "feat(profile): add user profile retrieval"

git add utils.js
git commit -m "feat(utils): add date formatting utilities"

# 4. Continue rebase
git rebase --continue

# 5. Verify
git log --oneline
# Should show 3 commits instead of 1

Task 4: Merge Conflict Master

Objective: Resolve a complex merge conflict involving multiple files.

bash
# Setup - Person A
mkdir git-conflict-a && cd git-conflict-a
git init

cat > config.json << 'EOF'
{
    "version": "1.0.0",
    "features": {
        "auth": true,
        "profile": false,
        "admin": false
    }
}
EOF

git add config.json
git commit -m "chore: initial config"
git checkout -b feature/person-a

cat > config.json << 'EOF'
{
    "version": "1.1.0",
    "features": {
        "auth": true,
        "profile": true,  // Added
        "admin": false,
        "notifications": true  // New feature
    }
}
EOF

git commit -am "feat: add profile and notifications"

# Setup - Person B (separate directory)
mkdir ../git-conflict-b && cd ../git-conflict-b
git init
cp ../git-conflict-a/config.json .
git add config.json
git commit -m "chore: initial config"
git checkout -b feature/person-b

cat > config.json << 'EOF'
{
    "version": "1.2.0",
    "features": {
        "auth": true,
        "profile": false,
        "admin": true,  // Added
        "analytics": true  // New feature
    },
    "database": {
        "host": "localhost",
        "port": 5432
    }
}
EOF

git commit -am "feat: add admin and analytics, add database config"

# TASK: Merge both branches and resolve conflicts intelligently

Solution:

bash
# 1. Create integration branch
git checkout main
git checkout -b merge/integration

# 2. Merge first feature branch
git merge feature/person-a --no-ff
# Should succeed

# 3. Merge second feature branch (CONFLICT!)
git merge feature/person-b

# 4. Resolve conflict in config.json
# Open config.json, create merged version:
{
    "version": "2.0.0",  // Bump major version for multiple new features
    "features": {
        "auth": true,
        "profile": true,      // From Person A
        "admin": true,        // From Person B
        "notifications": true, // From Person A
        "analytics": true     // From Person B
    },
    "database": {             // From Person B
        "host": "localhost",
        "port": 5432
    }
}

# 5. Mark as resolved
git add config.json
git commit -m "merge: resolve config.json conflicts

- Combined features from both branches
- Bumped version to 2.0.0
- Added database configuration"

# 6. Verify
cat config.json | jq '.features'  # Should have all 5 features

Task 5: Git Hook Implementation

Objective: Create a comprehensive pre-commit hook that enforces team standards.

bash
# Setup
mkdir git-hook-practice && cd git-hook-practice
git init

# TASK: Create pre-commit hook that:
# 1. Prevents committing .env files
# 2. Enforces file size limit (1MB)
# 3. Checks for TODO without ticket reference
# 4. Runs linter on staged files
# 5. Validates branch name format

Solution:

bash
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash

echo "🔍 Running pre-commit checks..."
FAILED=0

# 1. Branch name validation
BRANCH_NAME=$(git symbolic-ref --short HEAD 2>/dev/null)
if [[ ! "$BRANCH_NAME" =~ ^(feat|fix|hotfix|chore|docs)/[a-z0-9-]+$ ]]; then
    echo "❌ Branch name must match: type/description"
    echo "   Examples: feat/login-form, fix/null-pointer"
    FAILED=1
fi

# 2. Check for .env files
ENV_FILES=$(git diff --cached --name-only | grep -E "\.env$|\.env\.")
if [ -n "$ENV_FILES" ]; then
    echo "❌ Environment files detected:"
    echo "$ENV_FILES"
    echo "   Use .env.example instead"
    FAILED=1
fi

# 3. File size check
git diff --cached --name-only | while read file; do
    if [ -f "$file" ]; then
        SIZE=$(stat -c%s "$file")
        if [ $SIZE -gt 1048576 ]; then  # 1MB
            echo "❌ File too large: $file (${SIZE} bytes)"
            echo "   Max size: 1MB"
            FAILED=1
        fi
    fi
done

# 4. TODO without ticket reference
TODO_LINES=$(git diff --cached | grep -E "^\+.*TODO" | grep -vE "TODO\([A-Z]+-[0-9]+\)")
if [ -n "$TODO_LINES" ]; then
    echo "⚠️  TODO missing ticket reference:"
    echo "$TODO_LINES"
    echo "   Format: TODO(JIRA-123)"
    # Warning only, don't fail
fi

# 5. Run linter on staged JavaScript files
STAGED_JS=$(git diff --cached --name-only --diff-filter=ACM | grep "\.js$")
if [ -n "$STAGED_JS" ] && [ -f "node_modules/.bin/eslint" ]; then
    echo "Running ESLint..."
    npx eslint $STAGED_JS
    if [ $? -ne 0 ]; then
        echo "❌ ESLint failed"
        FAILED=1
    fi
fi

# 6. Check for debugging statements
if git diff --cached | grep -E "^\+.*console\.log|^\+.*debugger|^\+.*print\("; then
    echo "⚠️  Debugging statements detected"
    echo "   Consider removing before final commit"
    # Warning only
fi

if [ $FAILED -eq 1 ]; then
    echo "❌ Pre-commit checks failed"
    exit 1
else
    echo "✅ All pre-commit checks passed"
fi
EOF

chmod +x .git/hooks/pre-commit

# Test the hook
echo "console.log('debug');" > test.js
git add test.js
git commit -m "test"  # Should warn about console.log

echo "SECRET_KEY=123" > .env
git add .env
git commit -m "test"  # Should FAIL

Task 6: Git Team Simulation

Objective: Practice team collaboration with branches, PRs, and merge conflicts.

bash
#!/bin/bash
# team-simulation.sh

echo "=== Git Team Simulation ==="
echo "Role: Team Lead / DevOps Engineer"
echo

# Setup shared repository
mkdir team-repo && cd team-repo
git init --bare repo.git
cd ..
git clone team-repo/repo.git project
cd project

# Initialize project
cat > README.md << 'EOF'
# Team Project
Welcome to the team! 
EOF

git add README.md
git commit -m "chore: initial commit"
git push origin main

# Person A - Feature implementation
git checkout -b feat/user-auth
cat > auth.js << 'EOF'
function login(username, password) {
    // TODO: implement JWT
    return "token";
}
EOF
git add auth.js
git commit -m "feat(auth): add login function stub"
git push origin feat/user-auth

# Person B - Different feature (simulate in real team)
git checkout main
git checkout -b feat/user-profile
cat > profile.js << 'EOF'
function getProfile(userId) {
    // TODO: fetch from database
    return { name: "John" };
}
EOF
git add profile.js
git commit -m "feat(profile): add getProfile stub"
git push origin feat/user-profile

# Person A continues working...
git checkout feat/user-auth
echo "function validateEmail(email) { return true; }" >> auth.js
git commit -am "feat(auth): add email validation"
git push

# TASK: As team lead, review and merge both PRs
echo -e "\n🎯 YOUR TASK:"
echo "1. Review both feature branches"
echo "2. Test functionality"
echo "3. Merge with main"
echo "4. Resolve any conflicts"
echo "5. Tag release v1.0.0"

Solution steps:

bash
# 1. Review branches
git fetch --all
git checkout origin/feat/user-auth
git diff main
git log --oneline main..feat/user-auth

# 2. Test changes locally
git checkout -b test/user-auth origin/feat/user-auth
# Run tests, verify functionality

# 3. Merge to main with PR strategy
git checkout main
git pull origin main
git merge --no-ff feat/user-auth -m "merge: PR #123 - user authentication"
git push origin main

git merge --no-ff feat/user-profile -m "merge: PR #124 - user profile"
git push origin main

# 4. Create release
git tag -a v1.0.0 -m "Release 1.0.0 - Auth + Profile features"
git push origin v1.0.0

# 5. Clean up branches
git push origin --delete feat/user-auth
git push origin --delete feat/user-profile
git branch -d feat/user-auth feat/user-profile

📋 Git Interview Preparation Checklist

markdown
# Git Interview Readiness Checklist

## ✅ Fundamentals
- [ ] Explain difference between Git and GitHub
- [ ] Describe Git workflow (add, commit, push, pull)
- [ ] Differentiate merge vs rebase
- [ ] Understand detached HEAD state
- [ ] Know reset, revert, checkout differences

## ✅ Branching & Merging
- [ ] Create feature branches with naming conventions
- [ ] Resolve merge conflicts confidently
- [ ] Squash commits with interactive rebase
- [ ] Cherry-pick specific commits
- [ ] Stash and apply changes

## ✅ Collaboration
- [ ] Fork and clone repositories
- [ ] Open and review pull requests
- [ ] Implement branch protection rules
- [ ] Handle upstream changes with rebase
- [ ] Manage multiple remotes

## ✅ Troubleshooting
- [ ] Recover lost commits with reflog
- [ ] Find bugs with git bisect
- [ ] Remove large files from history
- [ ] Recover from force push disaster
- [ ] Clean up local/remote branches

## ✅ Advanced
- [ ] Implement Git hooks for automation
- [ ] Configure Git LFS for binaries
- [ ] Optimize monorepo performance
- [ ] Sign commits with GPG
- [ ] Custom Git aliases

## ✅ Best Practices
- [ ] Write conventional commits
- [ ] Maintain clean linear history
- [ ] Use .gitignore effectively
- [ ] Document branching strategy
- [ ] Automate with CI/CD

## 🎯 Common Interview Questions
- [ ] "How do you undo a public commit?"
- [ ] "What's your branching strategy and why?"
- [ ] "How do you resolve merge conflicts?"
- [ ] "How do you handle hotfixes in production?"
- [ ] "How do you onboard new developers to Git?"

🚀 Final Practice Challenge: Git Escape Room

Objective: Solve 5 Git problems in under 30 minutes.

bash
#!/bin/bash
# git-escape-room.sh

echo "=== GIT ESCAPE ROOM ==="
echo "You have 30 minutes to solve 5 challenges"
echo

# Challenge 1: Detached HEAD Recovery
git checkout v1.0.0
echo "hotfix" > urgent.txt
git add urgent.txt
git commit -m "fix: urgent production hotfix"
# 💡 Your commit is in detached HEAD!
# TASK: Save this commit to a branch

# Challenge 2: Lost Commit Recovery
git checkout main
git branch -D feature/in-progress  # Oops, deleted!
# TASK: Recover the branch using reflog

# Challenge 3: Merge Conflict Resolution
git merge release/v2.0.0
# CONFLICT in config.json!
# TASK: Resolve intelligently, keep both features

# Challenge 4: History Rewriting
git log --oneline
# 5 messy commits about the same feature
# TASK: Squash into 1 clean commit

# Challenge 5: Git Hook Implementation
# TASK: Create pre-commit hook that:
# - Prevents commit if contains "password"
# - Runs unit tests
# - Validates commit message format

echo -e "\n🎉 ESCAPE COMPLETE!"
echo "Rate your confidence (1-5):"

Solutions available upon request in comments! 💬


🔗 Master Git with Hands-on Interview Prep

Git interview questions are designed to test not just what you know, but how you think about version control problems. The best preparation is hands-on practice with real scenarios.

👉 Practice Git interview questions and real-world scenarios in our interactive labs at:
https://devops.trainwithsky.com/

Our platform provides:

  • 50+ common Git interview questions with solutions

  • Real-time Git simulation environment

  • Merge conflict resolution challenges

  • Team collaboration scenarios

  • Emergency recovery drills

  • Personalized feedback on your Git workflow


Frequently Asked Interview Questions

Q: "I've used Git for years but always struggle with rebase. Is that okay?"

A: Honesty is better than bluffing. Say: "I primarily use merge in my daily work because I prefer preserving history context. I understand rebase conceptually and use it for cleaning up feature branches before PRs, but I'm more comfortable with merge for collaborative work." This shows self-awareness and strategic thinking.

Q: "What's the worst Git mistake you've made?"

A: Everyone has made mistakes. A good answer shows growth: "I once force-pushed to the main branch, overwriting a teammate's commits. Since then, I always use --force-with-lease, enable branch protection, and never force push to shared branches. I also wrote a team guide about Git safety."

Q: "How do you stay updated with Git?"

A: "I follow Git's release notes, subscribe to GitHub's changelog, and practice new features in side projects. I also participate in code reviews where I see how other developers solve Git problems."

Q: "Should we use GitFlow or GitHub Flow?"

A: "It depends on your deployment cadence. For continuous deployment, GitHub Flow is simpler and faster. For scheduled releases with multiple versions in production, GitFlow's release branches provide better isolation. I've implemented both and would recommend GitHub Flow for most modern teams."

Q: "How do you handle Git in a regulated environment?"

A: "I implement mandatory code reviews, signed commits, and comprehensive Git hooks for compliance checks. All merges to protected branches require passing CI, ticket references, and sign-offs. Every action is logged for audit trails."


Have a Git interview coming up? Facing a specific Git challenge? Share your scenario in the comments below, and our community will help you prepare! 💬

Comments

Popular posts from this blog

🚀 Introduction to Terraform – The Future of Infrastructure as Code

  Introduction to Terraform – The Future of Infrastructure as Code In today’s fast-paced DevOps world, managing infrastructure manually is outdated . This is where Terraform comes in—a powerful Infrastructure as Code (IaC) tool that allows you to define, provision, and manage cloud infrastructure efficiently . Whether you're working with AWS, Azure, Google Cloud, or on-premises servers , Terraform provides a declarative, automation-first approach to infrastructure deployment. Shape Your Future with AI & Infinite Knowledge...!! Want to Generate Text-to-Voice, Images & Videos? http://www.ai.skyinfinitetech.com Read In-Depth Tech & Self-Improvement Blogs http://www.skyinfinitetech.com Watch Life-Changing Videos on YouTube https://www.youtube.com/@SkyInfinite-Learning Transform Your Skills, Business & Productivity – Join Us Today! In today’s digital-first world, agility and automation are no longer optional—they’re essential. Companies across the globe...

📊 Monitoring & Logging in Kubernetes – Tools like Prometheus, Grafana, and Fluentd

  Monitoring & Logging in Kubernetes – Tools like Prometheus, Grafana, and Fluentd Monitoring and logging are essential for maintaining a healthy and well-performing Kubernetes cluster. In this guide, we’ll cover why monitoring is important, key monitoring tools like Prometheus and Grafana, and logging tools like Fluentd to help you gain visibility into your cluster’s performance and logs. Shape Your Future with AI & Infinite Knowledge...!! Want to Generate Text-to-Voice, Images & Videos? http://www.ai.skyinfinitetech.com Read In-Depth Tech & Self-Improvement Blogs http://www.skyinfinitetech.com Watch Life-Changing Videos on YouTube https://www.youtube.com/@SkyInfinite-Learning Transform Your Skills, Business & Productivity – Join Us Today! 🚀 Introduction In today’s fast-paced cloud-native environment, Kubernetes has emerged as the de-facto container orchestration platform. But deploying and managing applications in Kubernetes is just half the ba...

🔒 Kubernetes Security – RBAC, Network Policies, and Secrets Management

  Kubernetes Security – RBAC, Network Policies, and Secrets Management Security is a critical aspect of managing Kubernetes clusters. In this guide, we'll cover essential security mechanisms like Role-Based Access Control (RBAC) , Network Policies , and Secrets Management to help you secure your Kubernetes environment effectively. Shape Your Future with AI & Infinite Knowledge...!! Want to Generate Text-to-Voice, Images & Videos? http://www.ai.skyinfinitetech.com Read In-Depth Tech & Self-Improvement Blogs http://www.skyinfinitetech.com Watch Life-Changing Videos on YouTube https://www.youtube.com/@SkyInfinite-Learning Transform Your Skills, Business & Productivity – Join Us Today! 🚀 Introduction: Why Kubernetes Security Is Non-Negotiable As Kubernetes becomes the backbone of modern cloud-native infrastructure, security is no longer optional—it’s mission-critical . With multiple moving parts like containers, pods, services, nodes, and more, Kuberne...