Module 8 polish: backup check, credentials, forge, prices (#38,#39,#47,#52) #64

Merged
claude merged 1 commits from fix/p2-module-8-polish into main 2026-06-22 17:15:41 -04:00
2 changed files with 60 additions and 16 deletions
+52 -16
View File
@@ -49,9 +49,10 @@ is a full, equal Git repo that happens to live on a server.
This is the fact the entire rest of the module rests on, so sit with it: **because a remote is just This is the fact the entire rest of the module rests on, so sit with it: **because a remote is just
another copy, the commands you use to talk to it are identical no matter who hosts it.** `git push` another copy, the commands you use to talk to it are identical no matter who hosts it.** `git push`
to GitHub is byte-for-byte the same operation as `git push` to a forge you run yourself in a to GitHub is byte-for-byte the same operation as `git push` to a **forge** (a Git hosting platform —
locked-down rack. The provider is a logistics decision — uptime, price, who can see it, where the GitHub, GitLab, Gitea, Forgejo, and the like) you run yourself in a locked-down rack. The provider is
servers sit — not a Git decision. We lean on GitHub as the worked example below *only* because it's a logistics decision — uptime, price, who can see it, where the servers sit — not a Git decision. We
lean on GitHub as the worked example below *only* because it's
the one you're most likely to hit first, not because the mechanics change anywhere else. the one you're most likely to hit first, not because the mechanics change anywhere else.
The local-to-remote vocabulary is small: The local-to-remote vocabulary is small:
@@ -102,12 +103,36 @@ where to go.
Everyone hits at least one of these. Recognizing them by their error text saves an afternoon. Everyone hits at least one of these. Recognizing them by their error text saves an afternoon.
**1. Authentication fails.** You push and get `Authentication failed` or `Permission denied **1. Authentication fails.** You push and get `Authentication failed`, `Permission denied
(publickey)`. The cause is almost always that you tried to use an account password (dead) or haven't (publickey)`, or a `403`. Two different causes hide behind that wall, and they have different fixes.
set up a token / SSH key. Fix: for HTTPS, generate a personal access token in the host's settings and The common one is *no usable credential at all* — you tried an account password (dead on every modern
use it as your password when prompted; for SSH, generate a key (`ssh-keygen`) and paste the public host) or never set up a token / SSH key. The sneakier one is a credential that *exists but lacks the
half into the host's SSH-keys settings. This is host-specific UI but the *concept* is identical right scope*: a token authenticates fine and then the push is refused with `403` because the token was
everywhere. never granted write access to repositories. They look alike but you fix them differently — create a
credential vs. *edit the existing token's scopes* (don't regenerate it). For the no-credential case:
for HTTPS, generate a personal access token in the host's settings and use it as your password when
prompted; for SSH, generate a key (`ssh-keygen`) and paste the public half into the host's SSH-keys
settings. This is host-specific UI but the *concept* is identical everywhere — the callout below walks
the shape of getting one.
> ### Getting a credential (the shape)
>
> The exact menu names and scope labels drift per host, so treat these as the *shape*, not gospel
> (**Verify-before-publish** the specific UI wording for your forge):
>
> - **Scope is the gotcha — check it first.** In the host's **Settings → developer / access tokens →
> create token**, you must grant the token write access to repositories: usually a scope literally
> named `repo`, or a "read **and write**" toggle on the repositories resource. A token created
> *without* it authenticates and then `403`s on push — it looks like an auth failure, but the fix is
> to **edit the token's scopes**, not to delete and recreate it.
> - **The token is shown once.** Hosts reveal the value a single time at creation. Copy it the moment
> it appears; if you lose it you create a new one rather than recover the old.
> - **Pasting it is invisible, and only happens once.** When Git prompts for your "password," paste
> the token — most terminals show *nothing* as you paste a secret, which is normal, not a failure.
> A **credential helper** (`git config --global credential.helper …`, e.g. `store`, `cache`, or your
> OS keychain) remembers it after the first success so you aren't pasting it on every push.
> - **SSH is the alternative.** A key you've added to the host skips passwords entirely: more setup
> once, no token to scope or cache afterward.
**2. The remote isn't empty (non-fast-forward).** You let the host create the repo *with* a README, **2. The remote isn't empty (non-fast-forward).** You let the host create the repo *with* a README,
then push, and get `! [rejected] ... (fetch first)` or `non-fast-forward`. The remote has a commit then push, and get `! [rejected] ... (fetch first)` or `non-fast-forward`. The remote has a commit
@@ -163,10 +188,10 @@ the forge; you just use it) and **self-hosted** (you run the forge on your own i
|---|---|---|---|---| |---|---|---|---|---|
| **GitHub** | Free; Team ~$4/user; Enterprise ~$21/user | GitHub Actions, built in (Free tier includes a monthly minutes allowance for private repos; unlimited for public) | **Deepest.** Most agents, MCP servers, and AI reviewers target GitHub first | Zero ops — pure SaaS | | **GitHub** | Free; Team ~$4/user; Enterprise ~$21/user | GitHub Actions, built in (Free tier includes a monthly minutes allowance for private repos; unlimited for public) | **Deepest.** Most agents, MCP servers, and AI reviewers target GitHub first | Zero ops — pure SaaS |
| **GitLab** (SaaS) | Free (capped users/namespace, small CI allowance); Premium ~$29/user; Ultimate ~$99/user | GitLab CI/CD — among the most mature, deeply integrated pipelines | Strong; first-party AI assistant plus growing agent support | Zero ops as SaaS; also self-hostable (see below) | | **GitLab** (SaaS) | Free (capped users/namespace, small CI allowance); Premium ~$29/user; Ultimate ~$99/user | GitLab CI/CD — among the most mature, deeply integrated pipelines | Strong; first-party AI assistant plus growing agent support | Zero ops as SaaS; also self-hostable (see below) |
| **Bitbucket** (Atlassian) | Free (≤5 users); Standard ~$3/user; Premium ~$6/user | Pipelines, built in (small free monthly build-minute allowance) | Growing; tightest value is deep Jira/Atlassian tie-in | Zero ops as SaaS; Data Center edition self-hostable (enterprise pricing) | | **Bitbucket** (Atlassian) | Free (≤5 users); Standard ~$3.65/user; Premium ~$7.25/user | Pipelines, built in (small free monthly build-minute allowance) | Growing; tightest value is deep Jira/Atlassian tie-in | Zero ops as SaaS; Data Center edition self-hostable (enterprise pricing) |
| **Azure DevOps** | First 5 users free; Basic ~$6/user beyond; pipelines ~$40/parallel job after a free job | Azure Pipelines, built in (one free parallel job + monthly minutes) | Good within the Microsoft ecosystem; Copilot integration | Zero ops as SaaS; Azure DevOps Server self-hostable | | **Azure DevOps** | First 5 users free; Basic ~$6/user beyond; pipelines ~$40/parallel job after a free job | Azure Pipelines, built in (one free parallel job + monthly minutes) | Good within the Microsoft ecosystem; Copilot integration | Zero ops as SaaS; Azure DevOps Server self-hostable |
| **Codeberg** | Free (FOSS projects only; soft repo/storage caps) | Forgejo Actions (it runs Forgejo) | Via API/MCP; not a first-tier agent target | Zero ops; nonprofit-run, no commercial/closed-source hosting | | **Codeberg** | Free (FOSS projects only; soft repo/storage caps) | Forgejo Actions (it runs Forgejo) | Via API/MCP; not a first-tier agent target | Zero ops; nonprofit-run, no commercial/closed-source hosting |
| **SourceHut** | Paid to host: ~$5 / $10 / $15 tiers (reduced ~$2); free to *contribute* | builds.sr.ht, built in | Minimal first-class AI tooling; reachable via API | Zero ops as SaaS; fully self-hostable (it's open source) | | **SourceHut** | Paid to host: ~$5 / $10 / $15 (all tiers buy the *same* service — "pay what's fair"); reduced ~$2 rate / financial aid if the full price is a hardship; free to *contribute* | builds.sr.ht, built in | Minimal first-class AI tooling; reachable via API | Zero ops as SaaS; fully self-hostable (it's open source) |
**Self-hostable open-source forges (you run it):** **Self-hostable open-source forges (you run it):**
@@ -343,6 +368,12 @@ independent* copy, history and all — not a snapshot.
commit count as your local repo — i.e. the offsite copy is complete, not partial. Read its output; commit count as your local repo — i.e. the offsite copy is complete, not partial. Read its output;
the green line is your evidence that the backup is real. the green line is your evidence that the backup is real.
> On the **HTTPS + token** path with a *private* repo, the clone check (c) needs your credential
> helper to have cached the token from your earlier push — otherwise it can't authenticate to clone.
> The script won't hang waiting for a prompt (it disables interactive credential prompts); it just
> reports a `NOTE` that it couldn't clone, and the push checks above still stand. SSH and public
> repos clone with no credential at all.
### Part C — The everyday loop ### Part C — The everyday loop
7. Edit the README in your *teammate* clone, commit, and push from there: 7. Edit the README in your *teammate* clone, commit, and push from there:
@@ -440,18 +471,23 @@ tables, and update the "as of" date when you do.
minutes allowance for private repos. minutes allowance for private repos.
- [ ] **GitLab** tiers — Free (user/namespace caps, CI allowance), Premium, Ultimate per-user/month, - [ ] **GitLab** tiers — Free (user/namespace caps, CI allowance), Premium, Ultimate per-user/month,
and the SaaS-vs-self-managed price split. and the SaaS-vs-self-managed price split.
- [ ] **Bitbucket** tiers — Free user cap, Standard, Premium per-user/month, and free build-minute - [ ] **Bitbucket** tiers — Free user cap, Standard (~$3.65), Premium (~$7.25) per-user/month, and
allowance. (Sources disagreed between ~$23 and ~$56 at build time — re-confirm the exact free build-minute allowance. (Reconciled against Atlassian's own pricing page on 2026-06-22;
figures.) stale third-party listings still quote ~$2/$5 — trust Atlassian's page, and re-confirm.)
- [ ] **Azure DevOps** — free-user count, Basic per-user/month, and the per-parallel-job pipeline - [ ] **Azure DevOps** — free-user count, Basic per-user/month, and the per-parallel-job pipeline
price plus free job/minutes. price plus free job/minutes.
- [ ] **Codeberg** — that it remains FOSS-only and free, and its current soft repo/storage caps. - [ ] **Codeberg** — that it remains FOSS-only and free, and its current soft repo/storage caps.
- [ ] **SourceHut** — paid-to-host tiers ($5/$10/$15 and reduced rate were *proposed for 2026*; - [ ] **SourceHut** — paid-to-host tiers ($5/$10/$15): the 2026 prices are now *in effect* for new
confirm they're in effect and current). accounts (confirmed 2026-06-22), so they're no longer "proposed." Note all tiers buy the same
service ("pay what's fair"), with a reduced rate (~the earlier minimum) and financial aid for
hardship — re-confirm before relying on it.
- [ ] **Self-hosted forges** — that Forgejo/Gitea still ship GitHub-Actions-compatible CI, GitLab CE's - [ ] **Self-hosted forges** — that Forgejo/Gitea still ship GitHub-Actions-compatible CI, GitLab CE's
current minimum resource footprint, and whether OneDev/Gogs CI status has changed. current minimum resource footprint, and whether OneDev/Gogs CI status has changed.
- [ ] **"GitHub integrates first" / AI-ecosystem maturity** — re-assess which forges are first-tier - [ ] **"GitHub integrates first" / AI-ecosystem maturity** — re-assess which forges are first-tier
agent and MCP targets; this gap narrows fast. agent and MCP targets; this gap narrows fast.
- [ ] **Self-host/hosted spans** — confirm GitLab still offers CE self-host, and Bitbucket/Azure DevOps - [ ] **Self-host/hosted spans** — confirm GitLab still offers CE self-host, and Bitbucket/Azure DevOps
still offer their self-hostable editions, before describing either as spanning both camps. still offer their self-hostable editions, before describing either as spanning both camps.
- [ ] **Credential/token UI** — the "Getting a credential" callout names menu paths and the
write-scope label (`repo` / "read and write") generically; confirm the current wording and
scope name on the default-example host before publishing.
- [ ] Update the comparison's **"as of" date** to the build date. - [ ] Update the comparison's **"as of" date** to the build date.
@@ -15,6 +15,14 @@
set -u set -u
# Fail fast instead of hanging. The clone and fetch below talk to the remote,
# and on the HTTPS+token path with no cached credential (a common fresh-Linux
# state) Git would stop to prompt for a username/password on the tty and block
# this check forever. Disabling interactive prompts turns that into a clean,
# non-zero failure that drops into the graceful warn branch below. SSH keys,
# public repos, and cached credential helpers are unaffected.
export GIT_TERMINAL_PROMPT=0
# --- tiny output helpers (fall back to plain text if no color) --------------- # --- tiny output helpers (fall back to plain text if no color) ---------------
if [ -t 1 ]; then if [ -t 1 ]; then
GREEN=$'\033[32m'; RED=$'\033[31m'; YELLOW=$'\033[33m'; BOLD=$'\033[1m'; RESET=$'\033[0m' GREEN=$'\033[32m'; RED=$'\033[31m'; YELLOW=$'\033[33m'; BOLD=$'\033[1m'; RESET=$'\033[0m'