From cf17f7a402d7953f8b868fe4c2cab9bbbfd52b2d Mon Sep 17 00:00:00 2001 From: Isaac Adjei Date: Fri, 16 Oct 2026 04:10:39 +0100 Subject: [PATCH] feat: add five practice modules and refresh the existing content Closes #27 --- .github/workflows/markdownlint.yml | 4 +- CHANGELOG.md | 11 ++++ CONTRIBUTING.md | 62 +++++++++--------- README.md | 10 ++- docs/command-reference.md | 55 ++++++++++++++++ docs/github-ui-vs-terminal.md | 6 +- docs/glossary.md | 64 ++++++++++++++++++- .../08.1-exercise/example-workflow.yml | 4 +- practice/11-gitlab/11.1-exercise/README.md | 31 +++++++++ .../11.1-exercise/example-gitlab-ci.yml | 26 ++++++++ .../11-gitlab/11.2-extra-practice/README.md | 15 +++++ practice/11-gitlab/11.3-self-test/README.md | 14 ++++ practice/11-gitlab/README.md | 13 ++++ .../12.1-exercise/README.md | 32 ++++++++++ .../12.2-extra-practice/README.md | 14 ++++ .../12.3-self-test/README.md | 13 ++++ practice/12-signing-and-security/README.md | 13 ++++ .../13.1-exercise/README.md | 30 +++++++++ .../13.2-extra-practice/README.md | 15 +++++ .../13.3-self-test/README.md | 14 ++++ practice/13-undoing-mistakes/README.md | 13 ++++ .../14.1-exercise/README.md | 23 +++++++ .../14.2-extra-practice/README.md | 15 +++++ .../14.3-self-test/README.md | 13 ++++ practice/14-github-projects/README.md | 13 ++++ .../15.1-exercise/README.md | 30 +++++++++ .../15.2-extra-practice/README.md | 25 ++++++++ .../15.3-self-test/README.md | 14 ++++ practice/15-newer-git-and-gh/README.md | 13 ++++ practice/README.md | 7 +- 30 files changed, 573 insertions(+), 39 deletions(-) create mode 100644 practice/11-gitlab/11.1-exercise/README.md create mode 100644 practice/11-gitlab/11.1-exercise/example-gitlab-ci.yml create mode 100644 practice/11-gitlab/11.2-extra-practice/README.md create mode 100644 practice/11-gitlab/11.3-self-test/README.md create mode 100644 practice/11-gitlab/README.md create mode 100644 practice/12-signing-and-security/12.1-exercise/README.md create mode 100644 practice/12-signing-and-security/12.2-extra-practice/README.md create mode 100644 practice/12-signing-and-security/12.3-self-test/README.md create mode 100644 practice/12-signing-and-security/README.md create mode 100644 practice/13-undoing-mistakes/13.1-exercise/README.md create mode 100644 practice/13-undoing-mistakes/13.2-extra-practice/README.md create mode 100644 practice/13-undoing-mistakes/13.3-self-test/README.md create mode 100644 practice/13-undoing-mistakes/README.md create mode 100644 practice/14-github-projects/14.1-exercise/README.md create mode 100644 practice/14-github-projects/14.2-extra-practice/README.md create mode 100644 practice/14-github-projects/14.3-self-test/README.md create mode 100644 practice/14-github-projects/README.md create mode 100644 practice/15-newer-git-and-gh/15.1-exercise/README.md create mode 100644 practice/15-newer-git-and-gh/15.2-extra-practice/README.md create mode 100644 practice/15-newer-git-and-gh/15.3-self-test/README.md create mode 100644 practice/15-newer-git-and-gh/README.md diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml index 93d6ff3..db847d1 100644 --- a/.github/workflows/markdownlint.yml +++ b/.github/workflows/markdownlint.yml @@ -20,10 +20,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Run markdownlint - uses: DavidAnson/markdownlint-cli2-action@v24.1.0 + uses: DavidAnson/markdownlint-cli2-action@21c1be1b93ad9ed58fa840aacc3f279cde2a72ff # v24.2.0 with: globs: '**/*.md' config: '.markdownlint.json' diff --git a/CHANGELOG.md b/CHANGELOG.md index a4c349c..36be2c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added +- Five new practice modules, each with an exercise, extra practice and a self-test: 11 GitLab, 12 signing and security, 13 undoing mistakes, 14 planning with GitHub Projects and 15 newer Git and GitHub CLI commands +- `practice/11-gitlab/11.1-exercise/example-gitlab-ci.yml`, a two-stage pipeline to paste into a GitLab project +- GitLab terms plus the new Git and GitHub terms in the glossary, with matching sections in the command reference +- Rows in `docs/github-ui-vs-terminal.md` for issue branches, sub-issues, reverting and updating pull requests - `CODEOWNERS`, `CODE_OF_CONDUCT.md`, `SECURITY.md` and `SUPPORT.md`, matching the rest of the fleet - `.markdownlint.json` and a markdownlint CI workflow, with its own `.github/workflows/README.md` - YAML issue forms for bug reports and enhancements plus a pull request template @@ -24,6 +28,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Changed +- `actions/checkout` moved from v4.4.0 to v7.0.1 in the lint workflow and the module 08 example +- `markdownlint-cli2-action` pinned to a commit at v24.2.0 +- `CONTRIBUTING.md` uses `git switch` throughout, with a practice-module example in place of the competitive programming one - Tidied the contributor guide examples. - The README's Contact section now links out to `SUPPORT.md` and `SECURITY.md` as callouts instead of plain prose - The Repository Files table wording tidied @@ -32,3 +39,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - The README's detailed command tables moved to `docs/`, keeping the root file short - `cats.txt` moved from the repository root into `practice/00-cats-original` - `CONTRIBUTING.md`'s example commit messages and project-type sections now name their commit prefix explicitly + +### Fixed + +- `docs/github-ui-vs-terminal.md` no longer says rulesets can only be created in the browser diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 19cac04..6ed3a97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,9 +21,9 @@ Before coding, create a GitHub issue that describes the work. Create a branch from `main` for the issue. ```powershell -git checkout main -git pull -git checkout -b feature/description-of-work +git switch main +git pull --ff-only +git switch -c feature/description-of-work ``` Common branch prefixes: @@ -34,15 +34,15 @@ Common branch prefixes: | `fix/` | Bug fixes | | `docs/` | Documentation updates | | `refactor/` | Code improvements without feature changes | -| `solve/` | Competitive programming solutions | +| `practice/` | Throwaway branches made while working through a module | Examples: ```powershell -git checkout -b feature/telemetry-dashboard -git checkout -b fix/auth-validation -git checkout -b docs/readme-update -git checkout -b solve/347-top-k-frequent-elements +git switch -c feature/telemetry-dashboard +git switch -c fix/auth-validation +git switch -c docs/readme-update +git switch -c practice/undo-demo ``` ### 3. Do the Work @@ -127,8 +127,8 @@ When the PR is ready: ### 8. Clean Up Locally ```powershell -git checkout main -git pull +git switch main +git pull --ff-only git branch -d feature/your-branch-name ``` @@ -147,17 +147,17 @@ This makes the project history easier to follow and demonstrates a professional ## Project Examples -### Competitive Programming Repositories +### Practice Modules -Use this for LeetCode, NeetCode, Codeforces and similar repos. +Use this for a new module or a new part of an existing one in this repository. -- Issue title: `Solve [ProblemName] - [Difficulty]` -- Label: `enhancement` -- Branch: `solve/[problem-code-or-name]` -- Example issue: `Solve Contains Duplicate - Easy` -- Example branch: `solve/contains-duplicate` +- Issue title: `Add [module or part]` +- Label: `content` +- Branch: `feature/[module-name]` +- Example issue: `Add a GitLab module` +- Example branch: `feature/gitlab-module` - Commit prefix: `feat:` -- Example PR description: `closes #7 - Adds Python, C++ and Java solutions with complexity notes.` +- Example PR description: `closes #7 - Adds module 11 with an exercise, extra practice and a self-test.` ### Feature Projects @@ -216,41 +216,43 @@ To practise real external review: Issue already created: ```text -#42 Solve Top K Frequent Elements - Medium +#42 Add a self-test to module 13 ``` Terminal: ```powershell -git checkout main -git pull -git checkout -b solve/347-top-k-frequent-elements +git switch main +git pull --ff-only +git switch -c test/13-self-test -# Write the solution files. +# Write the self-test. git add . -git commit -m "feat: solve LeetCode 347 with hash map approach" -git push origin solve/347-top-k-frequent-elements +git commit -m "test: add a self-test to module 13" +git push origin test/13-self-test ``` GitHub PR: ```text -Title: Solve Top K Frequent Elements - Medium +Title: Add a self-test to module 13 closes #42 -Adds Python, C++ and Java solutions with time and space complexity notes. +Adds six questions covering restore, reset, revert and recovering with the reflog. ``` After merge: ```powershell -git checkout main -git pull -git branch -d solve/347-top-k-frequent-elements +git switch main +git pull --ff-only +git branch -D test/13-self-test ``` +`-D` rather than `-d` because a squash-merge leaves the branch looking unmerged to Git. + ## Rule Going Forward For meaningful changes, use: diff --git a/README.md b/README.md index 1d04001..19fa119 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ I use this repository to practise Git, GitHub and the professional workflow habi ## Practice modules -The real content lives in [practice/](practice), ten modules covering everything from staging a file for the first time through to the real aliases I use daily. Each module is split into an exercise, extra practice and a self-test. See [practice/README.md](practice/README.md) for the full list. +The real content lives in [practice/](practice), fifteen modules covering everything from staging a file for the first time through to the real aliases I use daily, GitLab and the newest Git and GitHub CLI commands. Each module is split into an exercise, extra practice and a self-test. See [practice/README.md](practice/README.md) for the full list. ## Documentation @@ -34,6 +34,11 @@ Detailed reference lives in [docs/](docs) rather than cluttering this file: | Reflog, bisect, worktrees and hooks | Not started | | Newer GitHub features (rulesets, merge queue, Codespaces) | Not started | | My real daily aliases end to end | In progress | +| The same workflow on GitLab | Not started | +| Commit signing and keeping secrets out | Not started | +| Undoing mistakes and recovering work | Not started | +| Planning with GitHub Projects | Not started | +| Newer Git and GitHub CLI commands | Not started | I update this table as I actually work through each module, not in advance. @@ -71,7 +76,8 @@ The full step by step process, including opening issues, pushing branches, revie ## What is next for me - Work through the remaining practice modules, in particular the GitHub Actions and remote collaboration ones. -- Add a module on GitHub Projects once I actually use one for something real. +- Work through [14-github-projects](practice/14-github-projects) on a real project board rather than a practice one. +- Revisit [15-newer-git-and-gh](practice/15-newer-git-and-gh) whenever Git or `gh` ships a new release. - Keep [09-advanced](practice/09-advanced) updated as GitHub ships new features worth trying. - Follow up in `dotfiles` on the alias gaps found in [practice/10-daily-workflow-and-aliases](practice/10-daily-workflow-and-aliases). diff --git a/docs/command-reference.md b/docs/command-reference.md index 64fcb03..3c951ea 100644 --- a/docs/command-reference.md +++ b/docs/command-reference.md @@ -74,6 +74,40 @@ Every command that shows up across the practice modules, explained properly. The | `git fetch --prune` | Fetches and also removes local references to branches deleted on the remote | | `git push origin --delete ` | Deletes a branch on the remote, not just locally | +## Undoing more safely + +| Command | What it actually does | +| --- | --- | +| `git reset --soft HEAD~1` | Moves the branch back one commit, keeping the changes staged | +| `git revert -m 1 ` | Undoes a merge commit, keeping the first parent's side | +| `git restore --source= ` | Puts one file back to how it was in an earlier commit without moving the branch | +| `git switch --detach ` | Checks out a commit without a branch, for looking around | +| `git push --force-with-lease` | Force-pushes only if the remote branch is still where I last saw it | +| `git fsck --lost-found` | Finds commits no branch or reflog entry points at any more | + +## Signing + +| Command | What it actually does | +| --- | --- | +| `git config --global gpg.format ssh` | Tells Git to sign with an SSH key instead of GPG | +| `git config --global commit.gpgsign true` | Signs every commit without needing `-S` each time | +| `git log --show-signature` | Shows each commit with the result of checking its signature | +| `git verify-commit HEAD` | Checks one commit's signature | +| `git tag -s -m "message"` | Creates a signed annotated tag | + +## Newer Git commands + +| Command | What it actually does | +| --- | --- | +| `git config get ` | Reads a setting, the newer form of `git config --get` | +| `git config list --show-origin` | Lists every setting with the file it came from | +| `git repo info --all` | Reports facts about the repository, such as its object and reference formats | +| `git last-modified` | Shows the commit that last changed each path | +| `git range-diff ...` | Compares two versions of the same series of commits, such as before and after a rebase | +| `git maintenance start` | Schedules background tasks that keep a repository fast | +| `git backfill` | Fetches the file contents a partial clone skipped, in batches | +| `git sparse-checkout set ` | Keeps only the named folders on disk | + ## Diagnosing history | Command | What it actually does | @@ -97,5 +131,26 @@ Every command that shows up across the practice modules, explained properly. The | `gh issue close` | Closes an issue directly, without needing a linked pull request | | `gh label list` | Lists every label that actually exists on the current repository | | `gh run watch` | Streams a running workflow's logs live in the terminal | +| `gh run rerun --failed` | Reruns only the jobs that failed in a workflow run | +| `gh issue develop --checkout` | Creates a branch linked to an issue and switches to it | +| `gh issue create --parent ` | Opens a new issue as a sub-issue of another | +| `gh pr checks --watch` | Waits for a pull request's checks, reporting when they finish | +| `gh pr update-branch` | Brings a pull request branch up to date with its base | +| `gh pr revert ` | Opens a pull request that reverts a merged one | +| `gh ruleset check ` | Lists every rule that would apply to a branch name | +| `gh project item-add --owner "@me" --url ` | Adds an issue or pull request to a project | +| `gh release verify` | Checks a release's attestation | + +## GitLab CLI (`glab`) + +| Command | What it actually does | +| --- | --- | +| `glab auth login` | Signs in to GitLab.com or a self-managed instance | +| `glab repo create ` | Creates a new project | +| `glab mr create --fill` | Opens a merge request from the current branch, filled in from its commits | +| `glab ci status` | Shows the pipeline for the current branch | +| `glab ci view` | Opens an interactive view of the pipeline's jobs and logs | +| `glab ci lint` | Checks `.gitlab-ci.yml` for mistakes before pushing | +| `glab mr merge --squash --remove-source-branch` | Squash-merges the merge request and deletes its branch | See [practice/10-daily-workflow-and-aliases](../practice/10-daily-workflow-and-aliases) for the shorter alias I actually type for most of the commands above. diff --git a/docs/github-ui-vs-terminal.md b/docs/github-ui-vs-terminal.md index 29fa434..13c556d 100644 --- a/docs/github-ui-vs-terminal.md +++ b/docs/github-ui-vs-terminal.md @@ -11,8 +11,12 @@ The same task, done through the GitHub web interface and through the terminal, s | Delete a merged branch | Delete branch button that appears after merge | `git branch -d name` locally then `git push origin --delete name` on GitHub, `gdone` does both plus pruning in one step | | Add a label | Labels menu in the issue or pull request sidebar | `gh issue edit N --add-label x` / `gh pr edit N --add-label x`, `ghaddlabel N x` tries both automatically | | Create a release | Releases -> Draft a new release, pick or create a tag | `git tag -a vX.Y.Z -m "message" && git push origin vX.Y.Z`, then `gh release create` | -| Enable a branch ruleset | Settings -> Rules -> Rulesets -> New ruleset | `gh api repos/{owner}/{repo}/rulesets` for read-only inspection, rulesets themselves are UI-only to create as of writing | +| Enable a branch ruleset | Settings -> Rules -> Rulesets -> New ruleset | `gh ruleset list` and `gh ruleset check ` to inspect them, `gh api -X POST repos/{owner}/{repo}/rulesets --input ruleset.json` to create one from a JSON file | | Add an image to an issue or comment | Drag and drop directly into the text box | Not possible from the terminal, `gh` has no equivalent, this is a genuinely UI-only action | +| Start a branch for an issue | Development section in the issue sidebar -> Create a branch | `gh issue develop N --checkout` | +| Add a sub-issue | Create sub-issue button under the issue body | `gh issue create --parent N` | +| Revert a merged pull request | Revert button at the bottom of the merged pull request | `gh pr revert N` | +| Update a pull request branch from its base | Update branch button in the merge box | `gh pr update-branch` | | Check a workflow run's logs | Actions tab -> the run -> the job -> the step | `gh run list` then `gh run view --log` for one run, `gh run watch` for a live stream | | Fork a repository | Fork button, top right of the repository page | `gh repo fork` or `ghfork` | | Sync a fork with upstream | Sync fork button on the fork's own page | `git fetch upstream && git merge upstream/main` or the shorter `gh repo sync` | diff --git a/docs/glossary.md b/docs/glossary.md index d488562..da94223 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -1,6 +1,6 @@ # Glossary -Plain definitions for every term used across the practice modules, Git and GitHub side by side. My [git-unlocked](https://github.com/zaccesss/git-unlocked) repository has a much larger [full glossary](https://github.com/zaccesss/git-unlocked/blob/main/09-reference/glossary.md) covering GitLab and other platforms too, this one stays scoped to what actually appears in this repository. +Plain definitions for every term used across the practice modules, Git and GitHub side by side. My [git-unlocked](https://github.com/zaccesss/git-unlocked) repository has a much larger [full glossary](https://github.com/zaccesss/git-unlocked/blob/main/09-reference/glossary.md) covering other platforms too, this one stays scoped to what actually appears in this repository. ## Git terms @@ -43,6 +43,24 @@ A binary search through commit history to find the exact commit that introduced **Worktree** A second working directory checked out from the same repository, letting me have two branches open side by side without cloning twice. +**Restore** +Putting a file back to how it was in the staging area or a commit, without moving any branch. `git restore` replaced the file-level uses of `git checkout`. + +**Reset** +Moving the current branch to another commit. `--soft` keeps the changes staged, `--mixed` (the default) keeps them unstaged and `--hard` throws them away. + +**Revert** +A new commit that undoes an earlier one, the safe undo for anything already pushed because no existing history is rewritten. + +**Detached HEAD** +Checking out a commit directly rather than a branch. New commits made there belong to no branch until one is created for them. + +**Signed commit** +A commit carrying a cryptographic signature from a GPG or SSH key, which GitHub and GitLab show as Verified when the key is on the author's account. + +**Partial clone** +A clone that skips some objects, such as file contents with `--filter=blob:none`. It fetches them later when needed or with `git backfill`. + **Remote** A named reference to another copy of the repository, usually on GitHub. `origin` and `upstream` are conventional names, not special keywords. @@ -105,6 +123,50 @@ A full cloud development environment tied to a repository, configurable so it op **Private vulnerability reporting** GitHub's built-in flow letting someone report a security issue privately through the Security tab, without needing a separate email address. +**Sub-issue** +An issue attached to a parent issue, so the parent shows progress as its children close. + +**GitHub Project** +A planning board or table that lives on an account or organisation and pulls in issues and pull requests from any of its repositories. + +**Push protection** +Secret scanning that blocks a push containing a recognised token before it reaches GitHub. + +**Vigilant mode** +An account setting that marks every unsigned commit of mine as Unverified, so a commit made in my name without my key stands out. + +**Release attestation** +A signed statement from GitHub about a release and its assets, checked with `gh release verify`. + +## GitLab terms + +**Project** +GitLab's name for a repository plus everything around it: issues, merge requests, pipelines and settings. + +**Group** +GitLab's equivalent of an organisation, holding projects and subgroups with shared members and permissions. + +**Merge request (MR)** +GitLab's name for a pull request. + +**Pipeline** +A run of the jobs defined in `.gitlab-ci.yml`, grouped into stages that run in order. + +**Job** +One task in a pipeline, run by a runner, usually in a fresh container. + +**Runner** +The machine or container that picks up pipeline jobs and runs them. + +**Artifact** +Files a job saves so a later stage or a person can use them. + +**Protected branch** +A branch only chosen roles can push or merge to, GitLab's equivalent of branch protection. + +**glab** +The official GitLab CLI, GitLab's equivalent of `gh`. + ## See also - [docs/command-reference.md](command-reference.md) - every command in this repository, explained in full diff --git a/practice/08-github-actions/08.1-exercise/example-workflow.yml b/practice/08-github-actions/08.1-exercise/example-workflow.yml index a17c0e5..857f5e5 100644 --- a/practice/08-github-actions/08.1-exercise/example-workflow.yml +++ b/practice/08-github-actions/08.1-exercise/example-workflow.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Print a message run: echo "This workflow ran on ${{ github.ref_name }}" @@ -31,7 +31,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Count files in the practice folder run: find practice -type f | wc -l diff --git a/practice/11-gitlab/11.1-exercise/README.md b/practice/11-gitlab/11.1-exercise/README.md new file mode 100644 index 0000000..dada158 --- /dev/null +++ b/practice/11-gitlab/11.1-exercise/README.md @@ -0,0 +1,31 @@ +# 11.1: Exercise + +## The GitHub words and their GitLab equivalents + +| GitHub | GitLab | +| --- | --- | +| Repository | Project | +| Organisation | Group | +| Pull request | Merge request (MR) | +| Actions workflow in `.github/workflows/` | Pipeline in `.gitlab-ci.yml` at the project root | +| Check | Pipeline job | +| Branch protection or a ruleset | Protected branch | +| `gh` | `glab` | + +## Steps + +1. Install the GitLab CLI with `brew install glab`, then sign in with `glab auth login` and confirm it with `glab auth status`. +2. Create a throwaway project from the terminal: `glab repo create gitlab-practice --private`, then clone it. +3. In the project, open **Settings -> Repository -> Protected branches** and check `main` is protected with **Allowed to push and merge** set to Maintainers. Try `git push origin main` from a commit on `main` to see what the protection does and does not stop for my own role. +4. Copy [example-gitlab-ci.yml](example-gitlab-ci.yml) into the project root as `.gitlab-ci.yml`, plus a `practice` folder with a file or two in it so the count job has something to count. +5. Open an issue with `glab issue create`, note its number, then start a branch for it: `git switch -c feature/first-pipeline`. +6. Commit the pipeline file, push the branch, then open the merge request from the terminal with `glab mr create --fill --target-branch main`. Put `Closes #1` (with the real issue number) in the description. +7. Watch the pipeline with `glab ci status`, then open the full view with `glab ci view` and read each job's log. +8. Merge it from the terminal with `glab mr merge --squash --remove-source-branch`, then check the issue closed itself. +9. Clean up locally the same way as on GitHub: `git switch main`, `git pull --ff-only`, `git branch -D feature/first-pipeline` and `git fetch --prune`. + +## Questions to answer for myself + +- Why does a GitLab job start in a fresh container with none of the previous stage's files unless they are passed on as artifacts? +- What exactly did the protected branch stop? Would it stop a Developer where it did not stop me? +- What does the `workflow: rules:` block in the example file prevent? What would happen on an open merge request without it? diff --git a/practice/11-gitlab/11.1-exercise/example-gitlab-ci.yml b/practice/11-gitlab/11.1-exercise/example-gitlab-ci.yml new file mode 100644 index 0000000..29c8be3 --- /dev/null +++ b/practice/11-gitlab/11.1-exercise/example-gitlab-ci.yml @@ -0,0 +1,26 @@ +# a copy to paste into a GitLab project as .gitlab-ci.yml, not part of this repository's own CI + +# without these rules a push to a branch with an open merge request runs two pipelines, +# one for the branch and one for the merge request +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS + when: never + - if: $CI_COMMIT_BRANCH + +stages: + - hello + - count + +say-hello: + stage: hello + image: alpine:3.22 + script: + - echo "This pipeline ran on $CI_COMMIT_REF_NAME" + +count-files: + stage: count + image: alpine:3.22 + script: + - find practice -type f | wc -l diff --git a/practice/11-gitlab/11.2-extra-practice/README.md b/practice/11-gitlab/11.2-extra-practice/README.md new file mode 100644 index 0000000..5668ca2 --- /dev/null +++ b/practice/11-gitlab/11.2-extra-practice/README.md @@ -0,0 +1,15 @@ +# 11.2: Extra Practice + +1. **Merge methods:** in **Settings -> Merge requests**, switch the project between a merge commit, a merge commit with semi-linear history and a fast-forward merge. Merge one small merge request under each and compare the history with `git log --oneline --graph`. +2. **Draft merge requests:** open a merge request with `Draft:` at the start of its title and confirm it cannot be merged until I mark it ready. +3. **Suggested changes:** review my own merge request in the **Changes** tab, leave a suggestion on one line, then apply it from the browser and pull the commit it creates. +4. **Pipeline rules:** add a job with `rules:` so it only runs on `main`, then confirm from a merge request pipeline that it was skipped. +5. **CI variables:** add a masked variable under **Settings -> CI/CD -> Variables** (a made-up value, never a real secret), print it from a job and confirm the log shows it masked. +6. **Validate before pushing:** break the pipeline file on purpose, then run `glab ci lint` to catch the mistake locally before GitLab does. +7. **Push mirroring:** read how a GitLab project can push-mirror to another remote or pull from one, the same idea that keeps copies of my GitHub repositories on other platforms. + +## Questions to answer for myself + +- Which merge method keeps the history straightest? What does it make me do before every merge? +- Why does GitLab mask a variable in the log instead of refusing to print it at all? +- When would I pick a merge request pipeline over a branch pipeline? diff --git a/practice/11-gitlab/11.3-self-test/README.md b/practice/11-gitlab/11.3-self-test/README.md new file mode 100644 index 0000000..5b27543 --- /dev/null +++ b/practice/11-gitlab/11.3-self-test/README.md @@ -0,0 +1,14 @@ +# 11.3: Self-Test + +No answers here on purpose, if I cannot answer these from memory I go back to [11.1](../11.1-exercise) and [11.2](../11.2-extra-practice) rather than looking them up. + +1. What is the GitLab name for a pull request, an organisation and a check? +2. Where does GitLab look for a pipeline's configuration? What is the minimum a job needs? +3. How does one stage hand files to the next? +4. Which `glab` commands open a merge request from the current branch, show its pipeline and merge it? +5. What stops a duplicate pipeline running when a branch already has an open merge request? +6. Name the three merge methods a GitLab project can use. + +## Pass criteria + +I consider this module done when I can answer all six without opening [11.1](../11.1-exercise) or [11.2](../11.2-extra-practice) for a reminder. diff --git a/practice/11-gitlab/README.md b/practice/11-gitlab/README.md new file mode 100644 index 0000000..d88a3d5 --- /dev/null +++ b/practice/11-gitlab/README.md @@ -0,0 +1,13 @@ +# 11: GitLab + +I use this module to practise the same workflow as the rest of this repository on GitLab instead of GitHub: merge requests instead of pull requests, a `.gitlab-ci.yml` pipeline instead of an Actions workflow and `glab` instead of `gh`. + +| Part | What it covers | +| --- | --- | +| [11.1: Exercise](11.1-exercise) | A GitLab project, a protected branch, a merge request from the terminal and a first pipeline | +| [11.2: Extra Practice](11.2-extra-practice) | Merge methods, draft merge requests, suggested changes, pipeline rules and CI variables | +| [11.3: Self-Test](11.3-self-test) | Questions with no answers shown, to check what actually stuck | + +## Why this matters to me + +Plenty of teams, university groups and companies run on GitLab rather than GitHub. The ideas carry straight over, but the names, the menus and the CI file do not. Doing the full loop once here means the first real GitLab project I join feels familiar instead of new. My [git-unlocked](https://github.com/zaccesss/git-unlocked/tree/main/04-gitlab) guide has the full reference behind each step. diff --git a/practice/12-signing-and-security/12.1-exercise/README.md b/practice/12-signing-and-security/12.1-exercise/README.md new file mode 100644 index 0000000..ee17181 --- /dev/null +++ b/practice/12-signing-and-security/12.1-exercise/README.md @@ -0,0 +1,32 @@ +# 12.1: Exercise + +## SSH commit signing + +Git can sign with the same kind of SSH key I already use to push, which is simpler than setting up GPG. + +1. Check which key I have with `ls ~/.ssh/*.pub`. If there is none, create one with `ssh-keygen -t ed25519 -C ""`. +2. Tell Git to sign with it: + + ```bash + git config --global gpg.format ssh + git config --global user.signingkey ~/.ssh/id_ed25519.pub + git config --global commit.gpgsign true + git config --global tag.gpgsign true + ``` + +3. On GitHub, open **Settings -> SSH and GPG keys -> New SSH key**, set **Key type** to **Signing Key** and paste the public key. The same key added once as an authentication key does not count, it has to be added again as a signing key. +4. Make a commit in this repository on a practice branch, push it and open the commit on GitHub. It should show **Verified**. If it shows **Unverified**, check the commit email matches a verified email on my account with `git log -1 --format='%ae'`. +5. Make Git able to check signatures locally by listing which keys I trust: + + ```bash + echo " $(cat ~/.ssh/id_ed25519.pub)" >> ~/.ssh/allowed_signers + git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers + ``` + +6. Run `git log --show-signature -1` and `git verify-commit HEAD` and read what each one reports. + +## Questions to answer for myself + +- What exactly does a signature prove? What does it not prove about the code inside the commit? +- Why does GitHub need the key added as a signing key when it already knows it as an authentication key? +- What would `git verify-commit` say about a commit signed by a key missing from `allowed_signers`? diff --git a/practice/12-signing-and-security/12.2-extra-practice/README.md b/practice/12-signing-and-security/12.2-extra-practice/README.md new file mode 100644 index 0000000..e576488 --- /dev/null +++ b/practice/12-signing-and-security/12.2-extra-practice/README.md @@ -0,0 +1,14 @@ +# 12.2: Extra Practice + +1. **Signed tags:** create an annotated tag with `git tag -s v0.0.1-practice -m "practice tag"`, check it with `git tag -v v0.0.1-practice`, then delete it locally with `git tag -d v0.0.1-practice`. +2. **Vigilant mode:** read what **Flag unsigned commits as unverified** in **Settings -> SSH and GPG keys** changes. Note why it marks every unsigned commit of mine as **Unverified** once it is on. +3. **Signing on GitLab:** add the same public key on GitLab under **Edit profile -> SSH Keys** with **Usage type** set to signing, push a signed commit to the project from [module 11](../../11-gitlab) and find its badge there. +4. **Ignoring secrets:** in a throwaway repository, add `.env` to `.gitignore`, create a `.env` file with a made-up value and confirm `git status` no longer lists it. Then run `git check-ignore -v .env` to see which rule matched. +5. **Push protection:** read how GitHub's secret scanning push protection blocks a push that contains a recognised token, what the bypass options are and why a bypass still raises an alert. Never test it with a real token. +6. **A leaked secret drill:** write down, in order, what I would do if a real token reached a public repository: revoke it at the provider first, replace it, then decide whether rewriting history is still worth it. + +## Questions to answer for myself + +- Why does `.gitignore` do nothing for a file Git is already tracking? How do I stop tracking it without deleting it? +- Why is revoking a leaked token more urgent than removing it from the history? +- What does a signed tag add to a release that a signed commit alone does not? diff --git a/practice/12-signing-and-security/12.3-self-test/README.md b/practice/12-signing-and-security/12.3-self-test/README.md new file mode 100644 index 0000000..b2700af --- /dev/null +++ b/practice/12-signing-and-security/12.3-self-test/README.md @@ -0,0 +1,13 @@ +# 12.3: Self-Test + +No answers here on purpose, if I cannot answer these from memory I go back to [12.1](../12.1-exercise) and [12.2](../12.2-extra-practice) rather than looking them up. + +1. Which four `git config` settings turn on SSH signing for every commit and tag? +2. Name two reasons a signed commit can still show as **Unverified** on GitHub. +3. What file does Git need before `git log --show-signature` can check an SSH signature? +4. Why does adding a file to `.gitignore` not remove it from the repository? +5. A token has just been pushed to a public repository. What is the first thing I do? + +## Pass criteria + +I consider this module done when I can answer all five without opening [12.1](../12.1-exercise) or [12.2](../12.2-extra-practice) for a reminder. diff --git a/practice/12-signing-and-security/README.md b/practice/12-signing-and-security/README.md new file mode 100644 index 0000000..78d7c6a --- /dev/null +++ b/practice/12-signing-and-security/README.md @@ -0,0 +1,13 @@ +# 12: Signing and Security + +I use this module to practise proving my commits are mine and keeping secrets out of a repository in the first place. + +| Part | What it covers | +| --- | --- | +| [12.1: Exercise](12.1-exercise) | SSH commit signing, the Verified badge and checking signatures locally | +| [12.2: Extra Practice](12.2-extra-practice) | Signed tags, vigilant mode, signing on GitLab, ignoring secrets and push protection | +| [12.3: Self-Test](12.3-self-test) | Questions with no answers shown, to check what actually stuck | + +## Why this matters to me + +Git trusts whatever name and email I put in my config, so anyone can write a commit that claims to be from me. A signature is the proof. Secrets are the other half: once a token is pushed it has to be treated as leaked, however quickly the commit is removed. Both habits cost a few minutes to set up and save a much worse afternoon later. diff --git a/practice/13-undoing-mistakes/13.1-exercise/README.md b/practice/13-undoing-mistakes/13.1-exercise/README.md new file mode 100644 index 0000000..3b7312e --- /dev/null +++ b/practice/13-undoing-mistakes/13.1-exercise/README.md @@ -0,0 +1,30 @@ +# 13.1: Exercise + +## Which undo for which mistake + +| The mistake | Already pushed? | The command | +| --- | --- | --- | +| Edited a file and want the last committed version back | No | `git restore ` | +| Staged a file by accident | No | `git restore --staged ` | +| Wrong message or a missed file in the last commit | No | `git add ` then `git commit --amend` | +| Last commit should not exist, but keep its changes staged | No | `git reset --soft HEAD~1` | +| Last commit should not exist, keep its changes unstaged | No | `git reset HEAD~1` (the default, `--mixed`) | +| Last commit and its changes should both go | No | `git reset --hard HEAD~1` | +| A commit is wrong and others may already have it | Yes | `git revert ` | + +## Steps + +Work on a throwaway branch, `git switch -c practice/undo-demo`, so nothing here can touch `main`. + +1. Edit a file, then throw the edit away with `git restore`. Edit it again, stage it, then unstage it with `git restore --staged` and confirm the edit is still in the file. +2. Commit with a deliberately bad message, then fix only the message with `git commit --amend`. Compare the hash before and after with `git log --oneline -1`. +3. Make three small commits. Undo the last one with each kind of reset in turn (`--soft`, then `--mixed`, then `--hard`), running `git status` after each to see where the changes ended up. +4. After the `--hard` reset, get the commit back: find it with `git reflog`, then `git reset --hard HEAD@{1}` (or the hash the reflog shows). +5. Push the branch, then undo one of its commits with `git revert ` and look at the new commit it creates. +6. Delete the branch locally and on origin when done: `git switch main`, `git branch -D practice/undo-demo` then `git push origin --delete practice/undo-demo`. + +## Questions to answer for myself + +- Why is `git reset` on a pushed commit a problem for other people when it is harmless on my own machine? +- Where did the changes go after each of the three resets: staged, in the working directory or nowhere? +- Why does `git revert` add a commit instead of removing one? diff --git a/practice/13-undoing-mistakes/13.2-extra-practice/README.md b/practice/13-undoing-mistakes/13.2-extra-practice/README.md new file mode 100644 index 0000000..58cbbd9 --- /dev/null +++ b/practice/13-undoing-mistakes/13.2-extra-practice/README.md @@ -0,0 +1,15 @@ +# 13.2: Extra Practice + +1. **Revert a merge:** merge a practice branch with `git merge --no-ff`, then undo it with `git revert -m 1 `. Read why a merge commit needs `-m` to say which parent to keep. +2. **Recover a deleted branch:** delete a branch with unmerged work using `git branch -D`, find its last commit in `git reflog` and bring it back with `git switch -c recovered `. +3. **Detached HEAD:** run `git switch --detach HEAD~2`, make a commit there, then keep it with `git switch -c kept-from-detached` before switching away. +4. **One file from the past:** restore a single file as it was two commits ago with `git restore --source=HEAD~2 `, without moving the branch. +5. **ORIG_HEAD:** right after a reset or rebase I regret, try `git reset --hard ORIG_HEAD` as the quickest way back. +6. **Safer force pushes:** after amending a pushed commit on my own practice branch, push with `git push --force-with-lease --force-if-includes` rather than `--force`, then read what each flag protects against. +7. **When the reflog is not enough:** read what `git fsck --lost-found` finds and why `git gc` straight after a mistake can make recovery impossible. + +## Questions to answer for myself + +- Why does a reverted merge cause trouble when the same branch is merged again later? +- What does `--force-with-lease` check that `--force` does not? +- How long does the reflog keep an entry? Is it shared with anyone else who has cloned the repository? diff --git a/practice/13-undoing-mistakes/13.3-self-test/README.md b/practice/13-undoing-mistakes/13.3-self-test/README.md new file mode 100644 index 0000000..bffa018 --- /dev/null +++ b/practice/13-undoing-mistakes/13.3-self-test/README.md @@ -0,0 +1,14 @@ +# 13.3: Self-Test + +No answers here on purpose, if I cannot answer these from memory I go back to [13.1](../13.1-exercise) and [13.2](../13.2-extra-practice) rather than looking them up. + +1. What is the difference between `git restore ` and `git restore --staged `? +2. Where do the changes end up after `git reset --soft`, `git reset --mixed` and `git reset --hard`? +3. A bad commit is already on `main` on GitHub. Which command undoes it? Why that one? +4. How do I get back a commit that `git reset --hard` just threw away? +5. What extra flag does reverting a merge commit need? +6. Why prefer `--force-with-lease` to `--force`? + +## Pass criteria + +I consider this module done when I can answer all six without opening [13.1](../13.1-exercise) or [13.2](../13.2-extra-practice) for a reminder. diff --git a/practice/13-undoing-mistakes/README.md b/practice/13-undoing-mistakes/README.md new file mode 100644 index 0000000..51b9fac --- /dev/null +++ b/practice/13-undoing-mistakes/README.md @@ -0,0 +1,13 @@ +# 13: Undoing Mistakes + +I use this module to practise picking the right undo command for the situation, then getting work back when I picked the wrong one. + +| Part | What it covers | +| --- | --- | +| [13.1: Exercise](13.1-exercise) | Restore, amend, the three kinds of reset and revert, each on purpose | +| [13.2: Extra Practice](13.2-extra-practice) | Reverting a merge, recovering a deleted branch, detached HEAD and safer force pushes | +| [13.3: Self-Test](13.3-self-test) | Questions with no answers shown, to check what actually stuck | + +## Why this matters to me + +Most Git panic comes from not knowing which undo is safe. The rule I want automatic: anything already pushed and shared gets `git revert`, anything still only on my machine can be rewritten. [Module 09](../09-advanced) uses the reflog once, this module makes recovery a habit. diff --git a/practice/14-github-projects/14.1-exercise/README.md b/practice/14-github-projects/14.1-exercise/README.md new file mode 100644 index 0000000..d31a7b8 --- /dev/null +++ b/practice/14-github-projects/14.1-exercise/README.md @@ -0,0 +1,23 @@ +# 14.1: Exercise + +## Steps + +1. Give the GitHub CLI access to projects, which it does not have by default: `gh auth refresh -s project`. +2. Create a project owned by my account: `gh project create --owner "@me" --title "Git Practice Lab"`. Note the number it prints. +3. Open three issues in this repository, one for each module I still have to work through, then add each to the project: + + ```bash + gh project item-add --owner "@me" --url https://github.com/zaccesss/git-practice-lab/issues/ + ``` + +4. In the browser, add a **Board** view grouped by **Status** and move one item to **In Progress**. +5. Add two custom fields: **Priority** as a single select (High, Medium, Low) and **Size** as a number. Fill both in for each item. +6. Open the project's **Workflows** page and check the built-in workflows that set **Status** to **Done** when an item is closed or its pull request is merged. +7. Close one of the issues through a merged pull request and watch its card move to **Done** on its own. +8. Link the project to this repository from the repository's **Projects** tab so it shows up there. + +## Questions to answer for myself + +- Why does a project live on my account or an organisation instead of inside one repository? +- What is the difference between a label on an issue and a field on a project item? +- Which of the built-in workflows saves me the most manual work? Which would I turn off? diff --git a/practice/14-github-projects/14.2-extra-practice/README.md b/practice/14-github-projects/14.2-extra-practice/README.md new file mode 100644 index 0000000..d30dae3 --- /dev/null +++ b/practice/14-github-projects/14.2-extra-practice/README.md @@ -0,0 +1,15 @@ +# 14.2: Extra Practice + +1. **Sub-issues:** break one module's issue into sub-issues, one per part (exercise, extra practice and self-test). Watch the parent show its progress as each closes. +2. **Milestones:** create a milestone with a due date, add the module issues to it and read the progress bar on the **Milestones** page. +3. **Roadmap view:** add a start date and a target date field, then a **Roadmap** view. Drag an item to change its dates. +4. **Iterations:** add an **Iteration** field with one-week iterations and plan the next week's modules into the current one. +5. **Draft items:** add a quick draft item for an idea, then convert it into a real issue once it is worth doing. +6. **From the terminal:** list everything with `gh project item-list --owner "@me"` and read the JSON form with `--format json`. +7. **Clean up:** close the project from its settings once I no longer need the practice board. Deleting it with `gh project delete --owner "@me"` also works. + +## Questions to answer for myself + +- When is a sub-issue better than a task list in the issue body? +- What does a milestone show that a project view does not? +- Why might a team keep one project across several repositories instead of one per repository? diff --git a/practice/14-github-projects/14.3-self-test/README.md b/practice/14-github-projects/14.3-self-test/README.md new file mode 100644 index 0000000..dab5687 --- /dev/null +++ b/practice/14-github-projects/14.3-self-test/README.md @@ -0,0 +1,13 @@ +# 14.3: Self-Test + +No answers here on purpose, if I cannot answer these from memory I go back to [14.1](../14.1-exercise) and [14.2](../14.2-extra-practice) rather than looking them up. + +1. Which scope does the GitHub CLI need before it can create or edit a project? +2. Name three kinds of view a project can show. +3. What makes a card move to **Done** without me touching it? +4. What is a draft item? How does it become an issue? +5. How do sub-issues and milestones each show progress? + +## Pass criteria + +I consider this module done when I can answer all five without opening [14.1](../14.1-exercise) or [14.2](../14.2-extra-practice) for a reminder. diff --git a/practice/14-github-projects/README.md b/practice/14-github-projects/README.md new file mode 100644 index 0000000..9a30f7d --- /dev/null +++ b/practice/14-github-projects/README.md @@ -0,0 +1,13 @@ +# 14: Planning with GitHub Projects + +I use this module to practise planning work across issues and pull requests with a GitHub project board, instead of keeping the plan in my head or a separate app. + +| Part | What it covers | +| --- | --- | +| [14.1: Exercise](14.1-exercise) | A project for this repository, a board view, custom fields and the built-in workflows | +| [14.2: Extra Practice](14.2-extra-practice) | Sub-issues, milestones, a roadmap view, iterations and managing a project from the terminal | +| [14.3: Self-Test](14.3-self-test) | Questions with no answers shown, to check what actually stuck | + +## Why this matters to me + +Issues say what needs doing, a project says what comes next and what is stuck. Team projects and university group work both need that view. GitHub Projects keeps it next to the code rather than in a separate tool nobody updates. diff --git a/practice/15-newer-git-and-gh/15.1-exercise/README.md b/practice/15-newer-git-and-gh/15.1-exercise/README.md new file mode 100644 index 0000000..60f31b8 --- /dev/null +++ b/practice/15-newer-git-and-gh/15.1-exercise/README.md @@ -0,0 +1,30 @@ +# 15.1: Exercise + +## Newer `gh` commands + +| What I am doing | Command | +| --- | --- | +| Create a branch linked to an issue, so the issue shows it under Development | `gh issue develop --checkout` | +| Open an issue as a sub-issue of another | `gh issue create --parent ` | +| Watch a pull request's checks until they finish | `gh pr checks --watch` | +| Show only the checks that are required to merge | `gh pr checks --required` | +| Bring a pull request branch up to date with its base | `gh pr update-branch` (add `--rebase` to rebase instead of merging) | +| Open a pull request that reverts a merged one | `gh pr revert ` | +| See every rule that would apply to a branch name | `gh ruleset check ` | +| List the rulesets on a repository | `gh ruleset list` | +| Open the current repository, file or pull request in the browser | `gh browse` | + +## Steps + +1. Open an issue for a small change, then run `gh issue develop --checkout`. Open the issue in the browser and find the branch in its **Development** section. +2. Open a second issue as a child of the first with `gh issue create --parent ` and look at the parent's progress. +3. Make the change, push and open the pull request. Run `gh pr checks --watch` and let it report when the lint check finishes. +4. Merge something else to `main` first so my branch falls behind, then run `gh pr update-branch` and check the branch picked up the new commit. +5. Merge the pull request, then undo it with `gh pr revert `. Read the revert pull request it opens, then close it without merging. +6. Run `gh ruleset check main` and `gh ruleset check practice/anything` to compare which rules each branch name would meet. + +## Questions to answer for myself + +- What does `gh issue develop` give me that `git switch -c` alone does not? +- Why does `gh pr revert` open a new pull request instead of pushing a revert straight to `main`? +- When would `gh pr update-branch --rebase` be the wrong choice? diff --git a/practice/15-newer-git-and-gh/15.2-extra-practice/README.md b/practice/15-newer-git-and-gh/15.2-extra-practice/README.md new file mode 100644 index 0000000..6378c6f --- /dev/null +++ b/practice/15-newer-git-and-gh/15.2-extra-practice/README.md @@ -0,0 +1,25 @@ +# 15.2: Extra Practice + +## Newer Git + +1. **Config subcommands:** use `git config get user.email`, `git config set --global init.defaultBranch main` and `git config list --show-origin`. These replace the older flag style (`git config --get` and friends). +2. **Repository facts:** run `git repo info --all` to see what Git reports about this repository, such as its object format and reference format. +3. **Last change per file:** run `git last-modified` in this repository to see the commit that last touched each top-level path, the same thing GitHub shows beside each file in its file list. +4. **Comparing two versions of a branch:** after an interactive rebase, compare the old and new commits with `git range-diff main@{1}...HEAD`. The reflog hash of the branch before the rebase works in place of `main@{1}`. +5. **Background maintenance:** run `git maintenance start` in this repository, then `git config list --show-origin | grep maintenance` to see what it scheduled. Turn it off again with `git maintenance stop`. +6. **Partial clones:** clone a large public repository with `git clone --filter=blob:none`, then run `git backfill` to fetch the missing file contents in batches. +7. **Sparse checkout:** in that clone, run `git sparse-checkout set ` so only one folder is on disk. +8. **Experimental replay:** read what `git replay` does differently from `git rebase` (it rewrites commits without touching the working directory) before trying it on a throwaway branch. It is marked experimental, so its options may still change. +9. **What is coming:** read Git's own list of planned breaking changes for Git 3.0, such as `main` as the default branch name for new repositories. + +## GitHub releases and Actions + +1. **Release attestations:** run `gh release verify` against a release from a repository that publishes attestations, then read what the check proves about where the release came from. +2. **Cancel superseded runs:** add a `concurrency` block with `cancel-in-progress: true` to the practice workflow from [module 08](../../08-github-actions), push twice quickly and check only the newer run finishes. +3. **Rerun only what failed:** make one job fail on purpose, fix it, then run `gh run rerun --failed` instead of rerunning the whole workflow. + +## Questions to answer for myself + +- Why did Git move `config` to subcommands when the old flags still work? +- What does a blobless clone save? What does `git backfill` do about the cost later? +- What would `concurrency` save on a repository that pays for its Actions minutes? diff --git a/practice/15-newer-git-and-gh/15.3-self-test/README.md b/practice/15-newer-git-and-gh/15.3-self-test/README.md new file mode 100644 index 0000000..8984048 --- /dev/null +++ b/practice/15-newer-git-and-gh/15.3-self-test/README.md @@ -0,0 +1,14 @@ +# 15.3: Self-Test + +No answers here on purpose, if I cannot answer these from memory I go back to [15.1](../15.1-exercise) and [15.2](../15.2-extra-practice) rather than looking them up. + +1. Which `gh` command creates a branch that GitHub links to an issue? +2. How do I open an issue as a sub-issue from the terminal? +3. Which command waits for a pull request's checks? Which flag limits it to the required ones? +4. What is the newer form of `git config --get user.email`? +5. What does `git range-diff` compare? +6. What does `concurrency` with `cancel-in-progress: true` do to an older workflow run? + +## Pass criteria + +I consider this module done when I can answer all six without opening [15.1](../15.1-exercise) or [15.2](../15.2-extra-practice) for a reminder. diff --git a/practice/15-newer-git-and-gh/README.md b/practice/15-newer-git-and-gh/README.md new file mode 100644 index 0000000..116b89c --- /dev/null +++ b/practice/15-newer-git-and-gh/README.md @@ -0,0 +1,13 @@ +# 15: Newer Git and GitHub CLI Commands + +I use this module to keep up with what recent Git and `gh` releases added, so my habits do not stay frozen at whatever version I learned on. It was written against Git 2.54 and `gh` 2.102. I check `git --version` and `gh --version` before starting and update this module when either moves on. + +| Part | What it covers | +| --- | --- | +| [15.1: Exercise](15.1-exercise) | Everyday `gh` additions: issue branches, sub-issues, watching checks, updating and reverting pull requests, checking rulesets | +| [15.2: Extra Practice](15.2-extra-practice) | Newer Git commands, background maintenance, release attestations and two Actions habits | +| [15.3: Self-Test](15.3-self-test) | Questions with no answers shown, to check what actually stuck | + +## Why this matters to me + +Most of these replace something I used to do in the browser or with a longer command. Learning one release's worth at a time is easier than discovering years later that a whole workflow has a one-line version. diff --git a/practice/README.md b/practice/README.md index 1610a7d..131fe70 100644 --- a/practice/README.md +++ b/practice/README.md @@ -1,6 +1,6 @@ # Practice Modules -Ten modules, roughly in the order I worked through them. Each one is a folder split into three parts: an `.1-exercise` (the guided walkthrough), a `.2-extra-practice` (harder variations) and a `.3-self-test` (questions with no answers shown). Each module's own `README.md` explains why the topic matters to my workflow and links to all three parts. +Fifteen modules, roughly in the order I work through them. Each one is a folder split into three parts: an `.1-exercise` (the guided walkthrough), a `.2-extra-practice` (harder variations) and a `.3-self-test` (questions with no answers shown). Each module's own `README.md` explains why the topic matters to my workflow and links to all three parts. | Module | Topic | | --- | --- | @@ -14,5 +14,10 @@ Ten modules, roughly in the order I worked through them. Each one is a folder sp | [08-github-actions](08-github-actions) | Writing a CI workflow from scratch | | [09-advanced](09-advanced) | Reflog, bisect, worktrees, hooks and newer GitHub features | | [10-daily-workflow-and-aliases](10-daily-workflow-and-aliases) | The real aliases I use daily plus finding gaps in them | +| [11-gitlab](11-gitlab) | The same workflow on GitLab: merge requests, pipelines, protected branches and `glab` | +| [12-signing-and-security](12-signing-and-security) | SSH commit signing, verified commits, keeping secrets out and push protection | +| [13-undoing-mistakes](13-undoing-mistakes) | Choosing between restore, reset and revert, then recovering with the reflog | +| [14-github-projects](14-github-projects) | Planning with project boards, custom fields, sub-issues and milestones | +| [15-newer-git-and-gh](15-newer-git-and-gh) | What recent Git and GitHub CLI releases added | I do not need to work through these in strict order once the basics are solid, but each module assumes I am at least comfortable with the ones before it. `cats.txt`, my original practice file from before any of this existed, now lives in [00-cats-original](00-cats-original) rather than the repository root.