DevOps · 35 Days · Week 2 Day 10 — Git Advanced Lab
1 / 22
Week 2 · Day 10 · Capstone

Git Advanced Lab

rebase -i, cherry-pick, bisect, reflog — the power commands that separate confident Git users from cautious ones. Week 2 capstone: everything comes together in one hands-on session.

⏱ Duration 60 min
📖 Theory 15 min
🔧 Lab 40 min
❓ Quiz 5 min
Week 2 Final Day Week 3 → CI/CD Starts Monday
Session Overview

What we cover today

01
git rebase -i — Rewrite History
Squash messy commits, reorder, edit messages. Clean history before PR.
02
git cherry-pick — Surgical Commits
Apply one specific commit from any branch to your current branch. Hotfix workflow.
03
git bisect — Find the Bug
Binary search through commit history. "Which commit broke this?" answered in minutes.
04
git reflog — Your Safety Net
Recover "lost" commits after hard reset, bad rebase, or accidental branch deletion.
05
git reset variants
--soft, --mixed, --hard — know exactly what each does and when to use it.
06
🔧 Lab — All 5 Commands Hands-On
Conflict → rebase -i → cherry-pick → bisect → reflog. The full advanced workout.
07
Week 2 Wrap-Up
Git mastery complete. Preview of Week 3 — CI/CD with GitHub Actions + Jenkins.
Part 1 of 4

git rebase -i — rewrite history & Merge vs Rebase vs Squash

🐧🪟 Interactive Rebase
# 4 messy commits → 1 clean commit
git rebase -i HEAD~4
# Editor opens — change actions:
# pick  d4f5a6b feat: add login form  ← keep
# fixup c2d8e3b fix typo             ← merge, drop msg
# fixup b1e9f4a oops forgot a file   ← merge, drop msg
# fixup a3f7c2d WIP: trying approach ← merge, drop msg
# Save → result:
git log --oneline
# e5g6h7i feat: add login form ✅ clean!

# ── rebase -i action keywords ────────
# pick   = keep as-is (default)
# squash = merge + keep message
# fixup  = merge + discard message ★
# reword = keep commit, edit message
# drop   = delete commit entirely
# reorder = drag lines to reorder

# Keep branch fresh daily:
git rebase origin/main
⚠ Golden Rule
Never rebase commits already pushed to a shared branch. Local / private branches only — rewrites SHA hashes and breaks teammates' history.
Comparison: Merge vs Rebase vs Squash
Feature Git Merge Git Rebase Git Squash
History Preserves original branch structure Creates linear, flat history Condenses multiple commits into one
Commit Type New Merge Commit
two-parent pointer
Re-applies commits
with new SHAs
Rewrites history
removes "noise"
Best For Public / shared branches — always safe Local feature branches before PR PR final merge — clean main history
Safe on shared? ✅ Always safe ❌ Rewrites SHAs ✅ Via PR only
💡 How all three combine in practice
Working daily: git rebase origin/main — stay fresh.
Before PR: git rebase -i HEAD~N — squash WIPs.
Merging to main: "Squash and merge" on GitHub — one clean commit.
The Decision Rule
Public branch? Merge — never rewrite.
Local feature branch? Rebase freely.
PR → main? Squash — keep main clean.
Part 2 of 4

git cherry-pick — surgical commit transplant

🐧🪟 cherry-pick
# === Scenario: hotfix needed from feature branch ===
# You're on main. A critical security fix is on feat/auth
# but that branch has unfinished features too.
# You only want the security fix commit.

# Step 1: Find the commit hash
git log feat/auth --oneline
# a1b2c3d feat: add OAuth flow        ← don't want this yet
# e4f5g6h fix: patch SQL injection     ← want THIS
# h7i8j9k feat: start user profile     ← don't want this

# Step 2: Cherry-pick only the security fix
git switch main
git cherry-pick e4f5g6h
# [main k1l2m3n] fix: patch SQL injection
# Applied as a new commit on main!

# === Cherry-pick a range of commits ===
git cherry-pick abc123^..def456   # from abc123 to def456 (inclusive)

# === Cherry-pick without committing (--no-commit) ===
git cherry-pick --no-commit e4f5g6h
# Applies changes to working directory but doesn't commit
# Useful: combine multiple cherry-picks into one clean commit

# === If cherry-pick causes conflict ===
# 1. Resolve the conflict in the file
# 2. git add resolved-file
# 3. git cherry-pick --continue
# OR: git cherry-pick --abort  (go back to before)

# === Real DevOps use case ===
# Bug fixed on a feature branch during development
# Production still needs the fix NOW — don't wait for the full feature
# cherry-pick the fix commit to main → deploy immediately
Cherry-pick use cases
  • Hotfix from feature branch — apply security fix to main without the incomplete feature
  • Backport to older version — fix is on v2, but v1 customers still need it
  • Wrong branch — committed to feat/a, want it on feat/b instead
  • Selective feature preview — only specific commits for a demo build
cherry-pick creates a new commit
cherry-pick does NOT move the original commit. It creates a new commit with the same changes but a different SHA. The original commit remains on its branch. Both commits coexist — just different branches have them.
Part 3 of 4

git bisect — find the bug commit in minutes

🐧🪟 git bisect
# === Scenario: production bug, 500 commits of history
# You know HEAD is broken. A week ago it worked.
# Which commit introduced the bug?

# Without bisect: check each commit = 500 checks worst case
# With bisect: binary search = max 9 checks for 500 commits!

# === Start bisect ===
git bisect start

git bisect bad              # HEAD is broken
git bisect good v2.1.0      # tag from 2 weeks ago was good
# Git checks out the MIDDLE commit automatically

# === Now test if the bug exists ===
# Run your tests, check the feature...
npm test                    # or any test command

git bisect good             # This commit is fine
# Git moves to the next midpoint (upper half now)

# Repeat: test → bisect good/bad → repeat
git bisect bad              # This one is broken
git bisect good             # This one is fine
# ... ~7-9 more iterations ...

# Git announces:
# a4b5c6d is the first bad commit
# commit a4b5c6d
# Author: Developer Name
# Date:   Mon Nov 4 14:22:31 2024
#     feat: refactor authentication middleware

# === Reset back to HEAD ===
git bisect reset

# === Automate: pass a test script ===
git bisect start
git bisect bad HEAD
git bisect good HEAD~50
git bisect run npm test     # Runs npm test automatically at each step!
# Git runs the script, marks good/bad automatically
# Finds the bug commit without manual testing!
Binary Search Magic
With 500 commits, bisect needs at most log₂(500) ≈ 9 steps. Without bisect you might check all 500. With a test script (git bisect run) the entire process is fully automated.
bisect run — fully automated

Write a test that exits 0 if good, non-zero if bad:

#!/bin/bash
# test-bisect.sh
node -e "require('./auth.js')"
# exits 0 if no crash, non-zero if crash
git bisect run ./test-bisect.sh

Git runs the script at each midpoint automatically. Zero manual work.

Part 4 of 4

git reflog — your safety net

🐧🪟 git reflog
# reflog = "reference log" = every move HEAD has ever made

git reflog
# HEAD@{0}: reset: moving to HEAD~3       ← oh no, hard reset!
# HEAD@{1}: commit: feat: add dashboard
# HEAD@{2}: commit: fix: handle null case
# HEAD@{3}: commit: chore: cleanup imports ← lost these 3 commits?!
# HEAD@{4}: checkout: moving from main to feat/auth
# HEAD@{5}: commit: feat: add login form

# === Recover "lost" commits after hard reset ===
git reset --hard HEAD~3     # Oops! Lost 3 commits
git reflog                  # Find the SHA before the reset
git reset --hard HEAD@{1}   # Restore to before the reset
# All 3 commits back! 🎉

# === Recover a deleted branch ===
git branch -D feat/important # Accidentally deleted!
git reflog
# HEAD@{2}: checkout: moving from feat/important to main
# Find the last commit hash on that branch
git checkout -b feat/important HEAD@{2}
# Branch restored!

# === Reflog for a specific branch ===
git reflog show feat/auth    # History of that branch's tip
git reflog show HEAD         # HEAD movements

# === Reflog expires — default 90 days ===
# git gc --prune=now removes unreferenced objects
# Act quickly if you need to recover something!
Why reflog is your safety net
Git almost never truly loses data. Every commit you've ever made is stored in .git/objects/ until garbage collection. reflog keeps a log of all HEAD movements — so you can recover from:

✅ Accidental git reset --hard
✅ Accidentally deleted branch
✅ Bad interactive rebase
✅ Lost stash
✅ Force push overwrite (local copy)
💡 First step when you panic
Something went wrong with Git? Don't panic. Run git reflog first. Your work is almost certainly still there. Find the SHA before the mistake and reset to it.
Essential Knowledge

git reset — --soft vs --mixed vs --hard

--soft (Safest)

git reset --soft HEAD~1

Moves HEAD back. All changes from the undone commit stay staged.

Before:
  HEAD → bad commit
  (staging: empty)

After:
  HEAD → previous commit
  staging: all changes
  from bad commit ← still here

Use when: Undo last commit but keep changes staged (ready to re-commit).

--mixed (Default)

git reset HEAD~1

Moves HEAD back. Changes stay in working directory (unstaged).

Before:
  HEAD → bad commit
  (staging: empty)

After:
  HEAD → previous commit
  working dir: all changes
  from bad commit ← modified,
                    unstaged

Use when: Undo commit AND unstage changes (re-examine before re-committing).

--hard (Destructive)

git reset --hard HEAD~1

Moves HEAD back. Changes are permanently discarded.

Before:
  HEAD → bad commit
  (working dir: changes)

After:
  HEAD → previous commit
  working dir: CLEAN ⚠️
  changes: GONE ← for real

Use when: Completely throw away the last commit AND its changes. Cannot undo (without reflog).

💡 Quick decision rule
Keep the changes? → --soft (staged) or --mixed (unstaged). Throw away everything? → --hard. When in doubt, use --soft — you can always discard later but you can't undo --hard without reflog.
Advanced Lab — Week 2 Capstone

🔧 All 5 Commands

40 minutes hands-on: conflict → rebase -i → cherry-pick → bisect → reflog. The full advanced Git workout.

⏱ 40 minutes
my-devops-app ✓
All Week 2 skills
🔧 Lab — 5 Exercises

Advanced Git exercises

1
Interactive Rebase — Clean History
Make 4 messy commits (WIP, typo, fix, real work). Use git rebase -i HEAD~4 to squash them into 1 clean commit. Verify with git log --oneline.
2
Cherry-pick — Transplant a Commit
Create a branch with 3 commits. Switch to main. Cherry-pick only the middle commit using its SHA. Verify it appears on main.
3
git bisect — Find the Bug Commit
Make 10 commits, inserting a "bug" at commit 7 (e.g. a file with "ERROR"). Use bisect with good and bad to find commit 7 in 3–4 steps.
4
git reflog — Recover Lost Work
Make 3 commits. Run git reset --hard HEAD~3. Panic. Open reflog. Find SHA before the reset. Restore all 3 commits.
5
git reset --soft vs --hard
Commit something. Run git reset --soft HEAD~1 — see changes still staged. Commit again. Run git reset --hard HEAD~1 — see changes gone.
🔧 Lab — Part 1: rebase -i + cherry-pick

Exercise 1 & 2 commands

Exercise 1 — rebase -i
cd my-devops-app

# === Make 4 messy commits ===
git switch -c lab/rebase-practice
echo "real feature code" > feature.js
git add feature.js && git commit -m "feat: add feature code"

echo "console.log('debug')" >> feature.js
git add feature.js && git commit -m "WIP: debugging"

echo "# comment" >> feature.js
git add feature.js && git commit -m "oops: add comment"

echo "// final" >> feature.js
git add feature.js && git commit -m "fix: cleanup"

git log --oneline
# 4 messy commits visible

# === Clean with interactive rebase ===
git rebase -i HEAD~4
# In editor: change last 3 "pick" → "fixup"
# pick  abc feat: add feature code
# fixup def WIP: debugging
# fixup ghi oops: add comment
# fixup jkl fix: cleanup
# Save and close editor

git log --oneline
# Only 1 commit: "feat: add feature code" ✅

# Clean up
git switch main
git branch -D lab/rebase-practice
Exercise 2 — cherry-pick
# === Create source branch with 3 commits ===
git switch -c lab/cherry-source
echo "file A" > fileA.txt && git add . && git commit -m "feat: file A"
echo "file B" > fileB.txt && git add . && git commit -m "fix: file B fix"
echo "file C" > fileC.txt && git add . && git commit -m "chore: file C"

# Note the hash of the middle commit ("fix: file B fix")
git log --oneline
# xyz789 chore: file C
# abc456 fix: file B fix    ← copy this hash
# def123 feat: file A

# === Cherry-pick to main ===
git switch main

# Check: fileB.txt does NOT exist yet
ls

git cherry-pick abc456     # Use YOUR hash
# [main mno012] fix: file B fix

# Verify: fileB.txt now exists on main
ls                         # fileB.txt appears!
git log --oneline          # New cherry-pick commit visible

# Clean up
git branch -D lab/cherry-source
🔧 Lab — Part 2: bisect + reflog + reset

Exercise 3, 4 & 5 commands

Exercise 3 — git bisect
# === Create 10 commits, bug at commit 7 ===
git switch -c lab/bisect-test

for i in 1 2 3 4 5 6; do
  echo "commit $i" >> history.txt
  git add . && git commit -m "chore: commit $i (clean)"
done

# Commit 7 = THE BUG
echo "ERROR: bug introduced here" > bug.txt
git add . && git commit -m "feat: commit 7 (introduces bug)"

for i in 8 9 10; do
  echo "commit $i" >> history.txt
  git add . && git commit -m "chore: commit $i (clean)"
done

# === Start bisect ===
git bisect start
git bisect bad HEAD          # Current commit is broken
git bisect good HEAD~10      # 10 commits ago was fine

# Git checks out middle → test → mark good/bad
# Check if bug.txt exists:
ls bug.txt 2>/dev/null && git bisect bad || git bisect good
# Repeat until Git finds the bad commit (~3-4 times)
# Git will say: "abc123 is the first bad commit"

git bisect reset             # Back to HEAD

# Automated version:
git bisect start
git bisect bad HEAD
git bisect good HEAD~10
git bisect run bash -c "! test -f bug.txt"
# Git finds commit 7 automatically!
git bisect reset
Exercise 4 — reflog recovery
# === Make 3 commits ===
echo "important A" > importantA.txt
git add . && git commit -m "feat: important A"
echo "important B" > importantB.txt
git add . && git commit -m "feat: important B"
echo "important C" > importantC.txt
git add . && git commit -m "feat: important C"

git log --oneline
# xyz important C
# mno important B
# abc important A
# ... main history

# === OOPS — hard reset removes 3 commits ===
git reset --hard HEAD~3
git log --oneline          # They're gone! 😱
ls                         # importantA/B/C.txt gone!

# === RECOVER with reflog ===
git reflog
# HEAD@{0}: reset: moving to HEAD~3
# HEAD@{1}: commit: feat: important C  ← before the reset

git reset --hard HEAD@{1}  # Restore to before the reset
git log --oneline          # All 3 commits back! 🎉
ls                         # Files restored!
Exercise 5 — reset variants
# Commit something
echo "test" > test.txt && git add . && git commit -m "test commit"

# --soft: changes stay STAGED
git reset --soft HEAD~1
git status                 # Changes in green (staged)

# Re-commit with better message
git commit -m "chore: better message"

# --hard: changes GONE (use reflog to verify)
git reset --hard HEAD~1
git status                 # Clean working directory
git reflog                 # Previous commit still in reflog
Knowledge Check

Quiz Time

3 questions · 5 minutes · cherry-pick, bisect, reflog

Final Week 2 knowledge check →
QUESTION 1 OF 3
What does git cherry-pick <hash> do?
A
Creates a new branch from that commit
B
Applies the changes from that specific commit onto the current branch as a new commit
C
Permanently deletes that commit from history
D
Reverts the last commit on the current branch
QUESTION 2 OF 3
What is git bisect used for?
A
Splitting one commit into two separate commits
B
Finding which commit introduced a bug using binary search through history
C
Squashing multiple commits into one
D
Listing all branches in the repository
QUESTION 3 OF 3
Which command lets you view and recover "lost" commits after an accidental git reset --hard?
A
git log
B
git stash list
C
git reflog
D
git status
Day 10 — Week 2 Complete!

What you learned today

✂️
rebase -i
Squash WIP commits before PR. Clean history = better reviews.
🍒
cherry-pick
Apply one commit from any branch. Hotfix workflow. Backporting.
🔍
bisect
Binary search finds bug commit in log₂(n) steps. Automate with bisect run.
🛟
reflog
Safety net. Recover "lost" commits after hard reset, bad rebase, deleted branches.
🎉 Week 2 Complete!
5 days, full Git mastery:
Day 6: Fundamentals · Day 7: Branching · Day 8: PRs · Day 9: Hooks · Day 10: Advanced

Your my-devops-app repo now has: SSH auth, branch protection, merged PRs, Husky hooks, commitlint — and a clean professional commit history.
Monday — Week 3 Starts!
Day 11 — CI/CD Concepts & Jenkins

GitHub Actions + Jenkins pipelines. Every git push triggers a build. The pipeline catches what your local hooks missed. Week 2's Git foundation is now the trigger for everything in Week 3.

GitHub Actions Jenkins Pipelines YAML
📌 Week 2 Complete Review

All 5 days — Git mastery achieved

DayTopicKey SkillsLab Output
Day 6Git Fundamentals4 areas, add, commit, push, stash, .gitignoremy-devops-app on GitHub
Day 7Branching StrategiesGitHub Flow, GitFlow, TBD, merge/rebase/squashPR merged, branch protection enabled
Day 8Pull Requests & ReviewPR templates, code review, CODEOWNERSPR template + CODEOWNERS in repo
Day 9Git Hooks & AutomationHusky, lint-staged, commitlint.husky/ committed, bad commits blocked
Day 10 ✅Advanced Labrebase -i, cherry-pick, bisect, reflog, resetAll 5 exercises completed
Week 3 Preview — Days 11–15
  • Day 11 — CI/CD Concepts + Jenkins intro
  • Day 12 — GitHub Actions + Jenkins Pipelines
  • Day 13 — Testing in CI (Jest, coverage)
  • Day 14 — Artifacts & Package Management
  • Day 15 — Continuous Deployment + approval gates
Week 2 → Week 3 Connection
Week 3 CI/CD pipelines trigger on git push. They run on feature branches. They enforce PR review. They check commit messages. Every Week 2 concept becomes a CI/CD pipeline component in Week 3.
📌 Reference — Advanced Commands

Power commands — complete cheatsheet

CommandWhat it doesWhen to use
git rebase -i HEAD~NInteractive rebase — squash/reorder/edit N commitsBefore PR to clean history
git rebase origin/mainReplay branch on top of latest mainKeep branch fresh, prevent conflicts
git cherry-pick SHAApply one commit from any branch to currentHotfix, backport, wrong-branch commit
git cherry-pick A^..BApply a range of commitsMultiple related commits to transplant
git bisect startStart binary search for bad commitBug regression: "which commit broke this?"
git bisect run CMDAutomated bisect using a test scriptWhen you have a scripted pass/fail test
git reflogLog of all HEAD movementsFirst step when you think you lost work
git reset --soft HEAD~1Undo commit, keep changes stagedFix commit message, split commit
git reset --mixed HEAD~1Undo commit, keep changes unstagedRe-examine changes before re-committing
git reset --hard HEAD~1Undo commit + discard all changesCompletely throw away a bad commit
git log --oneline --graph --allVisual branch history in terminalUnderstanding branching state
git show SHAShow full diff + metadata of one commitInspect what a specific commit changed
git diff branch-a..branch-bAll differences between two branchesReview what a branch changed vs main
git shortlog -snCommit count per authorTeam contribution stats
📌 Decision Guide

Which command — for each situation

SituationCommandNotes
"I have 5 messy WIP commits before my PR"git rebase -i HEAD~5Squash/fixup into 1–2 logical commits
"A critical fix is on a feature branch — production needs it NOW"git cherry-pick SHAApply only that fix commit to main
"Something broke last week — I have 300 commits to check"git bisect startBinary search finds it in ~8 steps
"I ran git reset --hard and lost 3 commits"git reflogFind SHA before the reset, recover it
"I committed on the wrong branch"git cherry-pick + git resetCherry-pick to right branch, reset wrong one
"I want to undo the last commit but keep my changes"git reset --soft HEAD~1Changes stay staged — re-commit with better message
"I want to completely undo my last commit and changes"git reset --hard HEAD~1Destructive — use reflog if you change your mind
"I accidentally deleted a branch"git reflogFind the last SHA on that branch, recreate
"I need the same fix on both v1 and v2"git cherry-pickApply to both branches individually
"My branch is behind main — I want a clean base"git rebase origin/mainReplay your commits on latest main
📌 Rules to Live By

Rebase rules & Git philosophy

Safe to Rebase
  • ✅ Local commits not yet pushed
  • ✅ Your personal feature branch (nobody else is using it)
  • git rebase -i to clean up before first push
  • git rebase origin/main to keep branch fresh
Never Rebase These
  • main branch
  • develop branch
  • ❌ Any branch someone else has pulled
  • ❌ After running git push (shared)
Git Philosophy
Git gives you two options for history:

Honest history — merge commits, every WIP commit visible. Shows exactly how you worked.

Curated history — rebase/squash, clean logical commits. Shows what you built, not how.

Neither is wrong. Most teams use curated (squash merge) for main, honest for personal branches. Know which your team prefers.
💡 The Force Push Rule
After rebasing a pushed branch, you need to force push:
git push --force-with-lease (safe — fails if others pushed)
git push --force (dangerous — overwrites anything)
Always use --force-with-lease. Never --force on shared branches.
📌 Week 2 Complete Cheatsheet

All Week 2 commands — one page

Daily Git Workflow
# Morning: sync
git switch main && git pull
git switch feat/my-feature
git rebase origin/main     # keep fresh

# Working
git status && git add -p
git commit -m "feat: ..."  # commitlint enforced

# Before PR: clean history
git rebase -i HEAD~N       # squash WIP commits
git push origin feat/my-feature

# Hotfix needed
git cherry-pick SHA        # take fix from feature

# After PR merge: cleanup
git switch main && git pull
git branch -d feat/my-feature
git fetch --prune
Emergency & Recovery
# Panic: lost commits
git reflog                 # find SHA
git reset --hard SHA       # restore

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

# Find which commit broke it
git bisect start
git bisect bad HEAD
git bisect good TAG
git bisect run TEST_CMD
git bisect reset

# Oops: wrong branch commit
git log --oneline          # note SHA
git switch correct-branch
git cherry-pick SHA        # move it
git switch wrong-branch
git reset --hard HEAD~1   # remove it

# Hooks bypass (emergency only)
git commit --no-verify -m "..."
Week 3 Preview

CI/CD starts Monday — Day 11

DayTopicWhat You'll BuildTools
Day 11CI/CD Concepts + JenkinsJenkins vs GitHub Actions comparison pipelineJenkins, YAML
Day 12GitHub Actions + Jenkins PipelinesMulti-job pipeline with parallel tests + Jenkins DeclarativeGH Actions, Jenkinsfile
Day 13Testing in CIJest unit tests + coverage gate in CIJest, Istanbul
Day 14Artifacts & Package ManagementDocker image build + push to registry in pipelineDocker, GHCR
Day 15Continuous DeploymentFull CD pipeline with staging + prod approval gateGitHub Actions, Environments
How Week 2 Powers Week 3
Every Day 11–15 pipeline builds on Week 2:
git push → triggers the pipeline (Day 6)
Feature branch PR → CI runs on PR (Day 7)
PR review required → branch protection (Day 8)
Commit message format → changelog in pipeline (Day 9)
Clean history → readable pipeline runs (Day 10)
Weekend Challenge
Before Week 3 starts — practice once more:

  1. Create a feature branch
  2. Make 4 messy commits
  3. rebase -i to 1 clean commit
  4. Open a PR with description
  5. Merge + cleanup

This is your Day 11 starting point.