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:
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
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~5Task
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
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
doneTask
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 implementationSetup
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
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
- Rebase
feature/divergedonto the latestmain - Resolve all conflicts by keeping BOTH main's changes AND feature's changes (in that order)
- 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
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"
doneTask
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
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();
}
EOFTask
Create TWO separate commits from this single modified file:
- First commit: Only the login function bug fix
- 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
echo "important work" > important.txt
git add important.txt
git stash push -m "critical WIP"
git stash clearTask
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
# 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 initTask
Merge both repo-frontend and repo-backend into repo-combined such that:
- Frontend code lives in
frontend/directory - Backend code lives in
backend/directory - ALL commit history from both repos is preserved
- 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
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
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 mainTask
- Find the "lost" experimental commits
- Create a new branch called
feature/experimentpointing to those commits - 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
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
git checkout main
git branch release/v1
git branch release/v2
git branch release/v3
echo "security patch" > security-fix.jsTask
Apply security-fix.js to all three release branches with:
- Identical commit message:
security: patch CVE-2024-1234 - Identical commit timestamp
- 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 Completed | Level |
|---|---|
| 1-3 | Intermediate |
| 4-6 | Advanced |
| 7-9 | Expert |
| 10-12 | Git Master |
Additional Challenge
Complete all 12 questions, then write a single shell script that:
- Sets up a fresh repo
- Creates all the problematic scenarios
- Automatically fixes each one
- Verifies the fix was successful
Good luck! 🚀