Content update: Git for Advanced 2026 - #170
Draft
mjaehn wants to merge 39 commits into
Draft
Conversation
mjaehn
marked this pull request as draft
August 18, 2026 09:58
Renumber the exercises to follow the teaching order of the new two-part structure, and rewrite each one as tasks with optional hints instead of commands to paste. Exercises now state a goal and let participants work out the command, with Hint and Solution in collapsed blocks. Commands that are unguessable or destructive stay visible: hook bodies, git lfs syntax, anything near --force. Each exercise opens with a "Working directory" box and closes with a short "Check yourself" list. Exercise_1_git-log-diff-show.md -> Exercise_1_examining-history.md Exercise_8_git-submodule.md -> Exercise_2_submodules.md Exercise_3_gitignore.md -> Exercise_3_ignoring-files.md Exercise_6_git-cherry-pick.md -> Exercise_4_cherry-pick-rebase.md Exercise_4_git-stash-worktree.md-> Exercise_5_stash-worktree.md Exercise_7_git-hooks.md -> Exercise_6_hooks.md Exercise_5_git-workflow.md -> Exercise_8_web-workflow.md Exercise 4 absorbs Exercise_bonus_rebase.md, so merge and rebase are compared side by side rather than rebase being an optional extra. Exercise 7 on git lfs is new. Exercise 2 on git bisect is dropped and moves to Expert_Topics.md. Content fixes along the way: - git stash save -> git stash push -m (deprecated since Git 2.16) - hard-coded SHAs replaced with relative refs so Exercise 1 cannot rot - submodule target moved off a personal account to C2SM/c2sm-git-example - pandoc dropped from Exercise 3 in favour of tar, which needs no install - corrected the claim that pre-commit run --all-files only checks staged files - "master script" renamed to "dispatcher script" Closes #155 Closes #156
Three additions to the C2SM Marp themes, needed by the restructured slides: - .warning, an amber callout, replacing the achtung.gif used until now - .quote, a pull quote with attribution - table styling, since the themes had no table rule and the inherited Marp default is hard to read on the dark background Both the light and the dark theme get the same set, so a deck can switch between them without losing styling.
Adds 13 Mermaid diagram sources under advanced/slides/diagrams/, a shared mermaid-config.json carrying the C2SM palette, and build.sh, which renders them to SVG and then builds the PDF. CI now calls build.sh instead of an inline marp command, so a local build and the committed PDF cannot drift apart, and commits the rendered SVGs alongside the PDF so the VS Code Marp preview works without a render step. Note that marp-core's default HTML allow-list has no svg entry, so inline <svg> would be silently stripped. Referencing external .svg files as ordinary Markdown images avoids that entirely and needs no --html flag. Also adds a concurrency group to the build workflow, which previously pushed to the PR branch with no guard against racing itself.
Replaces the Parts 0-4 plus Bonus structure with a two-way split: - Part 1, Your Git Toolbox: log/blame/diff/show, submodules, ignoring files, cherry-pick and rebase, stash and worktree, hooks, git lfs - Part 2, Working Together on GitHub: why a shared workflow, the C2SM User Landing Page as a live example, issues, forks, pull requests, checks and previews, review, merging, keeping a fork in sync Deletes all 14 third-party raster screenshots, which came from dev.to, scaler.com, gitkraken.com, dzone.com and a 2019 tweet. They were 1.4 MB, could not be edited, were off-brand and blurred in the PDF. Twelve are replaced by the generated diagrams; achtung.gif becomes the .warning class and tweet.png becomes a pros and cons list. Every exercise signpost slide now names the working directory, so the information is in front of participants at the moment they need it. Also adds a GitHub and GitLab comparison slide, since C2SM works on both github.com and gitlab.ethz.ch and only the web interface and CI file differ; modernises the tools slide with gh, lazygit, delta and difftastic; and fixes the .gitkeep speaker notes, which were a verbatim copy of the .gitignore ones. The PDF drops from 2.4 MB to 1.7 MB.
init_advanced_repo used sed -i '/program/a text', which is GNU-only. BSD sed on macOS requires an argument to -i and does not accept that append syntax, so the helper that five exercises bootstrap from failed outright on a Mac. Replaces it with the idiom the beginner course adopted in #140: no -i, the POSIX "a\" plus literal newline form, and write-to-temp-then-move. Exposes it as an insert_after helper so the exercises can use it too instead of carrying their own sed one-liners. Also: - mkdir -> mkdir -p, since re-running the function used to fail - git init followed by git branch -m main -> git init -b main - adds reset_advanced_repo, so participants can start an exercise over; the beginner course has had an equivalent for a while Part of #147
Adds advanced/tests/test_helpers.sh, mirroring the beginner harness, with 10 assertions over insert_after, init_advanced_repo and reset_advanced_repo, including that the bootstrap is repeatable. Adds a workflow running both suites on ubuntu-latest, macos-latest and windows-latest. On Windows the steps use shell: bash, which is the Git Bash that ships with Git for Windows, so this exercises the platform #147 was raised about rather than a stand-in for it. Two pre-existing problems surfaced while wiring this up: - Neither harness exited non-zero on failure, so a CI job running them would have passed unconditionally. Both now propagate a failure. - The beginner harness tested get_default_branch_name before any repository existed, from a directory outside one. It only passed locally because developers tend to have a git repository above their checkout; on a clean runner the function would exit 1 and take the script with it. Moved to after init_simple_repo. Closes #147
The exercises used to span six working directories with no map anywhere, which was the most common source of confusion. Cuts that to four: dropping git bisect removes git-bisect-exercise, and worktrees are now created as siblings of conference_planning rather than inside a separate conference_worktree clone. advanced/README.md gains a directory tree, an exercise-to-directory table, and a Setup section. Moving the bootstrap here also decouples the exercises from each other: they used to link to Exercise 3 for it, which forced gitignore to come before submodules. schedule.md is rewritten for the two-part structure with a '26 column, plus notes for the next run: participants need to pair up for Exercise 8, and should fork c2sm-git-example once at the start rather than twice. Closes #156
"Git for Advanced" implied an expertise gate that does not exist: the course needs nothing beyond the everyday basics. The name described a level rather than a prerequisite, and put people off who were exactly the intended audience. Git for Beginners -> Git: First Steps Git for Advanced -> Git: Next Steps "Next" states the actual entry requirement, which is having done "First". The advanced/ and beginner/ directories deliberately keep their names. Renaming them would break the published landing-page links, the check_requirements.sh --beginner flag and every bookmark participants hold, and the issue is about how the courses are advertised rather than how the repository is laid out. Still to do outside this repository: the landing page entry in C2SM/c2sm.github.io, which also still advertises the 2025 slides, and the ETH technical training catalogue. Closes #162
A reading list of Git topics neither course covers: internals and the object model, history rewriting, recovery, debugging with history, merging in depth, large repositories, signing and automation, collaboration at scale, and configuration. Each entry says why it matters and names the commands to look up, rather than teaching them. It doubles as a syllabus draft should there ever be a third part. git bisect lands here, having been dropped from the advanced course.
Python was only ever needed for the git bisect checker script, and that exercise is gone. Removes requirements.txt, whose jupyterlab and bash_kernel entries had been stale since the 2025 move from JupyterLab to a plain terminal, and swaps the Python check in check_requirements.sh for a git lfs check, which Exercise 7 does need. This also removes the last obstacle to running the advanced course under Git Bash, which was getting a Python interpreter working there. Separately, .vscode/settings.json listed slides_theme/c2sm.css, which has not existed since the theme was split into light and dark variants during the Marp migration.
This content update was needed largely because the slides were migrated to Marp in July and the exercises were never updated to match. Nothing detected that drift; it was found by reading. These checks make the same drift fail a pull request instead. advanced/tests/check_consistency.sh verifies that: 1-2. the slides and the exercises on disk reference each other, both ways 3-4. every diagram used has a Mermaid source, and no source is orphaned 5. no raster images creep back into the slides 6-7. internal Markdown links and in-page anchors resolve 8. advanced/README.md lists every exercise 9-10. no accidental trailing whitespace, and files end with a newline It runs locally as well as in CI, like build.sh. Checks 9 and 10 are scoped to advanced/ and the root files this update owns. The beginner course uses trailing two spaces deliberately for Markdown hard breaks, so a repository-wide rule would misfire on it constantly; the check allows exactly-two-space breaks and flags everything else. Adds a ShellCheck workflow at severity=warning. beginner/helpers.sh is excluded: it has 16 pre-existing warnings about unquoted variables and unchecked cd, which are a separate cleanup rather than a regression to gate on here.
mjaehn
added a commit
to C2SM/c2sm-git-example
that referenced
this pull request
Aug 18, 2026
Matches the naming settled in C2SM/git-course#170 and what the landing page already publishes.
Settles the umbrella name over the two courses, and drops the outer numbering
that an earlier draft of the pull request description had used.
C2SM Git Courses
|-- Git: First Steps (beginner/)
`-- Git: Next Steps (advanced/)
|-- Part 1: Your Git Toolbox
`-- Part 2: Working Together on GitHub
The courses are deliberately not numbered. "First" and "Next" already carry
the sequence, so a "Part 1" and "Part 2" prefix would say it twice, and it
would collide with the two Parts inside the second course, leaving a Part 2
that contains a Part 1 and a Part 2.
It would also work against #162: labelling them Part 1 and Part 2 suggests you
need both, when they are separately attendable courses held months apart, and
making the second one approachable on its own was the point of that issue.
"C2SM Git Courses" also matches what the landing page already publishes.
Mermaid assigns a gitGraph cherry-pick commit a randomly generated id, which lands in a CSS class name in the SVG. It has no effect on how the diagram looks, but it made cherry-pick.svg differ on every single build. Since the build workflow commits the rendered SVGs back to the branch, that meant every CI run produced a spurious "Update advanced slides diagrams and PDF" commit for a diagram nobody had touched. Normalising the class name in build.sh makes two consecutive builds byte-identical. Uses the write-to-temp-then-move form rather than sed -i, for the same reason as advanced/helpers.sh: BSD sed on macOS requires an argument to -i, and build.sh is meant to run locally as well as on a runner.
Marp stamps CreationDate/ModDate with the current time on every build, so the PDF differs byte-for-byte even when nothing changed. That made CI commit a new PDF on every run, retriggering the workflow and requiring repeated approval. Pin both dates to the epoch after render.
Extends the half-day format to a 3/4 day (09:30-15:00, lunch 12:30-13:30). Part 1 keeps its original pacing shifted by 30 minutes; Part 2 is scaled up 3x to fill the afternoon.
The action's find walks from scandir ".", so generated paths are prefixed with "./". The exact-match exclude never matched without that prefix, so beginner/helpers.sh's pre-existing warnings were still gating the check.
…nto content-upate-advanced
Fork PRs require manual approval for every new commit's workflow runs; the bot's own PDF/diagram push was re-triggering content_consistency and itself, forcing repeat approvals.
Add concurrency guard, extract build steps into build.sh with reproducible PDF output (pinned timestamps), and skip CI on the auto-commit to avoid re-triggering approval on fork PRs.
…nto content-upate-advanced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Restructures the advanced course into two parts, replaces every slide image with a generated diagram, and rewrites the exercises so participants work things out instead of pasting commands.
Closes #147
Closes #155
Closes #156
Closes #162
Part of #165 (that issue also covers the beginner course, so it stays open).
Two-part structure
The old Parts 0–4 + Bonus become:
log/blame/diff/show, submodules, ignoring files,cherry-pickandrebase,stashandworktree, hooks, andgit lfs.git bisectis dropped (it moves toExpert_Topics.md),git lfsis added, andrebaseis promoted from the bonus into Exercise 4 alongsidecherry-pick.Exercises are renumbered to follow the teaching order:
Exercise_1_examining-history.mdExercise_1_git-log-diff-show.mdExercise_2_submodules.mdExercise_8_git-submodule.mdExercise_3_ignoring-files.mdExercise_3_gitignore.mdExercise_4_cherry-pick-rebase.mdExercise_6_git-cherry-pick.md+Exercise_bonus_rebase.mdExercise_5_stash-worktree.mdExercise_4_git-stash-worktree.mdExercise_6_hooks.mdExercise_7_git-hooks.mdExercise_7_git-lfs.mdExercise_8_web-workflow.mdExercise_5_git-workflow.md, rewrittenDiagrams
All 14 third-party raster screenshots are gone. In their place are 13 Mermaid sources in
advanced/slides/diagrams/, rendered to SVG byadvanced/slides/build.sh, which CI now runs instead of an inlinemarpcommand — so a local build and the committed PDF cannot drift apart. The two images with no diagram equivalent (achtung.gif,tweet.png) became a.warningCSS class and a pros/cons list.build.shnormalises one thing before committing: Mermaid gives agitGraphcherry-pick commit a random id that lands in a CSS class name, which madecherry-pick.svgdiffer on every build. Since the workflow commits the rendered SVGs back to the branch, that would have produced a spurious "Update advanced slides diagrams and PDF" commit on every CI run. Two consecutive builds are now byte-identical.Course renaming (#162)
"Git for Advanced" implied an expertise gate that does not exist. Under the umbrella name C2SM Git Courses, which is what the landing page already publishes, the two courses are now:
The
advanced/andbeginner/directories keep their names — renaming them would break the published landing-page links, thecheck_requirements.sh --beginnerflag and every bookmark.Still to do outside this repo: the landing-page entry
docs/events/git_courses.mdinC2SM/c2sm.github.io, and the ETH technical training website.Which folder for which exercise (#156)
Six working directories become four. Dropping bisect removes
git-bisect-exercise/, and worktrees are now created as siblings ofconference_planninginstead of inside a separateconference_worktree/clone.advanced/README.mdgains a directory map and an exercise → directory table, and every exercise opens with a> [!IMPORTANT] Working directory:box using the same wordinghelpers.shprints.Less guided exercises (#155)
Every exercise is now Goal → Tasks → collapsed Hint → collapsed Solution, with tasks stated as outcomes ("Find all commits that touch
helpers.sh") rather than commands. Anything unguessable or destructive stays visible: hook bodies,git lfs tracksyntax, and every--force-adjacent command. Each exercise ends with a Check yourself list.The time comes from the ~20 minutes bisect used to take.
Portability (#147)
advanced/helpers.shusedsed -i '/program/a text', which is GNU-only — soinit_advanced_repo, the bootstrap five exercises depend on, failed on macOS. It now uses the same portable idiom the beginner course adopted in #140 (no-i, POSIXa\+ newline, write-to-temp-then-move), and exposes it as aninsert_afterhelper the exercises use too.Also:
git stash save→git stash push -m(deprecated since Git 2.16)requirements.txt— it existed only for the bisect checker script. This removes the Git Bash blocker raised in Make sure Git course works on Linux and Git Bash terminal #147.pandocin Exercise 3 replaced withtar, which needs no extra install anywhereNew
advanced/tests/test_helpers.sh(10 assertions) mirrors the beginner harness, and a newtest_helpers.ymlworkflow runs both suites onubuntu-latest,macos-latestandwindows-latest.Note
Two pre-existing problems surfaced while wiring that up and are fixed here: neither test script exited non-zero on failure (so a CI job would always have passed), and the beginner script tested
get_default_branch_namefrom outside any repository — it only passed locally because developers happen to have a git repo above their checkout.Git Bash is genuinely covered, not merely reviewed.
windows-latestships Git for Windows, and a step withshell: bashruns under its Git Bash, so the workflow exercises the exact platform this issue was raised about rather than a stand-in for it. No manual pre-course check is needed.New: C2SM/c2sm-git-example
Part 2 needs somewhere safe to practise. https://github.com/C2SM/c2sm-git-example is now populated: Markdown pages about C2SM, a
CONTRIBUTING.md, issue and pull request templates, and achecks.ymlworkflow so participants see real status checks.Two content shapes are deliberate:
participants/<handle>.md— every participant's PR touches a unique file, so they never conflictglossary.md— shared and alphabetical, so PRs touching it do conflict, which is the point of the last part of Exercise 8Verified live: both checks pass on
mainand on a pull request (smoke-test PR opened, confirmed, then closed).C2SM/git-workflow-practiceis superseded and no longer referenced.New checks against future drift
This update was needed largely because the slides were migrated to Marp in July and the exercises were never updated to match — and nothing detected that. Two workflows now make the same drift fail a pull request.
content_consistency.ymlrunsadvanced/tests/check_consistency.sh, which verifies that the slides and the exercises reference each other in both directions, that every diagram used has a Mermaid source and no source is orphaned, that no raster images creep back in, that internal links and in-page anchors resolve, thatadvanced/README.mdlists every exercise, and that files have no accidental trailing whitespace and end with a newline. It runs locally too, likebuild.sh.The whitespace and newline rules are scoped to
advanced/plus the root files this update owns: the beginner course uses trailing two spaces deliberately for Markdown hard breaks, so a repository-wide rule would misfire on it constantly.shellcheck.ymllints the shell scripts atseverity=warning.beginner/helpers.shis excluded — it has 16 pre-existing warnings about unquoted variables and uncheckedcd, which are a separate cleanup rather than a regression to gate on here.Also
Expert_Topics.mdat the repo root — a backlog of what neither course covers (internals, history rewriting, recovery,bisect, large repositories, signing, collaboration at scale), and a syllabus draft should there ever be a Part 3gitlab.ethz.chtooadvanced/schedule.mdrewritten for the two-part structure with a'26columngh,lazygit,delta/difftastic, GitHub Desktop, JetBrains.vscode/settings.jsonpointing atslides_theme/c2sm.css, which does not exist.gitkeepspeaker notes, which were a verbatim copy of the.gitignoreonesVerification
.mmdsource and no.mmdis orphanedpr-<number>placeholder (inside backticks, not a link) and theExpert_Topics.mdlink, which resolves once this merges