feat(root03): author Git & Collaborative Development

Adds all 6 ROOT 03 modules (why version control exists, the Git mental model, everyday Git,
branching & merging, remote repositories, engineering Git workflow) — 31 activities. Uses only
real LOCAL Git repositories throughout — no Gitea account, no network access, and no
RootNode-canonical-repo credential is ever needed or exposed in a student Lab
(docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md §4). Modules 1, 2, and 6 are conceptual bookends with no
lab, matching the flexible readiness standard already used in ROOT 01/02.

Adds 3 new hands-on Git scenarios plus 2 MCQs: git-everyday-basics (init/add/commit, validated
by inspecting real `git log`/`git show` state, not just command output strings — Step 6's
explicit requirement), git-branching-and-merge (a REAL merge conflict caused on purpose by two
branches editing the same line, resolved by the student, validated by confirming the conflict
markers are gone and a real two-parent merge commit exists), and git-remote-clone-push (a real
local bare repository standing in for a remote — clone/commit/push validated by inspecting the
REMOTE side directly, not just the student's own clone). All tested end-to-end via the real
scenario-validation API, including negative tests.

Wires rootnode-git-fundamentals-assessment (2 required + 3 random-draw scenarios) using the
existing Phase 3B assessment engine.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-26 17:08:00 -05:00
co-authored by Claude Sonnet 5
parent e007bcf000
commit e68b6f445a
33 changed files with 1393 additions and 0 deletions
@@ -0,0 +1,40 @@
# Why Version Control Exists
## The problem: `final.txt`, `final_v2.txt`, `final_v2_ACTUALLY_FINAL.txt`
Before version control, "keeping history" usually meant copying a file with a new name every
time something changed. This fails fast: you lose track of WHAT changed between versions, WHO
changed it, and WHY — and it gets completely unworkable the moment more than one person touches
the same project.
## What version control actually gives you
- **History** — every change, in order, permanently. You can see exactly what a file looked
like at any point in the past.
- **Reproducibility** — you can recreate the EXACT state of an entire project at any past
moment, not just one file.
- **Collaboration** — multiple people can work on the same project without emailing files back
and forth or overwriting each other's work.
- **A source of truth** — one authoritative history everyone agrees is correct, instead of
"whoever has the newest-looking filename."
- **Rollback** — if a change turns out to be wrong, you can return to a known-good prior state
with confidence, not by hoping you kept a backup copy somewhere.
## Why copying files isn't version control
Copying `app.py` to `app_backup.py` before making a risky change LOOKS like version control, but
it has none of version control's real properties: no record of WHY the change was made, no way
to see incremental history, no way to combine two people's simultaneous edits, and no
scalability past a handful of files. Git (and version control generally) tracks CHANGES over
time as a structured history, not disconnected snapshots you have to manually manage.
## Instructor Notes
**Lesson goal:** Motivate Git before teaching a single command — students should feel the real
problem (the `final_v2_ACTUALLY_FINAL.txt` pattern) before the solution makes sense.
**Approximate timing:** 10 minutes read; 8 minutes live.
**Discussion question:** "Has anyone ever lost work, or overwritten someone else's work, because
of exactly this kind of file-copying problem?" (Real personal stories land this lesson far
better than abstract description.)
@@ -0,0 +1,31 @@
# Knowledge Check: Why Version Control Exists
---
**1. Name three real properties version control gives you that copying files as backups
doesn't.**
*Answer:* Any three of: structured history of every change, reproducibility of exact past
states, real collaboration between multiple people, a single agreed-upon source of truth,
confident rollback to a known-good state.
---
**2. Why does `final_v2_ACTUALLY_FINAL.txt` fail as a version-control strategy?**
*Answer:* It has no record of what changed or why between versions, doesn't scale past a
handful of files, and provides no way to merge two people's simultaneous changes.
---
**3. What does "source of truth" mean in the context of version control?**
*Answer:* One authoritative, agreed-upon history of a project that everyone treats as
correct — as opposed to ambiguity over which copy or filename is the "real" current version.
## Instructor Notes
**Facilitation:** Keep this brief — it's checking motivation/vocabulary before the hands-on
modules begin, not testing depth yet.
**Approximate timing:** 4 minutes.
@@ -0,0 +1,25 @@
# Reflection: Naming the Problem You're About to Solve
## Reflection questions
1. Have you personally ever lost work, or been confused about which file version was current,
in a way version control would have prevented?
2. What do you expect to feel DIFFERENT about how you work once you have real history and
rollback available?
## Real Ops takeaway
**Every engineering practice this program builds toward — code review, CI/CD, GitOps,
infrastructure as code — assumes version control as its foundation.** You cannot meaningfully
automate deployment, review changes before they ship, or declare infrastructure as code without
first having a reliable, structured history of what changed and when. This module named the
problem; the rest of ROOT 03 gives you the tool.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 1 tends to produce genuine, motivating
stories — let students share before moving to Module 2's mental model.
**Approximate timing:** 5 minutes live discussion; 3 minutes self-paced writing.
@@ -0,0 +1,59 @@
# Git Mental Model
## Three places your files can be
Git tracks your project through three distinct areas, and understanding this model is what
makes every Git command make sense — memorizing commands without it just produces confusion the
first time something doesn't behave as expected.
```
Working Tree → Staging Area → Repository (commit history)
(your actual (what you've (permanent,
files, as you marked ready recorded
edit them) to commit) snapshots)
```
- **Working tree** — the actual files on disk, exactly as you're editing them right now.
- **Staging area** (also called "the index") — a holding area for changes you've deliberately
marked as ready to be committed. This is Git's most distinctive design choice: you don't
commit "everything that changed," you commit "exactly what you staged."
- **Repository** — the permanent, recorded history of every commit ever made — this is what
`git log` shows you.
## Why `git add` exists at all
A change starts in your working tree. `git add <file>` moves it (conceptually — the mechanics
are more subtle, but this framing is enough for now) into the staging area. `git commit` takes
EVERYTHING currently staged and permanently records it as a new snapshot in the repository's
history. This two-step process (stage, then commit) exists so you can build up a commit
DELIBERATELY — staging exactly the related changes that belong together, even if your working
tree currently has other, unrelated changes you're not ready to commit yet.
## Core vocabulary
- **Commit** — one permanently recorded snapshot, with a message describing what changed and
why, and a unique identifier (a hash).
- **Branch** — a movable pointer to a specific commit, letting you develop something (a
"feature branch") without affecting the main line of history until you're ready to combine it
back in (Module 4).
- **HEAD** — Git's pointer to "which commit you're currently looking at" — almost always the
tip of whichever branch you have checked out.
- **Remote** — a reference to another copy of the same repository, usually hosted somewhere else
(Module 5).
## Instructor Notes
**Lesson goal:** Establish the three-area model BEFORE any commands — same "model before syntax"
pedagogy as ROOT 01's process model and ROOT 05's Kubernetes mental model. Every subsequent Git
command should be explainable in terms of moving something between these three areas.
**Approximate timing:** 15 minutes read; 10 minutes live, ideally with a literal diagram drawn
live (whiteboard or shared screen) showing files moving between the three areas.
**Common misconception to watch for:** assuming `git commit` commits every changed file
automatically — this is the single most common Git surprise for beginners, and it's exactly
what Module 3's Lab will make concrete.
**Discussion question:** "Why would you ever WANT to stage only some of your changes, not all
of them?" (Answer: to build one commit about ONE logical change, even if your working tree
currently has several unrelated edits in progress.)
@@ -0,0 +1,55 @@
# Demonstration: Watching a File Move Between the Three Areas
## OBSERVE
```
$ echo "draft" > report.txt
$ git status --short
?? report.txt
```
`??` means: Git sees this file, but it's in neither the staging area nor the repository yet —
purely in the working tree.
## HYPOTHESIS
Predict what `git status` will show after `git add report.txt`.
## INSPECT
```
$ git add report.txt
$ git status --short
A report.txt
```
`A` (in the LEFT column, which represents the staging area) means: staged, ready to commit.
## CHANGE
```
$ git commit -m "Add report draft"
$ git status --short
(nothing — clean)
```
## VERIFY
```
$ git log --oneline -1
a1b2c3d Add report draft
```
The file traveled through all three areas exactly as the model predicts: working tree (`??`) →
staging area (`A`) → repository (a permanent commit in `git log`).
## Instructor Notes
**Demo goal:** Make `git status`'s output legible by directly connecting its symbols (`??`, `A`,
clean) to the three-area model just taught, rather than treating them as arbitrary codes to
memorize.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** students reading `git status` output without connecting it
back to WHICH of the three areas each symbol refers to — reinforce the mapping explicitly.
@@ -0,0 +1,36 @@
# Knowledge Check: Git Mental Model
---
**1. Name the three areas a file passes through, in order.**
*Answer:* Working tree → staging area → repository (commit history).
---
**2. What does `git add` actually do, in terms of this model?**
*Answer:* Moves a change from the working tree into the staging area — marking it as ready to
be included in the next commit.
---
**3. If you edit three files but only `git add` one of them, what happens when you `git
commit`?**
*Answer:* Only the staged file is included in the new commit — the other two edited-but-unstaged
files remain as uncommitted changes in the working tree.
---
**4. What is HEAD?**
*Answer:* Git's pointer to the commit you're currently looking at — almost always the tip of
whichever branch you have checked out.
## Instructor Notes
**Facilitation:** Question 3 is the single most important check in this module — if students
get this wrong, revisit the diagram before continuing to Module 3.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,31 @@
# Guided Exercise: Predict `git status` Before You See It
This is a paper exercise — commit to a prediction before checking it in the Lab.
## Your task
Starting from a clean repository (nothing staged, nothing modified), predict what `git status
--short` would show after EACH of these actions, in sequence:
1. `echo "v1" > file.txt` (a brand new file)
2. `git add file.txt`
3. `echo "v2" >> file.txt` (modifying the ALREADY-STAGED file further)
4. `git commit -m "Add file"`
## A worked shape to check yourself against
1. `?? file.txt` — untracked, in the working tree only.
2. `A file.txt` — staged (left column).
3. `AM file.txt` — this is the surprising one: staged (`A`, left column) AND modified again
since staging (`M`, right column) — the staging area has a SNAPSHOT from step 2, and your
further edit in step 3 hasn't been staged yet.
4. Clean (nothing) — but only the STAGED version (from step 2, without the step-3 edit) actually
got committed; the step-3 edit remains as an uncommitted modification afterward.
## Instructor Notes
**Facilitation:** Item 3 is deliberately the hardest — it's the exact scenario that surprises
real beginners ("I thought I already staged this file, why does it show changes again?"). Worth
slowing down on.
**Approximate timing:** 10-12 minutes live discussion; 8 minutes self-paced.
@@ -0,0 +1,25 @@
# Reflection: The Model Explains the Commands, Not the Other Way Around
## Reflection questions
1. Before this module, would `git add` before `git commit` have seemed like an unnecessary
extra step? Why does it actually matter now?
2. Which of the three areas (working tree, staging, repository) do you feel least confident
distinguishing? What would help solidify it?
## Real Ops takeaway
**Every Git confusion you'll ever hit traces back to one of these three areas.** "Why isn't my
change in the commit," "why does `git status` show something weird," "why did my commit include
something I didn't mean to" — all of them are answerable by asking "which of the three areas is
this change actually in right now?" You now have that question available; Module 3 makes it
muscle memory.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 2 is worth a quick poll — knowing where
the class is least confident tells you where to slow down in Module 3's hands-on Lab.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,70 @@
# Everyday Git
## The commands you'll actually use constantly
Module 2 gave you the model. This module gives you the six commands that make up the vast
majority of real, everyday Git usage.
## `git init` — start tracking a project
```
$ git init
```
Creates a new, empty repository in the current directory (a hidden `.git` folder holds
everything). You only run this ONCE per project, at the very beginning.
## `git status` — where do things stand right now?
Shows what's staged, what's modified-but-unstaged, and what's untracked — the single most
useful command for orienting yourself, and one you'll run constantly, almost reflexively,
before and after almost every other Git command.
## `git add` — stage a change
```
$ git add file.txt # stage one specific file
$ git add . # stage everything currently changed
```
## `git commit` — permanently record what's staged
```
$ git commit -m "Add configuration loader"
```
A good commit message describes WHAT changed and, ideally, WHY — future-you (or a teammate)
reading `git log` months later should understand the change without re-reading the entire diff.
## `git log` — see the history
```
$ git log --oneline
a1b2c3d Add configuration loader
9f8e7d6 Initial commit
```
## `git diff` — see exactly what changed, before you commit it
```
$ git diff # unstaged changes vs. the last commit
$ git diff --staged # staged changes vs. the last commit
```
Reading your own diff before committing is one of the highest-value habits in this entire
course — catching an accidental leftover debug line, or a change you didn't mean to include,
BEFORE it becomes a permanent part of history.
## Instructor Notes
**Lesson goal:** Convert Module 2's model into the six commands used in nearly every real Git
session — this is the fluency floor for everything that follows in ROOT 03.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** treating `git add .` as always safe — it stages
EVERYTHING changed, including files you might not have intended to include; `git status` before
`git add .` is the habit that prevents this.
**Demo idea:** run the full init→status→add→commit→log→diff sequence live, narrating `git
status`'s changing output at each step.
@@ -0,0 +1,56 @@
# Demonstration: The Full Cycle, End to End
## OBSERVE
```
$ git init
$ git status --short
(nothing — empty repository)
```
## HYPOTHESIS
Predict what happens to `git status` after creating a new file.
## INSPECT
```
$ echo "v1" > app.py
$ git status --short
?? app.py
```
## CHANGE
```
$ git add app.py
$ git diff --staged
+v1
$ git commit -m "Add initial app.py"
```
`git diff --staged` shows exactly what's ABOUT to be committed — a real, final check before it
becomes permanent.
## VERIFY
```
$ git log --oneline
3f9a1c2 Add initial app.py
$ git status --short
(clean)
```
The complete cycle, verified with real evidence at each step — not "I think I committed it,"
but confirmed via `git log`.
## Instructor Notes
**Demo goal:** Show `git diff --staged` as the final safety check before a commit becomes
permanent — a habit worth building explicitly, not just mentioning in passing.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** skipping `git diff`/`git diff --staged` entirely and committing
on faith — a good moment to ask "how would you know if you accidentally staged the wrong
thing?"
@@ -0,0 +1,39 @@
# Knowledge Check: Everyday Git
---
**1. What's the difference between `git diff` and `git diff --staged`?**
*Answer:* `git diff` shows unstaged changes (working tree vs. last commit); `git diff --staged`
shows what's currently staged and about to be committed (staging area vs. last commit).
---
**2. Why is `git add .` potentially risky compared to `git add <specific-file>`?**
*Answer:* It stages EVERYTHING currently changed in the directory, which can accidentally
include files you didn't mean to commit — checking `git status` first (or using targeted `git
add`) avoids this.
---
**3. What makes a commit message actually useful months later?**
*Answer:* Describing WHAT changed and ideally WHY, clearly enough that someone (including
future-you) reading `git log` understands the change without re-reading the full diff.
---
**4. You run `git init` in a directory that already has an existing Git repository. What
happens?**
*Answer:* `git init` only needs to run once per project — running it again in an already-
initialized repository is harmless (it won't destroy existing history) but is never actually
necessary.
## Instructor Notes
**Facilitation:** Question 2 is a good moment to establish "check status before staging broadly"
as a house habit for the rest of the course.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,32 @@
# Guided Exercise: Plan a Real Commit Before You Make It
This is a paper exercise — commit to a plan before working in the Lab.
## Your task
You've made three unrelated changes to your working tree: fixed a typo in `README.md`, added a
new function to `utils.py`, and started (but not finished) an unrelated experiment in
`scratch.py` you're not ready to commit. Write out the exact sequence of commands you'd use to
end up with exactly ONE clean commit containing the README typo fix, leaving the other two files
alone.
## A worked shape to check yourself against
```
git status
git add README.md
git diff --staged
git commit -m "Fix typo in README"
git status
```
The key insight: `git add` lets you choose EXACTLY what goes into the next commit, regardless of
what else is sitting, unstaged, in your working tree — `utils.py` and `scratch.py` remain
untouched and uncommitted.
## Instructor Notes
**Facilitation:** This exercise directly tests whether Module 2's staging-area model actually
stuck — if students reach for `git add .`, that's a sign to revisit the model before the Lab.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
@@ -0,0 +1,24 @@
# Reflection: You Have Real, Permanent History Now
## Reflection questions
1. Look at your own `git log` from this module's Lab. Is your commit message something a
stranger (or future-you) could understand without more context?
2. Which of the six commands from this module do you expect to type the most, going forward?
## Real Ops takeaway
**A real, permanent, inspectable history of your work now exists — this is the actual thing
Module 1 named as missing from copy-a-file-as-backup.** Every commit you make from here on is
recoverable, comparable, and explainable. Module 4 builds on this by letting multiple lines of
work (branches) develop independently before combining — impossible without the reliable
history you just built the habit of creating.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 1 works well as a peer-review pass —
have students read a neighbor's commit message and guess what it changed, then compare.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,62 @@
# Branching and Merging
## Why branches exist
Without branches, every commit happens on the same single line of history — risky work and
finished work are indistinguishable, and two people can't develop different things
simultaneously without directly interfering with each other. A **branch** is a movable pointer
to a commit, letting you develop something in isolation and only combine it back into the main
line when it's actually ready.
## Creating and switching branches
```
$ git branch feature-login # create a new branch (doesn't switch to it)
$ git checkout feature-login # switch to it
$ git switch feature-login # the newer, clearer equivalent of checkout for this purpose
$ git checkout -b feature-login # create AND switch in one step
```
Commits made while on `feature-login` only affect that branch — `main` is completely unaffected
until you deliberately combine them.
## Merging: combining two branches' history
```
$ git checkout main
$ git merge feature-login
```
Git attempts to combine the two branches' history automatically. When the two branches changed
DIFFERENT parts of a project, this usually succeeds with no fuss.
## Divergence and conflicts
When both branches changed the SAME lines of the SAME file differently, Git can't automatically
decide which version is correct — this is a **merge conflict**. Git marks the conflicting
section directly in the file:
```
<<<<<<< HEAD
your current branch's version
=======
the incoming branch's version
>>>>>>> feature-login
```
A conflict is not an error you did something wrong — it's Git correctly refusing to silently
guess which change you actually want. You resolve it by editing the file to the content you
actually want (removing the markers), then staging and committing to complete the merge.
## Instructor Notes
**Lesson goal:** Frame merge conflicts as an EXPECTED, normal part of collaborative work — not
a sign of failure — before students hit their first real one in this module's Lab.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** panicking at the sight of conflict markers — reinforce
explicitly that this is Git behaving correctly, not breaking.
**Demo idea:** deliberately narrate a conflict as "Git is asking YOU to make a decision it
can't make safely on its own" rather than "something went wrong."
@@ -0,0 +1,61 @@
# Demonstration: A Conflict, Caused and Resolved on Purpose
## OBSERVE
Two branches both changed line 1 of `config.txt` — `main` to `"env=production"`, `feature` to
`"env=staging"`.
## HYPOTHESIS
Predict what `git merge feature` will do.
## INSPECT
```
$ git merge feature
Auto-merging config.txt
CONFLICT (content): Merge conflict in config.txt
Automatic merge failed; fix conflicts and then commit the result.
```
Exactly as predicted — Git refuses to guess.
## CHANGE
```
$ cat config.txt
<<<<<<< HEAD
env=production
=======
env=staging
>>>>>>> feature
```
Decide the real answer — here, say `env=production` is correct — and edit the file to exactly
that, deleting all three marker lines.
## VERIFY
```
$ git add config.txt
$ git commit -m "Merge feature, keep production config"
$ git log --oneline --graph
* a1b2c3d Merge feature, keep production config
|\
| * 9f8e7d6 Update from feature
* | 3d2c1b0 Update from main
|/
* 0a1b2c3 Initial commit
```
The graph shows exactly what happened: two lines of history, deliberately combined.
## Instructor Notes
**Demo goal:** Walk a real conflict from cause to resolution without skipping any step,
reinforcing that resolution means making an explicit CHOICE, not applying a trick.
**Approximate timing:** 10 minutes live.
**Common mistake to watch for:** leaving conflict markers accidentally in the "resolved" file
(easy to miss one) — `grep '<<<<<<<' file` before committing catches this reliably.
@@ -0,0 +1,36 @@
# Knowledge Check: Branching and Merging
---
**1. What is a branch, really?**
*Answer:* A movable pointer to a specific commit — not a copy of the whole project, just a
reference letting you develop independently from other branches.
---
**2. Why does a merge conflict happen?**
*Answer:* Both branches changed the SAME lines of the SAME file differently, and Git can't
safely guess which version you actually want — so it stops and asks you to decide.
---
**3. Is a merge conflict a sign something went wrong?**
*Answer:* No — it's Git correctly refusing to silently guess at a decision only a human should
make. It's a normal, expected part of collaborative work.
---
**4. After resolving a conflict by editing the file, what two steps complete the merge?**
*Answer:* Stage the resolved file (`git add`) and commit (`git commit`) — exactly like
completing any other commit, once the conflict markers are gone.
## Instructor Notes
**Facilitation:** Question 3 is worth stating explicitly and repeating — reframing conflicts
as normal, not scary, meaningfully changes how confidently students approach this module's Lab.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,36 @@
# Guided Exercise: Decide the Resolution Before You Touch the File
This is a paper exercise — commit to a decision before resolving anything in the Lab.
## Your task
A merge conflict shows:
```
<<<<<<< HEAD
timeout_seconds = 30
=======
timeout_seconds = 120
>>>>>>> feature
```
You know `main`'s value (30) was set deliberately for production safety, but `feature`'s value
(120) was added while debugging a slow endpoint that genuinely needs more time. Write out: what
final content would you put in the file, and why is that the RIGHT resolution (not just "pick
one side")?
## A worked shape to check yourself against
A well-reasoned resolution here is neither side alone: something like keeping `30` as the
DEFAULT but adding a comment or a separate, more specific setting for the slow endpoint
specifically — the point is that conflict resolution sometimes means genuinely combining intent
from both sides, not mechanically picking `HEAD` or the incoming branch. There's no single
"correct" file content — the value is in justifying whichever choice you make with real
reasoning, not defaulting to whichever side happens to be `HEAD`.
## Instructor Notes
**Facilitation:** The point of this exercise is resisting "just pick a side" as a reflex —
some conflicts genuinely require combining or renegotiating intent, not mechanical selection.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
@@ -0,0 +1,26 @@
# Reflection: Your First Conflict Wasn't a Disaster
## Reflection questions
1. Before this module, how would you have reacted to seeing conflict markers in a real file
for the first time?
2. What made resolving the conflict in this module's Lab feel manageable (or not)? What would
make a REAL conflict, in a large unfamiliar file, harder?
## Real Ops takeaway
**Merge conflicts are one of the most feared parts of Git for beginners, and one of the most
routine parts of Git for experienced engineers — the difference is just repetition.** You've now
caused one on purpose, resolved it deliberately, and verified the result — exactly the
experience that turns "conflicts are scary" into "conflicts are Tuesday." Module 5 adds a real
remote to this same workflow; conflicts show up there too, and you're now prepared for them.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 2 is worth extending into "what would
make a conflict on a 500-line file, with someone else's unfamiliar code, actually hard" — a good
honest preview of real collaborative work.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,56 @@
# Remote Repositories
## What a remote actually is
Every repository you've worked with so far has been entirely LOCAL — on this one machine. A
**remote** is a reference to another copy of the same repository, typically hosted somewhere
else (a server, or in this Lab, a second local repository playing that role). Remotes are what
make real collaboration possible: multiple people, multiple machines, all synchronizing through
one shared history.
## `origin`: a name, not a special concept
By convention, the remote you cloned FROM is named `origin` — but this is just a label Git
assigns automatically, not a technical requirement. You could name a remote anything; `origin`
is simply the default everyone recognizes.
## The four remote operations
- **`git clone <url>`** — copy an ENTIRE remote repository (full history included) to a new
local directory, automatically configuring it as `origin`.
- **`git fetch`** — download the remote's latest commits WITHOUT changing your own working
files or branches — a safe way to see what's new before deciding what to do about it.
- **`git pull`** — fetch AND immediately merge the remote's changes into your current branch —
effectively `fetch` + `merge` in one step (which is exactly why a `pull` can produce a merge
conflict, the same as Module 4's local merges).
- **`git push`** — upload your local commits to the remote, making them visible to everyone else
using that remote.
## Upstream: your branch's remote counterpart
A local branch can be configured to TRACK a specific remote branch (its "upstream") — once set,
plain `git pull`/`git push` (no extra arguments) know exactly which remote branch to sync
against, rather than requiring you to specify it every time.
## RootNode uses Gitea (this course does not)
RootNode's own engineering team uses Gitea (a self-hosted Git service) for its real work — the
CONCEPTS in this lesson (origin, clone, fetch, pull, push) are identical regardless of which
service hosts a remote (Gitea, GitHub, GitLab, or a private server). This course teaches those
concepts using a disposable LOCAL repository standing in for a remote — no account, no network
access, and no RootNode credentials are ever needed or exposed in this Lab.
## Instructor Notes
**Lesson goal:** Teach remotes as a genuine, transferable concept — students should be able to
work with ANY real Git hosting service afterward, not just this Lab's local simulation.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** treating `git pull` as a "safe, no-side-effects" command
— it's a merge, and merges can conflict, exactly like Module 4 taught.
**Discussion question:** "Why might a team prefer `git fetch` followed by manually reviewing
changes, over always running `git pull` directly?" (Answer: fetch lets you see what changed
before it touches your own working files/branch — useful caution before merging in unfamiliar
changes.)
@@ -0,0 +1,56 @@
# Demonstration: A Complete Clone-to-Push Round Trip
## OBSERVE
A bare (remote-style) repository already exists, currently empty.
```
$ git clone /srv/demo-remote.git /srv/demo-clone
warning: You appear to have cloned an empty repository.
```
Cloning an empty remote is completely normal — it just means no commits exist there yet.
## HYPOTHESIS
Predict what `git remote -v` will show inside the new clone.
## INSPECT
```
$ cd /srv/demo-clone && git remote -v
origin /srv/demo-remote.git (fetch)
origin /srv/demo-remote.git (push)
```
Automatically configured as `origin` — exactly as the lesson described, with no extra setup.
## CHANGE
```
$ echo "# Demo Project" > README.md
$ git add README.md
$ git commit -m "Add README"
$ git push origin main
```
## VERIFY
```
$ git --git-dir=/srv/demo-remote.git log --oneline
3f9a1c2 Add README
```
Checking the REMOTE directly (not the clone) proves the push actually reached it — the commit
now exists in two places, in sync.
## Instructor Notes
**Demo goal:** Prove the push actually worked by inspecting the REMOTE side independently,
not just trusting the clone's own `git log`.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** assuming a successful `git push` with no error message means
success without ever double-checking — worth reinforcing the "verify independently" habit from
earlier ROOT_ modules.
@@ -0,0 +1,40 @@
# Knowledge Check: Remote Repositories
---
**1. What's the difference between `git fetch` and `git pull`?**
*Answer:* `git fetch` downloads the remote's new commits without touching your working files or
branches. `git pull` does that AND immediately merges them into your current branch — it's
fetch + merge combined.
---
**2. Why can `git pull` produce a merge conflict?**
*Answer:* Because it performs a real merge under the hood — if your local branch and the
remote's branch both changed the same lines differently, the same conflict situation from
Module 4 can occur.
---
**3. Is `origin` a required, special name Git enforces?**
*Answer:* No — it's just the conventional default name Git assigns to the remote you cloned
from. You could name a remote something else; `origin` is a widely recognized convention, not a
technical requirement.
---
**4. Does this course require a GitHub or Gitea account to learn remotes?**
*Answer:* No — this course uses a disposable local bare repository to safely simulate a real
remote, teaching the same concepts (clone/fetch/pull/push/origin) without any account or network
access.
## Instructor Notes
**Facilitation:** Question 2 is worth emphasizing — many students assume `pull` is risk-free
until they hit their first real pull-conflict.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,30 @@
# Guided Exercise: Fetch First, Decide Second
This is a paper exercise — commit to a plan before working in the Lab.
## Your task
You're about to sync with a shared remote that a teammate has been actively pushing to all day.
You're not sure what they changed. Write out the SAFER sequence of commands (as opposed to
running `git pull` immediately), and explain what each step lets you verify before your own
working files are touched.
## A worked shape to check yourself against
```
git fetch origin
git log HEAD..origin/main --oneline
```
`git fetch` downloads the new commits without touching your branch. The `log` command then
shows you exactly what commits exist on the remote that you don't have locally yet — letting you
review WHAT changed before deciding to merge it in with a subsequent `git merge origin/main` (or
`git pull`, now that you already know roughly what to expect).
## Instructor Notes
**Facilitation:** This exercise directly builds the "fetch first, review, then merge" habit
real teams use on shared branches — worth connecting explicitly to why blind `git pull` on a
busy shared branch is a common source of surprise conflicts.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
@@ -0,0 +1,24 @@
# Reflection: You Just Practiced Real Collaboration, Safely
## Reflection questions
1. What would have felt different about this module's Lab if the remote were a real hosted
service (Gitea/GitHub) instead of a local simulation? What would have felt the same?
2. Where do you expect `push` to matter most in real engineering work you'll do later?
## Real Ops takeaway
**Everything you just practiced — clone, commit, push, verified independently on the remote
side — is the exact mechanism behind CI/CD and GitOps, which ROOT 11 covers later.** A CI
pipeline triggers because someone pushed; a GitOps deployment happens because a change was
pushed to a Git repository treated as the source of truth. You haven't just learned Git commands
— you've practiced the literal trigger mechanism modern deployment automation is built around.
This module is complete. Continue to the final module of this course.
## Instructor Notes
**Discussion questions for a live classroom:** question 2 previews ROOT 11's GitOps content
directly — worth naming that connection explicitly, even without teaching GitOps itself yet.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,54 @@
# Engineering Git Workflow
## Small commits, meaningful messages
A commit containing "fixed stuff" and 40 unrelated file changes is nearly useless to anyone
reading history later — including future-you. A commit that does ONE logical thing, with a
message describing what and why, is what actually makes `git log` a useful tool rather than
noise. This isn't pedantry — it's what makes rollback (below) and code review actually
practical.
## `main` as a protected source of truth
Real engineering teams treat their main branch as the one everyone trusts to be in a working
state at all times — direct, unreviewed pushes to `main` are typically restricted specifically
BECAUSE it's the shared source of truth every deployment and every other branch is built from.
Feature branches (Module 4) exist precisely so risky, in-progress work never threatens that
trust.
## Review: another set of eyes before history is permanent
Before a change reaches `main`, most real teams have someone else look at it first (a "pull
request" or "merge request," depending on the platform). This isn't about distrust — it's a
second perspective catching mistakes, and a natural point to discuss WHY a change is being made,
not just what it does.
## History and rollback as safety nets
Because every commit is permanent and inspectable, a bad change can be identified precisely (via
`git log`) and reverted deliberately — confident recovery, not panic, when something goes wrong.
This is Module 1's original promise, now fully realized: reproducibility and rollback aren't
theoretical, they're what your daily small-commit discipline actually buys you.
## Why this matters to DevOps, GitOps, and Infrastructure as Code
Everything in this lesson — small deliberate changes, a trusted source of truth, review before
merge, reliable history — is EXACTLY what CI/CD pipelines automate, what GitOps treats a Git
repository as authoritative for, and what Infrastructure as Code relies on to safely manage real
infrastructure through the same discipline you just practiced on plain text files. ROOT 11
builds directly on this course's habits, not a new set of ideas.
## Instructor Notes
**Lesson goal:** Close ROOT 03 by explicitly naming the professional discipline (not just Git
commands) this course was building, and its direct connection to DevOps/GitOps/IaC.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** treating "review" and "protecting main" as bureaucratic
overhead rather than genuine risk management — connect it back to the real cost of a bad change
reaching a shared source of truth unreviewed.
**Discussion question:** "Why might a team enforce small commits and review even when working
alone on a personal project?" (Good answers: future-you benefits from the same clarity; building
the habit now pays off the moment you DO work with others.)
@@ -0,0 +1,47 @@
# Demonstration: The Same Change, Told Two Ways
## OBSERVE
```
$ git log --oneline
a1b2c3d fixed stuff
```
One commit, an unhelpful message, and (imagine) 15 unrelated files changed together: a bug fix,
a typo correction, and an unrelated half-finished experiment.
## HYPOTHESIS
Predict: six months from now, could you (or a teammate) confidently `git revert` just the bug
fix from this commit, leaving the other 14 files untouched?
## INSPECT
No — reverting this ONE commit reverts everything in it together, including the unrelated
typo fix and experiment, whether you want that or not.
## CHANGE
The same work, done as three separate, well-described commits instead:
```
$ git log --oneline
3f9a1c2 Fix null-pointer crash in payment retry logic
9d8e7f6 Fix typo in onboarding email template
1a2b3c4 WIP: experiment with new caching strategy (not ready)
```
## VERIFY
Now `git revert 3f9a1c2` cleanly undoes JUST the payment bug fix, with zero effect on the other
two — because each commit is one logical, independently-reversible unit of work.
## Instructor Notes
**Demo goal:** Make the practical cost of "fixed stuff" commits concrete — not a style
preference, a genuine loss of capability (precise revert, clear history, easier review).
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** treating this as a purely aesthetic preference rather than a
practical one — reinforce the concrete "can you revert just the bug fix" test.
@@ -0,0 +1,32 @@
# Knowledge Check: Engineering Git Workflow
---
**1. Why does bundling unrelated changes into one commit cost you something real, not just
style points?**
*Answer:* It makes precise operations like `git revert` impossible to apply to just ONE logical
change — reverting the commit reverts everything in it together, whether you want that or not.
---
**2. Why do teams typically restrict direct, unreviewed pushes to `main`?**
*Answer:* `main` is the shared source of truth everything else (deployments, other branches) is
built from — protecting it reduces the chance an unreviewed mistake reaches something everyone
else depends on being trustworthy.
---
**3. Name one concrete way this course's Git discipline connects to GitOps or CI/CD.**
*Answer:* Any reasonable answer connecting small deliberate changes / a trusted source of truth
/ review-before-merge / reliable history to how CI/CD pipelines trigger on pushes or how GitOps
treats a Git repository as the authoritative record of desired infrastructure state.
## Instructor Notes
**Facilitation:** Question 3 is open-ended by design — the goal is students making the
connection in their own words, not reciting a fixed answer.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,30 @@
# Reflection: You've Practiced Real Engineering Discipline, Not Just Syntax
## Reflection questions
1. Look back across all six modules of ROOT 03. Which single habit (small commits, checking
`git status` before staging, fetch-before-pull, resolving conflicts deliberately) do you
think will matter most in real work?
2. This course started with "copying files as backup isn't version control." Can you now
explain, in one sentence, what Git actually gives you that copying never could?
## Real Ops takeaway
**Version control discipline is not a Git-specific skill — it's an engineering discipline that
happens to be exercised through Git.** Small deliberate changes, a trusted shared source of
truth, review before permanent history, and confident rollback are the same principles behind
CI/CD, GitOps, and Infrastructure as Code, all covered later in ROOT 11. You are not starting
that content from zero — you already practiced its foundation here.
This module — and ROOT 03 — is complete. Continue to ROOT 04: Containers & Docker.
## Instructor Notes
**Discussion questions for a live classroom:** question 2 is a good closing check — a clear,
confident answer here is real evidence the course's central premise landed.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced writing.
**Milestone note:** this is the last module of ROOT 03 — consider a brief recap connecting all
six modules (why version control → the three-area model → everyday commands → branching/
conflicts → remotes → professional workflow) before moving to ROOT 04.
@@ -0,0 +1,123 @@
-- Phase 6E — ROOT 03: Git & Collaborative Development. Adds 6 modules/activities under the
-- existing (PLANNED, zero-content) root-03-git-collaborative-development course row. Every lab
-- activity uses real LOCAL git repositories (including a local bare repo standing in for a
-- remote) — no Gitea account, no network access, no RootNode-canonical-repo credential ever
-- reaches a student Lab (docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md §4). Modules 1 and 6 are
-- conceptual bookends with no lab, matching the flexible readiness standard.
UPDATE courses SET
status = 'ready',
objectives = '{"Explain what version control gives you that copying files never could","Explain the working-tree/staging-area/repository model before memorizing commands","Use init/status/add/commit/log/diff fluently on a real repository","Create a branch, cause a real merge conflict, and resolve it deliberately","Clone, commit, and push to a real remote","Apply small-commit, reviewed, source-of-truth discipline"}',
updated_at = now()
WHERE course_id = 'root-03-git-collaborative-development';
INSERT INTO course_modules (module_id, course_id, title, description, sequence, objectives, prerequisites, estimated_duration_minutes, status) VALUES
('root-03-m01-why-version-control-exists', 'root-03-git-collaborative-development', 'Why Version Control Exists',
'History, reproducibility, collaboration, and rollback — the real problem Git solves, before any command. Target learner: has completed ROOT 02.',
1, '{"Explain what version control gives you that copying files does not","Explain why copying files as backup fails as a strategy"}', '{}', 20, 'ready'),
('root-03-m02-git-mental-model', 'root-03-git-collaborative-development', 'Git Mental Model',
'Working tree, staging area, repository — the model that makes every later command make sense. No lab — conceptual mastery via demonstrated reasoning.',
2, '{"Explain the working-tree/staging-area/repository model","Predict git status output from the model, not memorization"}', '{root-03-m01-why-version-control-exists}', 35, 'ready'),
('root-03-m03-everyday-git', 'root-03-git-collaborative-development', 'Everyday Git',
'init/status/add/commit/log/diff, against a real local repository.',
3, '{"Initialize and work in a real Git repository","Stage exactly the changes intended, verify with diff","Write a commit message that explains what and why"}', '{root-03-m02-git-mental-model}', 40, 'ready'),
('root-03-m04-branching-and-merging', 'root-03-git-collaborative-development', 'Branching & Merging',
'Real branches, a real merge conflict caused on purpose, and deliberate resolution.',
4, '{"Create and switch between branches","Explain why a merge conflict happens and that it is normal","Resolve a real merge conflict and complete the merge"}', '{root-03-m03-everyday-git}', 45, 'ready'),
('root-03-m05-remote-repositories', 'root-03-git-collaborative-development', 'Remote Repositories',
'Clone, fetch, pull, push against a real local-bare remote — no account or network required.',
5, '{"Clone a repository and explain origin","Distinguish fetch from pull and explain why pull can conflict","Push a real commit and verify it independently on the remote"}', '{root-03-m04-branching-and-merging}', 40, 'ready'),
('root-03-m06-engineering-git-workflow', 'root-03-git-collaborative-development', 'Engineering Git Workflow',
'Small commits, review, protecting main, and the direct bridge to CI/CD/GitOps/IaC. No lab — conceptual closer.',
6, '{"Explain why small, well-described commits matter beyond style","Explain why teams protect main and require review","Connect this course''s discipline to CI/CD and GitOps"}', '{root-03-m05-remote-repositories}', 30, 'ready')
ON CONFLICT (module_id) DO NOTHING;
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
-- M01 (no lab)
('root-03-m01-a01-lesson', 'root-03-m01-why-version-control-exists', 1, 'lesson', 'Why Version Control Exists',
'content/root/root-03-git-collaborative-development/m01-why-version-control-exists/01-lesson-why-version-control-exists.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-03-m01-a02-knowledge-check', 'root-03-m01-why-version-control-exists', 2, 'knowledge_check', 'Knowledge Check: Why Version Control Exists',
'content/root/root-03-git-collaborative-development/m01-why-version-control-exists/02-knowledge-check.md', NULL, NULL, 'manual_marker', 4, 'ready'),
('root-03-m01-a03-reflection', 'root-03-m01-why-version-control-exists', 3, 'reflection', 'Reflection: Naming the Problem You''re About to Solve',
'content/root/root-03-git-collaborative-development/m01-why-version-control-exists/03-reflection.md', NULL, NULL, 'manual_marker', 6, 'ready'),
-- M02 (no lab)
('root-03-m02-a01-lesson', 'root-03-m02-git-mental-model', 1, 'lesson', 'Git Mental Model',
'content/root/root-03-git-collaborative-development/m02-git-mental-model/01-lesson-git-mental-model.md', NULL, NULL, 'manual_marker', 15, 'ready'),
('root-03-m02-a02-demonstration', 'root-03-m02-git-mental-model', 2, 'demonstration', 'Demonstration: Watching a File Move Between the Three Areas',
'content/root/root-03-git-collaborative-development/m02-git-mental-model/02-demonstration-watching-a-file-move-between-areas.md', NULL, NULL, 'manual_marker', 8, 'ready'),
('root-03-m02-a03-knowledge-check', 'root-03-m02-git-mental-model', 3, 'knowledge_check', 'Knowledge Check: Git Mental Model',
'content/root/root-03-git-collaborative-development/m02-git-mental-model/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'),
('root-03-m02-a04-guided-exercise', 'root-03-m02-git-mental-model', 4, 'guided_exercise', 'Guided Exercise: Predict git status Before You See It',
'content/root/root-03-git-collaborative-development/m02-git-mental-model/04-guided-exercise-predicting-git-status.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-03-m02-a05-reflection', 'root-03-m02-git-mental-model', 5, 'reflection', 'Reflection: The Model Explains the Commands, Not the Other Way Around',
'content/root/root-03-git-collaborative-development/m02-git-mental-model/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'),
-- M03
('root-03-m03-a01-lesson', 'root-03-m03-everyday-git', 1, 'lesson', 'Everyday Git',
'content/root/root-03-git-collaborative-development/m03-everyday-git/01-lesson-everyday-git.md', NULL, NULL, 'manual_marker', 15, 'ready'),
('root-03-m03-a02-demonstration', 'root-03-m03-everyday-git', 2, 'demonstration', 'Demonstration: The Full Cycle, End to End',
'content/root/root-03-git-collaborative-development/m03-everyday-git/02-demonstration-the-full-everyday-cycle.md', NULL, NULL, 'manual_marker', 8, 'ready'),
('root-03-m03-a03-knowledge-check', 'root-03-m03-everyday-git', 3, 'knowledge_check', 'Knowledge Check: Everyday Git',
'content/root/root-03-git-collaborative-development/m03-everyday-git/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'),
('root-03-m03-a04-guided-exercise', 'root-03-m03-everyday-git', 4, 'guided_exercise', 'Guided Exercise: Plan a Real Commit Before You Make It',
'content/root/root-03-git-collaborative-development/m03-everyday-git/04-guided-exercise-planning-your-commit.md', NULL, NULL, 'manual_marker', 8, 'ready'),
('root-03-m03-a05-lab-everyday-basics', 'root-03-m03-everyday-git', 5, 'lab', 'Lab: Init, Track, Commit — Your First Real Repository',
NULL, 'git-everyday-basics', NULL, 'auto_scenario', 12, 'ready'),
('root-03-m03-a06-reflection', 'root-03-m03-everyday-git', 6, 'reflection', 'Reflection: You Have Real, Permanent History Now',
'content/root/root-03-git-collaborative-development/m03-everyday-git/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'),
-- M04
('root-03-m04-a01-lesson', 'root-03-m04-branching-and-merging', 1, 'lesson', 'Branching and Merging',
'content/root/root-03-git-collaborative-development/m04-branching-and-merging/01-lesson-branching-and-merging.md', NULL, NULL, 'manual_marker', 15, 'ready'),
('root-03-m04-a02-demonstration', 'root-03-m04-branching-and-merging', 2, 'demonstration', 'Demonstration: A Conflict, Caused and Resolved on Purpose',
'content/root/root-03-git-collaborative-development/m04-branching-and-merging/02-demonstration-a-conflict-happening-live.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-03-m04-a03-knowledge-check', 'root-03-m04-branching-and-merging', 3, 'knowledge_check', 'Knowledge Check: Branching and Merging',
'content/root/root-03-git-collaborative-development/m04-branching-and-merging/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'),
('root-03-m04-a04-guided-exercise', 'root-03-m04-branching-and-merging', 4, 'guided_exercise', 'Guided Exercise: Decide the Resolution Before You Touch the File',
'content/root/root-03-git-collaborative-development/m04-branching-and-merging/04-guided-exercise-choosing-a-resolution.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-03-m04-a05-lab-branching-and-merge', 'root-03-m04-branching-and-merging', 5, 'lab', 'Lab: Resolve a Real Merge Conflict',
NULL, 'git-branching-and-merge', NULL, 'auto_scenario', 15, 'ready'),
('root-03-m04-a06-reflection', 'root-03-m04-branching-and-merging', 6, 'reflection', 'Reflection: Your First Conflict Wasn''t a Disaster',
'content/root/root-03-git-collaborative-development/m04-branching-and-merging/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'),
-- M05
('root-03-m05-a01-lesson', 'root-03-m05-remote-repositories', 1, 'lesson', 'Remote Repositories',
'content/root/root-03-git-collaborative-development/m05-remote-repositories/01-lesson-remote-repositories.md', NULL, NULL, 'manual_marker', 15, 'ready'),
('root-03-m05-a02-demonstration', 'root-03-m05-remote-repositories', 2, 'demonstration', 'Demonstration: A Complete Clone-to-Push Round Trip',
'content/root/root-03-git-collaborative-development/m05-remote-repositories/02-demonstration-clone-commit-push.md', NULL, NULL, 'manual_marker', 8, 'ready'),
('root-03-m05-a03-knowledge-check', 'root-03-m05-remote-repositories', 3, 'knowledge_check', 'Knowledge Check: Remote Repositories',
'content/root/root-03-git-collaborative-development/m05-remote-repositories/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'),
('root-03-m05-a04-guided-exercise', 'root-03-m05-remote-repositories', 4, 'guided_exercise', 'Guided Exercise: Fetch First, Decide Second',
'content/root/root-03-git-collaborative-development/m05-remote-repositories/04-guided-exercise-fetch-vs-pull.md', NULL, NULL, 'manual_marker', 8, 'ready'),
('root-03-m05-a05-lab-remote-clone-push', 'root-03-m05-remote-repositories', 5, 'lab', 'Lab: Clone, Commit, and Push to a Real Remote',
NULL, 'git-remote-clone-push', NULL, 'auto_scenario', 12, 'ready'),
('root-03-m05-a06-reflection', 'root-03-m05-remote-repositories', 6, 'reflection', 'Reflection: You Just Practiced Real Collaboration, Safely',
'content/root/root-03-git-collaborative-development/m05-remote-repositories/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'),
-- M06 (no lab)
('root-03-m06-a01-lesson', 'root-03-m06-engineering-git-workflow', 1, 'lesson', 'Engineering Git Workflow',
'content/root/root-03-git-collaborative-development/m06-engineering-git-workflow/01-lesson-engineering-git-workflow.md', NULL, NULL, 'manual_marker', 15, 'ready'),
('root-03-m06-a02-demonstration', 'root-03-m06-engineering-git-workflow', 2, 'demonstration', 'Demonstration: The Same Change, Told Two Ways',
'content/root/root-03-git-collaborative-development/m06-engineering-git-workflow/02-demonstration-a-bad-commit-vs-a-good-one.md', NULL, NULL, 'manual_marker', 8, 'ready'),
('root-03-m06-a03-knowledge-check', 'root-03-m06-engineering-git-workflow', 3, 'knowledge_check', 'Knowledge Check: Engineering Git Workflow',
'content/root/root-03-git-collaborative-development/m06-engineering-git-workflow/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'),
('root-03-m06-a04-reflection', 'root-03-m06-engineering-git-workflow', 4, 'reflection', 'Reflection: You''ve Practiced Real Engineering Discipline, Not Just Syntax',
'content/root/root-03-git-collaborative-development/m06-engineering-git-workflow/04-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- ROOT 03 course assessment — mixes real Git-state-validation tasks with knowledge-recall MCQs
-- reasoning about the staging area and diverged branches, via the existing Phase 3B engine.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
INSERT INTO assessment_definitions (assessment_definition_id, type, title, description, duration_minutes, hint_policy, pool_spec, completion_rule)
VALUES (
'rootnode-git-fundamentals-assessment', 'exam', 'ROOT 03 Git & Collaborative Development Assessment',
'A timed check across everyday Git usage, branching/merge-conflict resolution, and remote workflows — combining real repository-state-validation tasks with conceptual reasoning questions.',
35, 'disabled',
'{"required": ["git-everyday-basics", "git-branching-and-merge"],
"random": [
{"count":1,"from":["git-remote-clone-push"]},
{"count":2,"from":["git-staging-area-mcq","git-diverged-branches-mcq"]}
]}',
'{"type":"all_scenarios_passed"}'
) ON CONFLICT (assessment_definition_id) DO NOTHING;
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-03-m06-a05-assessment', 'root-03-m06-engineering-git-workflow', 5, 'assessment', 'ROOT 03 Git & Collaborative Development Assessment', NULL, NULL, 'rootnode-git-fundamentals-assessment', 'auto_assessment', 35, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
@@ -0,0 +1,44 @@
{
"id": "git-branching-and-merge",
"title": "Resolve a Real Merge Conflict",
"category": "Git",
"isolation_type": "shared_namespace",
"difficulty": "Medium",
"type": "task",
"weight": 6,
"description": "## Resolve a Real Merge Conflict\n\nA repository at `/srv/git-lab-branch/` already has two branches (`main` and `feature`) that both changed the SAME line of `shared.txt` differently — merging them WILL conflict.\n\n**Your task:**\n\n1. Make sure you're on the `main` branch\n2. Merge `feature` into it: `git merge feature`\n3. Git will report a conflict — open `shared.txt` and you'll see conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)\n4. Edit the file to remove the markers and decide on final content (either version, both, or something new — your choice)\n5. Stage the resolved file and commit to complete the merge",
"hints": [
{
"title": "What the conflict markers mean",
"body": "Everything between `<<<<<<< HEAD` and `=======` is YOUR current branch's version; everything between `=======` and `>>>>>>> feature` is the incoming branch's version. Delete all three marker lines and keep whichever content (or combination) you actually want.",
"command": "cat /srv/git-lab-branch/shared.txt"
},
{
"title": "Completing the merge",
"body": "Once the file no longer has conflict markers, staging and committing tells Git the conflict is resolved.",
"command": "cd /srv/git-lab-branch\ngit add shared.txt\ngit commit -m 'Merge feature, resolve conflict'"
}
],
"setup_commands": [
{ "command": "git config --global init.defaultBranch main" },
{ "command": "git config --global user.email [email protected]" },
{ "command": "git config --global user.name 'RootNode Student'" },
{ "command": "rm -rf /srv/git-lab-branch && mkdir -p /srv/git-lab-branch" },
{ "command": "cd /srv/git-lab-branch && git init -q && echo 'original line' > shared.txt && git add shared.txt && git commit -q -m 'Initial commit'" },
{ "command": "cd /srv/git-lab-branch && git branch feature && git checkout -q feature && echo 'feature version' > shared.txt && git commit -qam 'Update from feature branch'" },
{ "command": "cd /srv/git-lab-branch && git checkout -q main && echo 'main version' > shared.txt && git commit -qam 'Update from main branch'" },
{ "command": "cd /srv/git-lab-branch && git merge feature 2>/dev/null; true" }
],
"validation": {
"commands": [
{ "description": "the feature branch still exists", "command": "git -C /srv/git-lab-branch branch --list feature | tr -d ' *'", "expected_output": "feature", "match": "exact" },
{ "description": "a real merge commit (two parents) exists", "command": "git -C /srv/git-lab-branch log --merges --oneline 2>/dev/null | wc -l | tr -d ' '", "expected_output": "^[1-9][0-9]*$", "match": "regex" },
{ "description": "the conflict markers were actually removed", "command": "grep -c '<<<<<<<' /srv/git-lab-branch/shared.txt", "expected_output": "0", "match": "exact" },
{ "description": "the working tree is clean (nothing left uncommitted)", "command": "git -C /srv/git-lab-branch status --short | wc -l | tr -d ' '", "expected_output": "0", "match": "exact" }
]
},
"default_namespace": "default",
"teardown_commands": [
{ "command": "rm -rf /srv/git-lab-branch" }
]
}
@@ -0,0 +1,22 @@
{
"id": "git-diverged-branches-mcq",
"title": "Your Branch and the Remote Have Diverged",
"category": "Git",
"isolation_type": "shared_namespace",
"difficulty": "Medium",
"type": "mcq",
"weight": 4,
"description": "## Your Branch and the Remote Have Diverged\n\n`git status` reports \"Your branch and 'origin/main' have diverged, and have 2 and 3 different commits each, respectively.\" What should you understand BEFORE blindly running `git pull`?",
"options": [
{ "id": "a", "text": "Nothing — git pull always resolves this automatically and safely with no side effects" },
{ "id": "b", "text": "That a pull here will attempt to merge (or rebase, depending on config) the remote's 3 commits with your own 2 local commits, which can itself produce a conflict you'll need to resolve — the same way two diverged branches did in this course's merge exercise" },
{ "id": "c", "text": "That you must delete your local commits first" },
{ "id": "d", "text": "That the remote repository is corrupted" }
],
"correct_option": "b",
"explanation": "\"Diverged\" means both sides have commits the other doesn't have — a plain `git pull` is really fetch-then-merge (or rebase), and merging two sets of independent commits can conflict exactly like the local branch-merge exercise did, just with a remote branch instead of a local one. Understanding this before pulling means you won't be surprised by a conflict, and you definitely don't need to delete anything or assume corruption.",
"hints": [],
"setup_commands": [],
"default_namespace": "default",
"teardown_commands": []
}
+34
View File
@@ -0,0 +1,34 @@
{
"id": "git-everyday-basics",
"title": "Init, Track, Commit — Your First Real Repository",
"category": "Git",
"isolation_type": "shared_namespace",
"difficulty": "Easy",
"type": "task",
"weight": 4,
"description": "## Init, Track, Commit — Your First Real Repository\n\n**Your task**, inside `/srv/git-lab-everyday/`:\n\n1. Initialize a new Git repository\n2. Create a file named `notes.txt` containing any text you like\n3. Stage and commit it, with a commit message that includes the word `notes`\n4. Confirm your work with `git log` and `git status`",
"hints": [
{
"title": "The full sequence",
"body": "`git init` creates the repository. `git add` stages a file (moves it from working tree to staging area). `git commit` records the staged snapshot permanently.",
"command": "cd /srv/git-lab-everyday\ngit init\necho 'my first notes' > notes.txt\ngit add notes.txt\ngit commit -m 'Add notes file'"
}
],
"setup_commands": [
{ "command": "mkdir -p /srv/git-lab-everyday" },
{ "command": "git config --global user.email [email protected]" },
{ "command": "git config --global user.name 'RootNode Student'" }
],
"validation": {
"commands": [
{ "description": "a real Git repository was initialized", "command": "git -C /srv/git-lab-everyday rev-parse --is-inside-work-tree 2>/dev/null", "expected_output": "true", "match": "exact" },
{ "description": "at least one commit exists", "command": "git -C /srv/git-lab-everyday log --oneline 2>/dev/null | wc -l | tr -d ' '", "expected_output": "^[1-9][0-9]*$", "match": "regex" },
{ "description": "notes.txt is tracked in the latest commit", "command": "git -C /srv/git-lab-everyday show --name-only --format= HEAD 2>/dev/null", "expected_output": "notes.txt", "match": "exact" },
{ "description": "the commit message mentions notes", "command": "git -C /srv/git-lab-everyday log -1 --pretty=%s 2>/dev/null", "expected_output": "notes", "match": "contains" }
]
},
"default_namespace": "default",
"teardown_commands": [
{ "command": "rm -rf /srv/git-lab-everyday" }
]
}
+35
View File
@@ -0,0 +1,35 @@
{
"id": "git-remote-clone-push",
"title": "Clone, Commit, and Push to a Real Remote",
"category": "Git",
"isolation_type": "shared_namespace",
"difficulty": "Medium",
"type": "task",
"weight": 5,
"description": "## Clone, Commit, and Push to a Real Remote\n\nA bare Git repository already exists at `/srv/git-lab-remote.git` — this plays the role of a real remote (like Gitea or GitHub) without needing any account or network access. It is currently empty.\n\n**Your task:**\n\n1. Clone it to `/srv/git-lab-clone`\n2. Inside the clone, create a file `README.md` with any content\n3. Add and commit it\n4. Push your commit back to the remote (`origin`)",
"hints": [
{
"title": "The full sequence",
"body": "`git clone` copies a remote repository (bare or not) into a new working directory, automatically configuring it as `origin`. `git push origin main` sends your local commits back to it.",
"command": "git clone /srv/git-lab-remote.git /srv/git-lab-clone\ncd /srv/git-lab-clone\necho '# My Project' > README.md\ngit add README.md\ngit commit -m 'Add README'\ngit push origin main"
}
],
"setup_commands": [
{ "command": "git config --global init.defaultBranch main" },
{ "command": "git config --global user.email [email protected]" },
{ "command": "git config --global user.name 'RootNode Student'" },
{ "command": "rm -rf /srv/git-lab-remote.git /srv/git-lab-clone" },
{ "command": "git init -q --bare /srv/git-lab-remote.git" }
],
"validation": {
"commands": [
{ "description": "the clone has origin configured pointing at the remote", "command": "git -C /srv/git-lab-clone remote get-url origin 2>/dev/null", "expected_output": "/srv/git-lab-remote.git", "match": "exact" },
{ "description": "the commit actually reached the remote (not just the local clone)", "command": "git --git-dir=/srv/git-lab-remote.git log --oneline 2>/dev/null | wc -l | tr -d ' '", "expected_output": "^[1-9][0-9]*$", "match": "regex" },
{ "description": "README.md is part of what was pushed", "command": "git --git-dir=/srv/git-lab-remote.git show --name-only --format= HEAD 2>/dev/null", "expected_output": "README.md", "match": "exact" }
]
},
"default_namespace": "default",
"teardown_commands": [
{ "command": "rm -rf /srv/git-lab-remote.git /srv/git-lab-clone" }
]
}
+22
View File
@@ -0,0 +1,22 @@
{
"id": "git-staging-area-mcq",
"title": "A Changed File That Won't Commit",
"category": "Git",
"isolation_type": "shared_namespace",
"difficulty": "Easy",
"type": "mcq",
"weight": 3,
"description": "## A Changed File That Won't Commit\n\nYou edit `config.py`, then run `git commit -m \"update config\"`. The commit succeeds, but when you check `git show`, your changes to `config.py` aren't in it. What Git state should you inspect first?",
"options": [
{ "id": "a", "text": "Whether config.py is even tracked by Git at all" },
{ "id": "b", "text": "The staging area — run `git status` to check whether your changes were actually staged with `git add` before you committed" },
{ "id": "c", "text": "Whether your internet connection is working" },
{ "id": "d", "text": "The remote repository's branch protection settings" }
],
"correct_option": "b",
"explanation": "`git commit` only records what's currently in the STAGING AREA, not every change in your working tree. A modified-but-unstaged file is invisible to the next commit — `git status` shows exactly this distinction (\"Changes not staged for commit\" vs. \"Changes to be committed\"), which is why checking the staging area is the right first step, not assuming the file isn't tracked or a network issue (Git is entirely local for this operation).",
"hints": [],
"setup_commands": [],
"default_namespace": "default",
"teardown_commands": []
}