Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ cd "$repo_root"
# Keep the per-check "n. ... / ok: ..." rundown quiet on a passing commit; show
# it only when something actually failed, so it's there to diagnose but doesn't
# scroll past on every commit.
if output=$(bash advanced/tests/check_consistency.sh 2>&1); then
if output=$(bash beyond/tests/check_consistency.sh 2>&1); then
status=0
else
status=$?
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_beginner_slides.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
# so fork PRs don't need a fresh manual approval after every auto-push.
git commit -m "Update beginner slides PDF [skip ci]"

# The sibling advanced-slides workflow can push to this same branch at
# The sibling beyond-slides workflow can push to this same branch at
# the same time (both trigger on shared slides_theme/** changes), so
# retry with a rebase if another push landed first.
for attempt in 1 2 3 4 5; do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ name: Build Marp Slides PDF
on:
pull_request:
paths:
- "advanced/slides/**"
- "beyond/slides/**"
- "slides_theme/**"
- ".github/workflows/build_advanced_slides.yml"
- "!advanced/slides/slides_advanced.pdf"
- ".github/workflows/build_beyond_slides.yml"
- "!beyond/slides/slides_beyond.pdf"

workflow_dispatch:

permissions:
contents: write

concurrency:
group: build-advanced-slides-${{ github.ref }}
group: build-beyond-slides-${{ github.ref }}
cancel-in-progress: true

jobs:
Expand All @@ -34,20 +34,20 @@ jobs:

- name: Build diagrams and PDF
# Same script authors run locally, so the committed PDF cannot drift.
run: ./advanced/slides/build.sh
run: ./beyond/slides/build.sh

- name: Commit updated diagrams and PDF to PR branch
run: |
git config user.name "GitHub Action"
git config user.email "action@github.com"

git add advanced/slides/images advanced/slides/slides_advanced.pdf
git add beyond/slides/images beyond/slides/slides_beyond.pdf
if git diff --cached --quiet; then
echo "Diagrams and PDF are already up to date."
else
# [skip ci] stops GitHub from queuing new workflow runs for this commit,
# so fork PRs don't need a fresh manual approval after every auto-push.
git commit -m "Update advanced slides diagrams and PDF [skip ci]"
git commit -m "Update beyond slides diagrams and PDF [skip ci]"

# The sibling beginner-slides workflow can push to this same branch at
# the same time (both trigger on shared slides_theme/** changes), so
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/content_consistency.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name: Content consistency
on:
pull_request:
paths:
- "advanced/**"
- "beyond/**"
- "beginner/**"
- ".github/workflows/content_consistency.yml"

Expand All @@ -20,4 +20,4 @@ jobs:
- uses: actions/checkout@v5

- name: Check that slides, exercises and diagrams agree
run: bash advanced/tests/check_consistency.sh
run: bash beyond/tests/check_consistency.sh
10 changes: 5 additions & 5 deletions .github/workflows/publish_pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches:
- main
paths:
- "advanced/slides/**"
- "beyond/slides/**"
- "beginner/slides/**"
- "slides_theme/**"
- "pages/**"
Expand Down Expand Up @@ -40,24 +40,24 @@ jobs:
# Same scripts authors run locally, so the published site cannot drift.
run: |
./beginner/slides/build.sh
./advanced/slides/build.sh
./beyond/slides/build.sh

- name: Assemble site
# The theme stylesheets reference the C2SM logo and the title background as
# ../../slides_theme/images/..., relative to the deck. That only resolves if
# the site mirrors the repository layout, so keep the <course>/slides/ depth
# and ship slides_theme/images alongside.
run: |
mkdir -p _site/slides_theme _site/advanced _site/beginner
mkdir -p _site/slides_theme _site/beyond _site/beginner

cp pages/index.html _site/index.html
cp -r slides_theme/images _site/slides_theme/

cp -r advanced/slides _site/advanced/
cp -r beyond/slides _site/beyond/
cp -r beginner/slides _site/beginner/

# Serve each deck at <course>/slides/ instead of a long file name.
mv _site/advanced/slides/slides_advanced.html _site/advanced/slides/index.html
mv _site/beyond/slides/slides_beyond.html _site/beyond/slides/index.html
mv _site/beginner/slides/slides_beginner.html _site/beginner/slides/index.html

# Sources and build inputs have no business on the published site.
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/test_helpers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ name: Test helper functions
on:
pull_request:
paths:
- "advanced/helpers.sh"
- "advanced/examples/**"
- "advanced/tests/**"
- "beyond/helpers.sh"
- "beyond/examples/**"
- "beyond/tests/**"
- "beginner/helpers.sh"
- "beginner/examples/**"
- "beginner/tests/**"
Expand Down Expand Up @@ -49,8 +49,8 @@ jobs:
git config --global user.email "action@github.com"
git config --global init.defaultBranch main

- name: Test the advanced helpers
run: bash git-course/advanced/tests/test_helpers.sh
- name: Test the beyond helpers
run: bash git-course/beyond/tests/test_helpers.sh

- name: Test the beginner helpers
run: bash git-course/beginner/tests/test_helpers.sh
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ git-course_env/
check_requirements.log

# HTML decks are built on demand by build.sh and published from CI, not committed.
advanced/slides/slides_advanced.html
beyond/slides/slides_beyond.html
beginner/slides/slides_beginner.html
_site/
4 changes: 2 additions & 2 deletions Expert_Topics.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ tutorial - none of it is needed for the two existing courses.
- **[Git: The Basics](beginner)** - `init`, `add`, `commit`, `status`, `log`, branches,
`switch`, `restore`, merging and merge conflicts, `.gitignore`, remotes, `push`, `pull`,
`fetch`, and a first pull request.
- **[Git: Beyond the Basics](advanced)** - `log`/`blame`/`diff`/`show` in depth, submodules,
- **[Git: Beyond the Basics](beyond)** - `log`/`blame`/`diff`/`show` in depth, submodules,
`.gitignore` in depth, `cherry-pick`, `rebase`, `stash`, `worktree`, hooks, `git lfs`, and the
issue → fork → pull request → review workflow.

Expand Down Expand Up @@ -59,7 +59,7 @@ Understanding what Git actually stores turns most of its odd behavior into commo

- **`git bisect`** - binary search through history to find the commit that broke something.
Manual (`git bisect start` / `good` / `bad`) and automated (`git bisect run <script>`, where the
script exits 0 for good, 1-127 for bad, and 125 to skip). This used to be in the advanced course
script exits 0 for good, 1-127 for bad, and 125 to skip). This used to be in the beyond course
and is a strong candidate for a third part.
- `git blame -C -M` - follow lines through file renames and moves between files.
- `blame.ignoreRevsFile` - hide bulk reformatting commits from every blame.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ working with branches, resolving merge conflicts, and pushing to a remote.

## Git: Beyond the Basics

The folder [advanced](advanced) contains the exercises for **Git: Beyond the Basics**. It picks up where
The folder [beyond](beyond) contains the exercises for **Git: Beyond the Basics**. It picks up where
the first course leaves off and needs nothing more than those basics. It has two parts: the
commands beyond the basics (reading history, submodules, cherry-pick and rebase, stash and
worktree, hooks, large files), and how a change travels through a shared project on a web
Expand All @@ -25,7 +25,7 @@ view, with the current slide, the next slide, the notes and a timer. The PDFs co
slides only.

The sources are [beginner/slides/slides.md](beginner/slides/slides.md) and
[advanced/slides/slides.md](advanced/slides/slides.md). To build a deck locally, run its
[beyond/slides/slides.md](beyond/slides/slides.md). To build a deck locally, run its
`build.sh` - it needs only Node.js and writes both the HTML and the PDF next to the source.
Pushing to `main` republishes the site.

Expand Down
2 changes: 1 addition & 1 deletion beginner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This folder contains the exercises for **Git: The Basics**, the introductory one of the two C2SM
Git Courses. Feel free to download the material to practice and enhance your Git skills.

Once you are comfortable with these, [Git: Beyond the Basics](../advanced) continues from here.
Once you are comfortable with these, [Git: Beyond the Basics](../beyond) continues from here.

The corresponding slides of this course can be found on our [C2SM User Landing Page](https://c2sm.github.io/events/git_courses/).

Expand Down
2 changes: 1 addition & 1 deletion beginner/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ commit_to_remote_by_third_party() {
cd conference_planning_remote_tmp
git checkout updated_schedules
cp ../conference_planning/schedule_day1.txt .
sed '3s/.*/09:00-11:00: Workshop Git for advanced/' schedule_day1.txt > schedule_day1_tmp.txt
sed '3s/.*/09:00-11:00: Workshop Git for Force-Pushers Anonymous/' schedule_day1.txt > schedule_day1_tmp.txt
mv -f schedule_day1_tmp.txt schedule_day1.txt
git add * && git commit -m "Git workshop in the morning"

Expand Down
42 changes: 37 additions & 5 deletions beginner/slides/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,53 @@ npx -y @marp-team/marp-cli@latest beginner/slides/slides.md \
--allow-local-files \
-o "$pdf"

# Marp stamps the PDF's CreationDate/ModDate with the current time on every build,
# which makes the file differ byte-for-byte even when nothing changed. That causes
# CI to commit a "changed" PDF on every run. Pin both dates to the epoch to keep
# the output reproducible.
# Two sources make the PDF differ byte-for-byte between runs even when nothing
# changed, which would make CI commit a "changed" PDF every time:
# - Marp stamps CreationDate/ModDate with the current time.
# - Headless Chrome numbers the tagged-PDF accessibility structure tree with
# "node<N>" ids drawn from a per-run counter, unrelated to the document content.
# Pin the dates and renumber the node ids deterministically to keep the output
# reproducible.
normalize_tmp=$(mktemp -d)
npm install --no-audit --no-fund --silent --prefix "$normalize_tmp" pdf-lib@1
NODE_PATH="$normalize_tmp/node_modules" node - "$pdf" <<'NODE'
const fs = require("fs");
const { PDFDocument } = require("pdf-lib");
const { PDFDocument, PDFDict, PDFArray, PDFStream, PDFString } = require("pdf-lib");

const NODE_ID_RE = /^node\d+$/;

(async () => {
const path = process.argv[2];
const doc = await PDFDocument.load(fs.readFileSync(path));
doc.setCreationDate(new Date(0));
doc.setModificationDate(new Date(0));

const renumbered = new Map();
const nextId = (oldId) => {
if (!renumbered.has(oldId)) {
renumbered.set(oldId, `node${String(renumbered.size).padStart(8, "0")}`);
}
return renumbered.get(oldId);
};

// Structure tree node ids are referenced from many objects scattered across
// the document, so walk every indirect object and rewrite each occurrence to
// a value based only on the order it is first encountered while enumerating
// objects in ascending, and therefore stable, object-number order.
const visit = (obj, set) => {
if (obj instanceof PDFString) {
const value = obj.asString();
if (NODE_ID_RE.test(value)) set(PDFString.of(nextId(value)));
} else if (obj instanceof PDFDict) {
for (const [key, value] of obj.entries()) visit(value, (v) => obj.set(key, v));
} else if (obj instanceof PDFArray) {
for (let i = 0; i < obj.size(); i++) visit(obj.get(i), (v) => obj.set(i, v));
} else if (obj instanceof PDFStream) {
visit(obj.dict, () => {});
}
};
for (const [, object] of doc.context.enumerateIndirectObjects()) visit(object, () => {});

fs.writeFileSync(path, await doc.save());
})();
NODE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ git log --oneline --author="Lauber"

</details>

**Task 7. (Bonus)** Show only the commits that changed the file *advanced/helpers.sh*.
**Task 7. (Bonus)** Show only the commits that changed the file *beyond/helpers.sh*.

<details><summary>💡 Hint</summary>

Expand All @@ -166,7 +166,7 @@ branch.
<details><summary>✅ Solution</summary>

```plaintext
git log --oneline -- advanced/helpers.sh
git log --oneline -- beyond/helpers.sh
```

</details>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ In this exercise you add a submodule, watch how Git keeps the two repositories s
move changes in both directions.

> [!IMPORTANT]
> **Where you work:** `advanced_git/conference_submodule`, a copy of the sandbox you make in the
> **Where you work:** `git_beyond/conference_submodule`, a copy of the sandbox you make in the
> first task below. This has nothing to do with the *git-course* repository you cloned: the
> sandbox lives in `advanced_git/`, a **separate** directory next to *git-course*. See
> sandbox lives in `git_beyond/`, a **separate** directory next to *git-course*. See
> [Where each exercise happens](README.md#where-each-exercise-happens) for the full map.
> If you have not created the sandbox yet, follow the [Setup section](README.md#setup) first.

Expand All @@ -33,19 +33,19 @@ In this exercise we cover the following:

## Add a submodule <a name="add"></a>

The sandbox is the repository `advanced_git/conference_planning`. We work on a **copy** of it, so
The sandbox is the repository `git_beyond/conference_planning`. We work on a **copy** of it, so
that the original stays usable for the later exercises. Three steps get you set up.

First, move to `advanced_git/`, the folder that *contains* the sandbox, so that you are not inside
First, move to `git_beyond/`, the folder that *contains* the sandbox, so that you are not inside
any repository:

```plaintext
cd ~/<path>/advanced_git
cd ~/<path>/git_beyond
```

Second, create the repository the submodule will point at. The course helper
`init_submodule_remote` builds a small one called *glossary-tool*, at
`advanced_git/glossary-tool.git`:
`git_beyond/glossary-tool.git`:

```plaintext
init_submodule_remote
Expand Down Expand Up @@ -73,15 +73,15 @@ cd conference_submodule
<details><summary>💡 Hint</summary>

The command is `git submodule add <url> <path>`. `init_submodule_remote` created the repository
at `~/<path>/advanced_git/glossary-tool.git` - use that path as the URL. A local filesystem path
at `~/<path>/git_beyond/glossary-tool.git` - use that path as the URL. A local filesystem path
works exactly like a GitHub URL here; Git does not care where a repository lives.

</details>

<details><summary>✅ Solution</summary>

```plaintext
git submodule add ~/<path>/advanced_git/glossary-tool.git c2sm-info
git submodule add ~/<path>/git_beyond/glossary-tool.git c2sm-info
```

</details>
Expand Down Expand Up @@ -234,7 +234,7 @@ without going into the repository yourself.

```plaintext
git push origin main
git -C ~/<path>/advanced_git/glossary-tool.git log --oneline -3
git -C ~/<path>/git_beyond/glossary-tool.git log --oneline -3
```

The submodule is an ordinary repository, so the push is an ordinary push. `glossary-tool.git` is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ effect on files Git is already tracking, and when a file mysteriously refuses to
is a command that tells you exactly why.

> [!IMPORTANT]
> **Where you work:** `advanced_git/conference_planning`.
> **Where you work:** `git_beyond/conference_planning`.
> If you have not created the sandbox yet, follow the [Setup section](README.md#setup) first.
> Confirm with `pwd` that you are inside *conference_planning*.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ In this exercise you use cherry-pick to rescue a single commit from a branch, th
merging and rebasing on the same starting point so you can see the difference in the history.

> [!IMPORTANT]
> **Where you work:** `advanced_git/conference_planning`.
> **Where you work:** `git_beyond/conference_planning`.
> If you have not created the sandbox yet, follow the [Setup section](README.md#setup) first.
>
> This exercise deliberately creates a complex history. If you lose track at any point, run
> `reset_advanced_repo` and start the section again.
> `reset_beyond_repo` and start the section again.

> [!TIP]
> Keep a second terminal open running the graph view from Exercise 1. After every step, look at
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ somewhere else. `git stash` puts your unfinished work aside for a moment. `git w
you a second directory so you never have to put it aside at all.

> [!IMPORTANT]
> **Where you work:** `advanced_git/conference_planning`, plus a second directory next to it that
> **Where you work:** `git_beyond/conference_planning`, plus a second directory next to it that
> you create in the worktree section.
> If you have not created the sandbox yet, follow the [Setup section](README.md#setup) first.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ In this exercise you write a `pre-commit` hook, watch it stop a bad commit, then
setup so several checks can run together.

> [!IMPORTANT]
> **Where you work:** `advanced_git/conference_planning`, specifically its *.git/hooks* directory.
> **Where you work:** `git_beyond/conference_planning`, specifically its *.git/hooks* directory.
> If you have not created the sandbox yet, follow the [Setup section](README.md#setup) first.

> [!NOTE]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ keeps the real bytes in a separate store. This exercise is entirely local, so yo
and no storage quota.

> [!IMPORTANT]
> **Where you work:** `advanced_git/conference_planning`.
> **Where you work:** `git_beyond/conference_planning`.
> If you have not created the sandbox yet, follow the [Setup section](README.md#setup) first.

> [!NOTE]
Expand Down
Loading
Loading