Module 8 polish: backup check, credentials, forge, prices (#38,#39,#47,#52) (#64)
Co-authored-by: claude <claude@jpaul.io> Co-committed-by: claude <claude@jpaul.io>
This commit was merged in pull request #64.
This commit is contained in:
@@ -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
|
||||
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
|
||||
locked-down rack. The provider is 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
|
||||
to GitHub is byte-for-byte the same operation as `git push` to a **forge** (a Git hosting platform —
|
||||
GitHub, GitLab, Gitea, Forgejo, and the like) you run yourself in a locked-down rack. The provider is
|
||||
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 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.
|
||||
|
||||
**1. Authentication fails.** You push and get `Authentication failed` or `Permission denied
|
||||
(publickey)`. The cause is almost always that you tried to use an account password (dead) or haven't
|
||||
set up a token / SSH key. Fix: 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.
|
||||
**1. Authentication fails.** You push and get `Authentication failed`, `Permission denied
|
||||
(publickey)`, or a `403`. Two different causes hide behind that wall, and they have different fixes.
|
||||
The common one is *no usable credential at all* — you tried an account password (dead on every modern
|
||||
host) or never set up a token / SSH key. The sneakier one is a credential that *exists but lacks the
|
||||
right scope*: a token authenticates fine and then the push is refused with `403` because the token was
|
||||
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,
|
||||
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 |
|
||||
| **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 |
|
||||
| **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):**
|
||||
|
||||
@@ -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;
|
||||
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
|
||||
|
||||
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.
|
||||
- [ ] **GitLab** tiers — Free (user/namespace caps, CI allowance), Premium, Ultimate per-user/month,
|
||||
and the SaaS-vs-self-managed price split.
|
||||
- [ ] **Bitbucket** tiers — Free user cap, Standard, Premium per-user/month, and free build-minute
|
||||
allowance. (Sources disagreed between ~$2–3 and ~$5–6 at build time — re-confirm the exact
|
||||
figures.)
|
||||
- [ ] **Bitbucket** tiers — Free user cap, Standard (~$3.65), Premium (~$7.25) per-user/month, and
|
||||
free build-minute allowance. (Reconciled against Atlassian's own pricing page on 2026-06-22;
|
||||
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
|
||||
price plus free job/minutes.
|
||||
- [ ] **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*;
|
||||
confirm they're in effect and current).
|
||||
- [ ] **SourceHut** — paid-to-host tiers ($5/$10/$15): the 2026 prices are now *in effect* for new
|
||||
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
|
||||
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
|
||||
agent and MCP targets; this gap narrows fast.
|
||||
- [ ] **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.
|
||||
- [ ] **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.
|
||||
|
||||
@@ -15,6 +15,14 @@
|
||||
|
||||
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) ---------------
|
||||
if [ -t 1 ]; then
|
||||
GREEN=$'\033[32m'; RED=$'\033[31m'; YELLOW=$'\033[33m'; BOLD=$'\033[1m'; RESET=$'\033[0m'
|
||||
|
||||
Reference in New Issue
Block a user