Skip to content

Git Advanced Practical Lab - Set 1

Difficulty: Hard
Time: 90-120 minutes
Prerequisites: Basic git commands (add, commit, push, pull, branch, merge)


Setup Instructions

Before starting, create a practice repository:

bash
mkdir git-lab && cd git-lab
git init
echo "# Project Alpha" > README.md
git add README.md
git commit -m "Initial commit"

Question 1: The Accidental Reset

Scenario

You were working on a feature branch with 5 commits. You accidentally ran git reset --hard HEAD~5 and lost all your work. The commits are not pushed to remote.

Setup

bash
git checkout -b feature/payments
echo "payment v1" > payment.js && git add . && git commit -m "feat: add payment module"
echo "payment v2" >> payment.js && git add . && git commit -m "feat: add stripe integration"
echo "payment v3" >> payment.js && git add . && git commit -m "feat: add webhook handler"
echo "payment v4" >> payment.js && git add . && git commit -m "fix: handle duplicate webhooks"
echo "payment v5" >> payment.js && git add . && git commit -m "test: add payment tests"

# Simulate the accident
git reset --hard HEAD~5

Task

Recover all 5 commits and restore the branch to its previous state.

Hint

Git keeps a log of where HEAD has been.


Question 2: Surgical Commit Extraction

Scenario

You have a develop branch with 10 commits. Commits 3, 5, and 8 contain critical bug fixes that need to go to main immediately, but the other commits are not ready for production.

Setup

bash
git checkout main
git checkout -b develop
for i in {1..10}; do
  echo "feature $i" > "file$i.txt"
  git add .
  if [[ $i -eq 3 || $i -eq 5 || $i -eq 8 ]]; then
    git commit -m "fix: critical bug fix #$i"
  else
    git commit -m "feat: work in progress $i"
  fi
done

Task

Apply ONLY commits 3, 5, and 8 to main branch in that order, without any of the other commits.

Expected Result

main should have exactly 3 new commits (the bug fixes), and develop should remain unchanged.


Question 3: The Messy History Cleanup

Scenario

Your branch has this commit history that needs to be cleaned up before PR:

* abc123 fix typo
* def456 WIP
* ghi789 more WIP  
* jkl012 actually fix the bug
* mno345 forgot to add file
* pqr678 initial implementation

Setup

bash
git checkout -b feature/messy-cleanup
echo "impl v1" > feature.js && git add . && git commit -m "initial implementation"
echo "forgotten" > forgotten.js && git add . && git commit -m "forgot to add file"
echo "impl v2" >> feature.js && git add . && git commit -m "actually fix the bug"
echo "wip" >> feature.js && git add . && git commit -m "more WIP"
echo "wip2" >> feature.js && git add . && git commit -m "WIP"
sed -i 's/wip/work/' feature.js && git add . && git commit -m "fix typo"

Task

Squash all commits into a single clean commit with the message: feat: implement user authentication

Constraint

Do NOT use git merge --squash. Use interactive rebase.


Question 4: The Diverged Branches

Scenario

Both main and your feature branch have diverged significantly. main has 3 new commits, and your branch has 4 commits. You need to rebase your work on top of the latest main.

Setup

bash
git checkout main
echo "base" > shared.txt && git add . && git commit -m "base commit"

git checkout -b feature/diverged
echo "feature line 1" >> shared.txt && git add . && git commit -m "feat: add feature 1"
echo "feature line 2" >> shared.txt && git add . && git commit -m "feat: add feature 2"
echo "feature line 3" >> shared.txt && git add . && git commit -m "feat: add feature 3"
echo "feature line 4" >> shared.txt && git add . && git commit -m "feat: add feature 4"

git checkout main
echo "main line 1" >> shared.txt && git add . && git commit -m "hotfix: urgent fix 1"
echo "main line 2" >> shared.txt && git add . && git commit -m "hotfix: urgent fix 2"
echo "main line 3" >> shared.txt && git add . && git commit -m "hotfix: urgent fix 3"

Task

  1. Rebase feature/diverged onto the latest main
  2. Resolve all conflicts by keeping BOTH main's changes AND feature's changes (in that order)
  3. Ensure the final history is linear

Expected Result

Linear history with main's 3 hotfixes followed by your 4 feature commits.


Question 5: The Bisect Investigation

Scenario

A bug was introduced somewhere in the last 20 commits. You need to find the exact commit that introduced the bug.

Setup

bash
git checkout main
for i in {1..20}; do
  if [ $i -eq 13 ]; then
    echo "function calculate() { return x / 0; }" > math.js  # Bug introduced here
  else
    echo "function calculate() { return x * $i; }" > math.js
  fi
  git add . && git commit -m "update: iteration $i"
done

Task

Use git bisect to find the commit that introduced the division by zero bug. The "test" is: check if math.js contains "/ 0".

Expected Output

Identify the exact commit hash where the bug was introduced.


Question 6: The Partial Staging

Scenario

You modified a file with both a bug fix and an unrelated feature. You need to commit them separately.

Setup

bash
cat > app.js << 'EOF'
function login(user, pass) {
  // TODO: implement
  return false;
}

function logout() {
  // TODO: implement
}

function dashboard() {
  // TODO: implement  
}
EOF
git add app.js && git commit -m "initial app structure"

# Now make multiple changes in one file
cat > app.js << 'EOF'
function login(user, pass) {
  // BUG FIX: validate inputs
  if (!user || !pass) return false;
  return authenticate(user, pass);
}

function logout() {
  clearSession();
  redirect('/login');
}

function dashboard() {
  // NEW FEATURE: add analytics
  trackPageView('dashboard');
  return renderDashboard();
}
EOF

Task

Create TWO separate commits from this single modified file:

  1. First commit: Only the login function bug fix
  2. Second commit: The logout and dashboard changes

Constraint

Use interactive staging (not manual file editing).


Question 7: The Lost Stash

Scenario

You stashed some important work, then accidentally ran git stash clear. The stash contained hours of work.

Setup

bash
echo "important work" > important.txt
git add important.txt
git stash push -m "critical WIP"
git stash clear

Task

Recover the cleared stash.

Hint

Stashes are stored as commit objects.


Question 8: The Multi-Root Merge

Scenario

You have two completely separate repositories that need to be merged into one, preserving all history from both.

Setup

bash
# Create first repo
mkdir repo-frontend && cd repo-frontend
git init
echo "React App" > README.md && git add . && git commit -m "frontend: initial"
echo "components" > components.js && git add . && git commit -m "frontend: add components"
cd ..

# Create second repo  
mkdir repo-backend && cd repo-backend
git init
echo "Node API" > README.md && git add . && git commit -m "backend: initial"
echo "routes" > routes.js && git add . && git commit -m "backend: add routes"
cd ..

# Create target repo
mkdir repo-combined && cd repo-combined
git init

Task

Merge both repo-frontend and repo-backend into repo-combined such that:

  1. Frontend code lives in frontend/ directory
  2. Backend code lives in backend/ directory
  3. ALL commit history from both repos is preserved
  4. The combined repo has a unified history

Question 9: The Commit Surgery

Scenario

Three commits ago, you accidentally committed a file with secrets (API key). You need to completely remove that file from ALL history, not just the current state.

Setup

bash
echo "normal code" > app.js && git add . && git commit -m "add app"
echo "API_KEY=sk_live_12345secret" > .env && git add . && git commit -m "add config"
echo "more code" >> app.js && git add . && git commit -m "update app"
echo "even more" >> app.js && git add . && git commit -m "more updates"

Task

Completely remove .env from the entire repository history. After completion, .env should not appear in any commit, and git log --all --full-history -- .env should return nothing.

Warning

This rewrites history. In real scenarios, rotate the exposed secrets immediately.


Question 10: The Detached HEAD Recovery

Scenario

You checked out a specific commit to investigate something, made some changes and committed them, then realized you're in detached HEAD state. Now you've switched to main and your commits seem "lost".

Setup

bash
git checkout main
echo "v1" > file.txt && git add . && git commit -m "version 1"
echo "v2" > file.txt && git add . && git commit -m "version 2"
echo "v3" > file.txt && git add . && git commit -m "version 3"

# Go to detached HEAD
git checkout HEAD~2

# Make commits in detached state
echo "experiment 1" > experiment.txt && git add . && git commit -m "experiment: try new approach"
echo "experiment 2" >> experiment.txt && git add . && git commit -m "experiment: it works!"

# "Lose" the commits by switching away
git checkout main

Task

  1. Find the "lost" experimental commits
  2. Create a new branch called feature/experiment pointing to those commits
  3. The branch should contain both experimental commits

Question 11: The Selective Revert

Scenario

A merge commit introduced bugs. You need to revert the merge but keep specific files that were correctly changed.

Setup

bash
git checkout main
echo "main code" > main.js && git add . && git commit -m "main initial"

git checkout -b feature/breaking
echo "good change" > good.js && git add . && git commit -m "good change"  
echo "bad change" > bad.js && git add . && git commit -m "bad change"
echo "another good" > another-good.js && git add . && git commit -m "another good"

git checkout main
git merge feature/breaking -m "Merge feature/breaking"

Task

Revert the merge commit but then re-apply ONLY the changes from good.js and another-good.js. The final state should have:

  • main.js (original)
  • good.js (from feature branch)
  • another-good.js (from feature branch)
  • bad.js (should not exist)

Question 12: The Atomic Multi-Repo Update

Scenario

You need to make the exact same commit across 3 different branches atomically - if one fails, none should be applied.

Setup

bash
git checkout main
git branch release/v1
git branch release/v2
git branch release/v3

echo "security patch" > security-fix.js

Task

Apply security-fix.js to all three release branches with:

  1. Identical commit message: security: patch CVE-2024-1234
  2. Identical commit timestamp
  3. If you encounter any conflict on any branch, rollback ALL changes across all branches

Constraint

Write a script or series of commands that handles the atomicity requirement.


Scoring Guide

Questions CompletedLevel
1-3Intermediate
4-6Advanced
7-9Expert
10-12Git Master

Additional Challenge

Complete all 12 questions, then write a single shell script that:

  1. Sets up a fresh repo
  2. Creates all the problematic scenarios
  3. Automatically fixes each one
  4. Verifies the fix was successful

Good luck! 🚀

Released under the MIT License.