This repo powers the Week 6 live demo: rebasing two feature branches, hitting a real merge conflict, and resolving it by intent — live, in VS Code, while narrating the decision-making out loud.
There is no AI or LLM in this demo. The focus is entirely on the Git workflow.
Two contributors have been working on the game night scheduler in parallel:
feature/dedup-games— added a duplicate check toadd_game()so the same game can't appear twice in the rotationfeature/random-picker— added apick_random()method and also modifiedadd_game()to shuffle the list on every insert
Both changes touch the same method. When you rebase feature/random-picker onto feature/dedup-games, git stops and asks you to decide what add_game() should look like.
The resolution preserves both intents: keep the dedup check, keep pick_random(), and drop the shuffle (because shuffling on every add_game() call is the wrong place for that randomness — pick_random() already handles it).
git clone <github-url>
cd ai201-week6-game-nightpip install -r requirements.txtA fresh clone only gives you a local main — the feature branches exist only as remote-tracking refs (origin/feature/...), and git rebase feature/dedup-games will fail with invalid upstream unless a local branch by that name exists. Create both:
git branch feature/dedup-games origin/feature/dedup-games
git branch feature/random-picker origin/feature/random-picker
git branchYou should now see local main, feature/dedup-games, and feature/random-picker.
pytest tests/ -vExpected output — 3 pass, 3 fail (the dedup and both pick_random tests fail on main, which is expected and intentional):
PASSED tests/test_scheduler.py::test_add_game
PASSED tests/test_scheduler.py::test_build_schedule_cycles_through_games
PASSED tests/test_scheduler.py::test_build_schedule_raises_with_no_games
FAILED tests/test_scheduler.py::test_add_game_skips_duplicates
FAILED tests/test_scheduler.py::test_pick_random_returns_a_game_from_rotation
FAILED tests/test_scheduler.py::test_pick_random_returns_none_when_rotation_is_emptyThe 3 failing tests are the spec for what the resolved code needs to satisfy. After conflict resolution, all 6 should pass.
code .Make sure the GitLens or built-in Source Control panel is visible. During the demo, VS Code will show the conflict markers inline with Accept/Ignore buttons — that's the UI you'll resolve in.
This file shows the correct resolved version with annotations. Do not share your screen while this tab is open — it's for your reference only. You can open it on a second monitor or a separate window.
Show students the two feature branches in the Source Control panel or by running:
git log --oneline --all --graphWalk through the history out loud:
"Here's what we've got.
mainhas the base scheduler, a summary method, and the test suite (plus this instructor guide). Then two contributors branched off and went in different directions. One was fixing a data quality issue — duplicate games in the rotation. The other was adding a feature — random game selection. Neither one knew what the other was doing."
git checkout feature/random-picker
git log --oneline"This branch has one commit: adding
pick_random()and a shuffle toadd_game(). We want to bring in the dedup work before we merge this to main. So we're going to rebase ontofeature/dedup-games."
git rebase feature/dedup-gamesGit stops with a conflict message. The terminal output will look something like:
CONFLICT (content): Merge conflict in scheduler.py
error: could not apply abc1234... feat: add pick_random method and shuffle rotation on add
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue"."Git is telling us it can't automatically combine these two changes. Both branches touched the same method. Let's go see what it looks like."
Open scheduler.py in VS Code. The conflict section will look like this:
def add_game(self, game: str) -> None:
<<<<<<< HEAD
"""Add a game to the rotation. Skips duplicates."""
if game not in self.games:
self.games.append(game)
=======
"""Add a game to the rotation and shuffle for varied order."""
self.games.append(game)
random.shuffle(self.games)
def pick_random(self) -> str | None:
"""Pick a random game from the rotation."""
return random.choice(self.games) if self.games else None
>>>>>>> b57ba5c (feat: add pick_random method and shuffle rotation on add)Note that the entire pick_random() method is inside the conflict block, on the incoming side — it was added directly below add_game() in the same commit, so git's conflict hunk swallows it along with the shuffle. This matters: clicking "Accept Current Change" wouldn't just discard the shuffle, it would silently delete pick_random() too, and both of its tests would fail.
Read both sides out loud:
"HEAD is
feature/dedup-games— it added a duplicate check before the append. The incoming change —feature/random-picker— changed the docstring, added a shuffle after the append, and brought the whole newpick_random()method with it. Git marked both versions and stopped. It doesn't know which one is right. That's our job."
"Before I touch anything — what was each change trying to do? The dedup branch was preventing data quality issues: the same game appearing twice in the rotation. The random-picker branch was trying to vary the order. Those are different goals. A resolution that only picks one side loses something."
Click "Accept Both Changes" in VS Code's conflict UI as a starting point. This gives you both versions stacked. Now manually edit so add_game() keeps the dedup check and drops the shuffle, while pick_random() stays intact below it:
def add_game(self, game: str) -> None:
"""Add a game to the rotation. Skips duplicates."""
if game not in self.games:
self.games.append(game)
def pick_random(self) -> str | None:
"""Pick a random game from the rotation."""
return random.choice(self.games) if self.games else NoneNarrate as you edit:
"I'm keeping the dedup check — that's the whole point of
feature/dedup-games. I'm dropping the shuffle. Here's why:pick_random()came in on this same commit, and it usesrandom.choice()to pick unpredictably at call time. Shuffling on everyadd_game()call is a side effect that callers don't expect — every time someone adds a game, the order of the list silently changes. That's a bug waiting to happen. The randomness belongs inpick_random(), not here."
Then point at pick_random():
"And notice
pick_random()was inside the conflict block — it rode in on the incoming side. If I'd just clicked 'Accept Current Change' to keep the dedup version, this whole method would have vanished and both of its tests would fail. That's why you read the entire hunk before clicking a button."
Make sure import random is at the top of the file (it was added by feature/random-picker).
git add scheduler.py
git rebase --continueGit will prompt for a commit message — keep the existing one or press :wq / save and close.
Then show the clean history:
git log --onelineOutput:
def4567 feat: add pick_random method and shuffle rotation on add
abc1234 fix: prevent duplicate games in rotation when add_game is called
789abcd chore: add pytest test suite and requirements
456def0 feat: add schedule summary and host display to scheduler
123abc9 feat: initialize game night scheduler with add and schedule methods"Linear history. No merge commit. If you squinted at this log, you'd never know two people worked on this in parallel. And notice why this rebase was safe: both branches lived only on this machine — nothing had been pushed. Local cleanup before anything is shared is the case where rebase shines."
pytest tests/ -vAll 6 tests pass:
PASSED tests/test_scheduler.py::test_add_game
PASSED tests/test_scheduler.py::test_build_schedule_cycles_through_games
PASSED tests/test_scheduler.py::test_build_schedule_raises_with_no_games
PASSED tests/test_scheduler.py::test_add_game_skips_duplicates
PASSED tests/test_scheduler.py::test_pick_random_returns_a_game_from_rotation
PASSED tests/test_scheduler.py::test_pick_random_returns_none_when_rotation_is_empty
6 passed in 0.12s"Both intents are preserved. The dedup test passes. The random picker tests pass. And the original baseline tests still pass — we didn't break anything."
git rebase doesn't produce a conflict — Check that you're on feature/random-picker before rebasing. If you accidentally ran the rebase from a different branch, git rebase --abort to reset and try again.
VS Code doesn't show the inline conflict UI — Make sure you're using VS Code 1.70 or later. The conflict markers are always in the file even if the UI doesn't render — you can resolve manually by deleting the <<<<<<<, =======, and >>>>>>> lines.
Tests fail after resolution — Open conflict_resolution.py and compare your resolved add_game() against it. The most common mistake is keeping the random.shuffle() line or accidentally deleting pick_random().
import random is missing from the top of the file — Add it manually below the existing imports. It was introduced by feature/random-picker but may have been dropped during an imperfect resolution.
Accidentally committed during rebase — Run git rebase --abort to return to the pre-rebase state and start over.
Resetting after a practice run — Once the rebase completes, feature/random-picker has moved. To restore the pre-demo state for the live run:
git checkout feature/random-picker
git reset --hard origin/feature/random-picker
git checkout main