.gitbay/wiki/Users.org

d6d57309d9ddb202b5c9a29ff4f4d22c000f3874
gitbay/.gitbay/wiki/Users.org rendered · source · history · blame · raw

480 lines · 20527 bytes

  1#+title: gitbay user guide
  2
  3Everything here works from stock OpenSSH — replace =gitbay= with
  4=ssh git@<host>= in any command and it behaves identically. The CLI adds
  5convenience (instance profiles, repo inference, =$EDITOR=), nothing more.
  6=ssh git@<host> help= lists every command the server knows.
  7
  8* Installing the CLI
  9
 10#+begin_src sh
 11go install gitbay.org/gitbay/cmd/gitbay@latest   # any platform with Go
 12
 13brew tap krz/tap https://gitbay.org/krz/homebrew-tap.git
 14brew install krz/tap/gitbay                      # Homebrew (macOS/Linux)
 15#+end_src
 16
 17Or build from source: =go build ./cmd/gitbay= in a clone of
 18=https://gitbay.org/krz/gitbay.git=.
 19
 20* Getting an account
 21
 22How you join depends on the instance's registration mode. On instances
 23with web accounts enabled, =/register= offers the same signup as a
 24browser form (paste your SSH public key); everything below works from
 25the terminal alone:
 26
 27- closed :: an admin creates your account on the host and registers your
 28  first SSH key. Nothing for you to do but hand over your public key.
 29- invite :: you receive a single-use code by email. With the SSH key you
 30  want to use:
 31  #+begin_src sh
 32  ssh git@<host> register --username you --invite <code>
 33  #+end_src
 34  Your account is active immediately; the invited address is your
 35  verified email.
 36- open ::
 37  #+begin_src sh
 38  ssh git@<host> register --username you --email you@example.org
 39  #+end_src
 40  A verification code arrives by mail. Until you run
 41  =ssh git@<host> email verify <code>=, the account is pending: you can
 42  run =whoami= and the email commands, and nothing else — no git, no
 43  repos.
 44
 45* SSH keys
 46
 47Your key is your identity; there are no passwords anywhere. The SSH
 48username is always =git= — the key alone determines who you are.
 49
 50#+begin_src sh
 51gitbay auth keys list
 52gitbay auth keys add --scope git < ~/.ssh/ci_key.pub   # key on stdin
 53gitbay auth keys remove SHA256:...
 54#+end_src
 55
 56Scopes: =full= (default; git plus every control command), =git= (git
 57transport only — right for automation keys, which then cannot touch
 58issues, settings, or your account), or =runner= (the CI runner's
 59protocol plus read-only git, for the key a =gitbay-runner= host holds;
 60see [[Admin]]).
 61
 62A key belongs to exactly one account instance-wide. Registering a key
 63someone else already holds is refused without telling you whose it is.
 64
 65* Verified commits
 66
 67The commit badge is driven by the *author* email and the signing key:
 68=verified= means the signature is valid, the key is registered to an
 69account, and the author email is a verified address on that account.
 70
 71For OpenPGP signing (git's default):
 72#+begin_src sh
 73gpg --armor --export you@example.org | gitbay auth pgp add
 74#+end_src
 75
 76For SSH signing (=git config gpg.format ssh=): sign with any key
 77registered on your account; your verified addresses act as the principal
 78set. No separate registration step.
 79
 80Add and verify additional addresses with =email add <address>= /
 81=email verify <code>= (requires the instance to have SMTP; otherwise an
 82admin can assert an address for you).
 83
 84The states you will see, in decreasing order of trust: =verified=,
 85=signed_unknown_key= (valid signature, key not registered here — register
 86it and history upgrades retroactively), =signed_email_mismatch= (real
 87key, author line claims someone else), =signed_key_expired= /
 88=signed_key_revoked=, =bad_signature=, =unsigned=. Server-created commits
 89(web edits, merge commits) are always =unsigned= — the server holds no
 90signing key on principle.
 91
 92* Profiles
 93
 94A profile is what =/{owner}= shows: a one-line description, a website, a
 95set of links, long-form about text, the repositories you can see, org
 96membership, and a year of activity. Users and orgs have the same fields.
 97Repository rows carry the listing metadata too — topics, license,
 98default branch, last commit — so a client renders a profile listing the
 99way =/{owner}= does. The web dispatches this command rather than
100assembling the page itself.
101
102#+begin_src sh
103gitbay profile show               # your own
104gitbay profile show alice
105gitbay profile set --description "builds small tools" --website https://alice.example
106#+end_src
107
108About text is markdown by default, or org-mode. It takes inline text or
109stdin, so it can live in a file you keep:
110
111#+begin_src sh
112gitbay profile set --about "I maintain a few small tools."
113gitbay profile set --file - --about-format org < about.org
114#+end_src
115
116Up to five links, each =label|url= or a bare url, http(s) only. Passing
117=--link= replaces the whole set; a single empty one clears it:
118
119#+begin_src sh
120gitbay profile set --link "Mastodon|https://fosstodon.example/@alice" \
121                   --link https://alice.example/now
122gitbay profile set --link ""      # clear
123#+end_src
124
125Every field follows the same rule as the rest of the CLI: a flag you
126leave out is untouched, and ='' clears the one you name. Org profiles
127work the same way and need org admin:
128
129#+begin_src sh
130gitbay org profile krz --description "software and experiments" --about-format org --file - < krz.org
131gitbay org profile krz            # no flags shows it
132#+end_src
133
134The web renders profiles but has no form for editing one, so the CLI is
135the only interface today. =profile set= is not =SSHOnly=, so the JSON API
136runs it like any other write command.
137
138* Repositories
139
140#+begin_src sh
141gitbay repo create you/project [--private]
142gitbay repo clone you/project
143gitbay repo list
144gitbay repo show you/project
145gitbay repo log you/project --limit 20      # commits with signature states
146gitbay repo fork other/project [--name mine]
147gitbay repo delete you/project --yes
148#+end_src
149
150Pushing is SSH-only. Public repositories are anonymously readable over
151HTTPS (and =git://= where enabled); private repositories exist only over
152SSH and answer "not found" to everyone without access.
153
154Access and settings (owner or =admin= grant):
155#+begin_src sh
156gitbay repo access grant you/project alice write    # read | write | admin
157gitbay repo access revoke you/project alice
158gitbay repo settings protect you/project main       # no force-push, no delete
159gitbay repo settings require-signed you/project on  # every commit must verify
160gitbay repo settings git-daemon you/project on      # expose over git://
161gitbay repo topics add you/project cli forge        # free-form tags, shown on the web
162gitbay repo search forge                            # find repos by name/description/topic
163gitbay repo grep you/project "some string"          # literal git grep over the default branch
164gitbay repo pin you/project                         # pin to your web dashboard
165gitbay repo unpin you/project
166gitbay repo archive you/project                     # read-only: pushes and issue/MR
167gitbay repo unarchive you/project                   #   writes refused, browsing intact
168#+end_src
169
170Import from another forge — git data first, then optionally the GitHub
171issue and PR history (issues keep state/labels/comments; PRs land as
172closed or merged MRs with their discussion; originals are attributed
173inline since foreign authors have no local account; re-running resumes
174where it stopped):
175#+begin_src sh
176gitbay repo import you/mirror --from https://github.com/you/repo.git \
177    [--private] [--token-stdin]        # token on stdin, never in the URL
178gitbay repo import-issues you/mirror --from you/repo --token-stdin
179#+end_src
180
181Moving between gitbay instances (no lock-in): run on the TARGET, with
182your key registered on both sides. Profile, repos with settings,
183issues, MRs, and comments replay with attribution; git data mirrors
184client-side through your own key. Keys never transfer and emails
185arrive unverified — trust is per-instance. Re-running resumes.
186Push-blocking policies (require-signed, protected branches) are
187deferred and printed for you to re-apply after the data lands.
188=gitbay auth export= alone doubles as a user-level backup.
189
190#+begin_src sh
191gitbay migrate --from old-instance.example [--from-port 22]
192#+end_src
193
194Mirroring keeps a foreign remote in sync during a gradual migration
195(repo admin; https remotes; the token is stored server-side for the
196recurring sync and never echoed back):
197
198#+begin_src sh
199gitbay repo mirror add you/project https://github.com/you/project.git \
200    --direction push --token-stdin    # propagate after every local push
201gitbay repo mirror add you/copy https://github.com/them/theirs.git \
202    --direction pull                  # follow upstream; local pushes refused
203gitbay repo mirror list               # sync status and last error, per mirror
204gitbay repo mirror sync / remove <id>
205#+end_src
206
207Markdown and org files render on the web when opened, the way a README
208does on the repository page, with relative links resolved against the
209file's directory; =source= in the file's action bar (or =?view=source=)
210shows the text instead. Other files show the text with highlighting.
211
212* Organizations
213
214Orgs share the owner namespace with users and own repositories at
215=org/repo=. By default members get write on all org repos; org admins
216get repo admin, create repos under the org, and manage membership.
217
218#+begin_src sh
219gitbay org create krz
220gitbay org members add krz alice [--role admin]
221gitbay org show krz
222gitbay org rename krz newname     # clone URLs change
223gitbay org delete krz --yes       # only when it owns no repositories
224#+end_src
225
226Large orgs scope access with teams: set what plain membership implies,
227then grant per-repo roles through named teams (org admins always keep
228admin; the default =write= keeps the simple model):
229
230#+begin_src sh
231gitbay org settings members-role krz none   # write | read | none
232gitbay org team create krz core-devs
233gitbay org team add krz core-devs alice bob # org members only
234gitbay org team grant krz core-devs krz/gitbay write
235gitbay org team show krz core-devs          # members + grants
236gitbay org team revoke / remove / delete ...
237#+end_src
238
239* Issues
240
241Anyone who can read a repository can file and comment. Closing/reopening
242is for the author or anyone with write; labels and assignees need write.
243
244#+begin_src sh
245gitbay issue create --title "it breaks" [--body "..." | --file -]
246gitbay issue list [--state open|closed|all]
247gitbay issue show 4
248gitbay issue comment 4 --message "same here"
249gitbay issue edit 4 --title "better title" [--body|--file -]  # author or write
250gitbay issue close 4 / reopen 4
251gitbay issue label 4 --add bug --remove wontfix
252gitbay issue assign 4 --add alice
253gitbay issue milestone 4 v1.0                 # or "none" to clear
254#+end_src
255
256Inside a clone, the repository is inferred from the =origin= remote —
257that is why no =owner/name= appears above. Anywhere else, pass it as the
258first argument. Long text: =--body= inline, =--file -= from stdin, or
259neither on a terminal and =$EDITOR= opens.
260
261Wikis are companion repositories edited by push — no separate storage,
262no web editor, the same rendering pipeline as READMEs (markdown and
263org). Access mirrors the parent repo (read to view, write to push);
264the companion is created on your first push and follows the repo
265through transfer and delete:
266
267#+begin_src sh
268git clone ssh://git@<host>/you/project.wiki.git
269# add Home.md (or .org), more pages, images; relative links between
270# pages just work on the web at /you/project/wiki
271git push
272#+end_src
273
274Releases anchor notes and binary assets to a pushed tag (write access;
275assets stream over SSH, capped by the instance's =max_asset_bytes=):
276
277#+begin_src sh
278gitbay release create v1.0 --title "First light" [--notes|--file -|$EDITOR]
279gitbay release asset add v1.0 tool-linux-amd64 < dist/tool-linux-amd64
280gitbay release asset get v1.0 tool-linux-amd64 > tool   # or the web download link
281gitbay release list / show v1.0 / delete v1.0 --yes
282#+end_src
283
284The web shows them under the repository's =releases= tab with rendered
285notes, sha256 sums, and download links.
286
287Commit messages act on issues when the commits land on the default
288branch (direct push or MR merge): =closes/fixes/resolves #4= closes the
289issue with a linking comment, and a bare =#4= leaves a reference
290comment. Each issue/commit pair acts once, ever. Same repository only.
291
292Milestones group issues and MRs toward a release (write access to
293manage, attach with =issue milestone= / =mr milestone=; progress shows
294on the web at =/owner/name/milestones=):
295
296#+begin_src sh
297gitbay milestone create v1.0 --description "first release" --due 2027-01-01
298gitbay milestone list [--state open|closed|all]
299gitbay milestone close v1.0 / reopen v1.0
300#+end_src
301
302Issue templates: commit =.gitbay/issue-template.md= (and optional
303=issue-template-<name>.md= variants) to the default branch. =gitbay
304issue create= prefills =$EDITOR= with the default template, the web
305form prefills its textarea, and =gitbay issue templates= lists them.
306
307Lists narrow the same way on every surface: =issue list --label bug
308--assignee bob --author alice --milestone v1= (or =--milestone none=),
309=mr list --author bob --milestone v1=; the web's issue and merge request
310lists take the same names as query parameters, and each active filter
311shows with a link that drops it.
312
313Labels take a colour: =gitbay label set bug --color cf222e=; =label
314list= shows each with its colour and how many issues carry it, and
315=label remove= takes one off every issue. =issue label --add= still
316creates a colourless label on the fly.
317
318* Merge requests
319
320#+begin_src sh
321gitbay mr create --source feature --target main --title "add thing"
322gitbay mr create other/upstream --source you/fork:feature --target main --title "..."
323gitbay mr list / show 4 / diff 4
324gitbay mr checkout 4              # local branch mr/4 from the MR head
325gitbay mr review 4 --approve      # or --request-changes / --comment
326gitbay mr merge 4 [--strategy ff|merge|squash|rebase]
327gitbay mr close 4
328#+end_src
329
330Semantics worth knowing:
331
332- the MR head lives in the *target* repository as
333  =refs/merge-requests/N/head= (fetchable by any reader), so an MR
334  survives deletion of its source branch or fork.
335- force-pushing the source updates the MR and marks existing reviews
336  stale.
337- default strategy: fast-forward when possible, else a merge commit.
338  Squash makes one commit authored by the MR author, committed by the
339  merger. Rebase replays a linear range preserving authors; it refuses
340  ranges containing merge commits, and when fast-forward is possible it
341  *is* one (original commits and signatures land untouched).
342- on =require_signed_commits= branches only fast-forwards of fully
343  verified commits merge; everything server-created is refused with
344  instructions to rebase locally.
345
346Repo admins can gate merges (=repo settings ...=): =require-approvals
347<n>= (fresh, non-author approvals; each reviewer's latest review is
348their stance, and a fresh request-changes blocks), =require-resolved=
349(no open review threads), =require-checks= (all statuses green), and
350=require-codeowners= (an approval from an owner of every owned changed
351file). Owners come from a =CODEOWNERS= file on the target branch, root
352or =.gitbay/=, gitignore-style patterns, last match wins. The toggle is
353the opt-in, so a repository can carry the file as documentation of who
354to ask without it gating merges; with it on and no file on the target
355branch, the merge is refused and says so. It does not wait on
356=require-approvals=.
357
358A merge request whose target is another open merge request's source
359branch is stacked on it: =mr create= says so, =mr show= carries
360=stacked_on= and =stacked=, and merging the lower one retargets the
361upper onto =main= with its reviews kept. See [[Stacked-MRs][Stacked
362merge requests]].
363
364Review threads anchor to diff lines:
365
366#+begin_src sh
367gitbay mr diff-comment 4 --path main.go --line 12 --message "use log here"
368gitbay mr diff-comment 4 --reply 7 --message "done"     # join thread 7
369gitbay mr threads 4                                     # threads with staleness
370gitbay mr resolve 4 7 / unresolve 4 7
371#+end_src
372
373Threads render inline on the MR page. A force-push marks them stale
374(shown under "threads on earlier revisions") rather than guessing new
375anchors; =mr show= reports the unresolved count. Resolving is for the
376thread author, the MR author, or anyone with write.
377
378* CI builds
379
380A =.gitbay/ci.yml= in the repo runs jobs on every branch push:
381
382#+begin_src yaml
383jobs:
384  test:
385    steps:
386      - go test ./...
387#+end_src
388
389Each job becomes a build (=build list=, =build log=, the builds tab on
390the web) and a =ci/<job>= commit status, which =repo settings
391require-checks= can gate merges on. Steps run with =sh -c= on the
392instance's runner, stopping at the first failure; a broken config
393surfaces as a failed =ci/config= status. Environment: =GITBAY_REPO=,
394=GITBAY_SHA=, =GITBAY_REF=, =GITBAY_JOB=, =CI=true=.
395
396Secrets: =repo secret set <owner/name> <NAME>= reads the value from
397stdin (never argv) and injects it into the repo's builds as =$NAME=;
398=repo secret list= shows names only, and the value is never echoed
399back. Anyone with write access can read a secret from inside a build,
400so scope them accordingly.
401
402Schedules: a job with =schedule: "17 11,23 * * *"= (five-field cron,
403server-local time; lists, ranges, and steps supported) runs on its cron
404against the default branch instead of on push. A default-branch push
405registers or updates the schedule. A job with =tags: "v*"= runs when a
406matching tag is pushed — and only then; =schedule= and =tags= are
407mutually exclusive. =build trigger <owner/name> <job>= queues any job
408immediately, and =build cancel <owner/name> <n>= withdraws one, queued
409or running: a running build stops at the runner within seconds and the
410log says who cancelled it. Both need write access.
411
412* Large files (LFS)
413
414Standard Git LFS works over both transports with no setup beyond the
415usual =git lfs track=. SSH remotes authenticate through
416=git-lfs-authenticate= (deploy keys included: ro keys can download, rw
417keys upload); anonymous HTTPS clones of public repositories can fetch
418LFS objects with no credentials. Objects are verified against their
419sha256 on upload and capped at 512MB by default.
420
421* Pages
422
423On instances with =[pages] domain= set, a =pages= branch in any public
424repo is served as a static site: the repo named =pages= at
425=https://<you>.<domain>/=, every other repo at
426=https://<you>.<domain>/<repo>/=. Push HTML to publish; a CI job can
427build and push the branch for automatic deploys. Sites run on a
428separate origin — your scripts work, and the forge's cookies are out of
429reach.
430
431A repo can also serve its pages branch on a domain you own.
432=repo domain add <owner/name> <domain>= claims it and prints a DNS TXT
433challenge (=_gitbay-challenge.<domain>=); create the record, run
434=repo domain verify=, then point the domain's A/AAAA records at the
435instance (DNS-only if the domain sits behind a proxying provider — the
436instance issues its own certificates). Claims are exclusive per
437instance; unverified claims serve nothing and expire after 7 days.
438=repo domain list= reports pending/verified/expired.
439
440* Browser sessions
441
442=gitbay web login= mints a one-time URL; the session it opens lasts
443seven days. =gitbay web sessions list= shows each of yours by a short
444id with its creation and expiry, and =gitbay web sessions revoke <id>=
445or =--all= ends them from the terminal, which is where a lost laptop is
446handled.
447
448* Notifications
449
450When the instance has SMTP configured, activity mails you: someone
451opens an issue or MR on your repository, comments where you are a
452participant (author, commenter, reviewer), reviews, closes, or merges.
453You are never mailed about your own actions, and only verified primary
454addresses receive anything. Delivery retries on relay failure.
455
456* Scripting
457
458Every read command takes =--json= and emits one envelope:
459={"protocol_version": 1, "data": ...}=. stdout is data, stderr is
460messages. Exit codes are stable: 0 ok, 1 failure, 2 usage, 3 not found,
4614 denied, 5 server/protocol error. Nothing ever prompts; destructive
462commands take =--yes=.
463
464For HTTP automation see [[API]].
465
466* CLI setup
467
468#+begin_src sh
469gitbay remote add myforge forge.example.org [--port n] [--user u] --default
470gitbay remote list
471gitbay init [name] [--private]   # git init + repo create + origin, in one step
472#+end_src
473
474Configuration lives at =~/.config/gitbay/config.toml=. The CLI shells
475out to your real =ssh=, so =~/.ssh/config=, the agent, and hardware keys
476all apply. It shares one connection per instance through a control
477socket under =~/.ssh=: the first command in five minutes pays the
478handshake and the rest ride it. =no_multiplex = true= on an instance in
479the config turns that off. Man pages: =gitbay man --dir <dir>=; completions:
480=gitbay completion bash|zsh|fish=.