Repositories and git
Owners, visibility, HTTP and SSH, branch and tag protection, mirrors, external tokens, setup commands, activity, and the Danger tab.
Owners and visibility#
- Owner: every repository belongs to a user or an organization:
alice/web,acme/api. You can create repositories under yourself and the organizations you own. - Visibility: repositories are private by default, readable only by people with access. A public repository can be read, and cloned, by anyone, signed in or not.
- Not found: a private repository you can't read doesn't exist as far as you're concerned. The web app, the API and git all answer "not found", so names don't leak.
- Changing it: on the repository's Danger tab (below).
Cloning and pushing#
Each repository has two URLs, shown on its Code page and by bscope repo view:
| Protocol | URL | Credentials |
|---|---|---|
| HTTP | http://<host>:8080/<owner>/<repo>.git | a token as the password (any username) |
| SSH | ssh://git@<host>:2222/<owner>/<repo>.git | an SSH key added under SSH keys |
- Anonymous HTTP requests to private repositories get
401and a credentials prompt. bscope auth setup-gitmakes git ask the CLI for credentials for your Branchscope host, and no other.bscope repo cloneworks even without that setup.
Both protocols take the same path: the same authorization, the same pre-receive hook, and the same push guard.
Description and topics#
A repository's description (up to 160 characters) and topics show under its name at the top of its page and in lists of repositories. Administrators set both under Settings → General; a new repository's description can be given when it's created, and a fork's when it's forked.
- Topics: up to 10, separated by commas, of lowercase letters, digits and dashes, such as
billing, frontend. They group repositories. - The topic filter: lists of repositories (Explore, yours, an account's or organization's, and Following) show the topics of the repositories in them; pick one to see only those with it (
?topic=billing). Search finds repositories by name or description. - Through the API:
descriptionandtopicsinPUT /repos/{owner}/{name}/settings(topics replace the old ones);GET /repos?topic=&q=filters.
Default branch#
Each repository has a default branch: the one its Code tab and a clone open on, that changes, tasks and runs started by hand use unless they name another, that a fork copies when it copies one branch, and that rulesets protect when they include the default branch.
- Where it comes from: a new repository's is
main. A fork's is its source's. An import's is the source's default branch when it came over, elsemainif that came over, else the first branch by name. In an empty repository, the first push names it:mainif that push has it, else the first of its branches by name. - Changing it: a repository administrator picks another existing branch under Settings → General. Only people can: an agent can't move what the default branch's rulesets protect. The push guard hears at once, clones check out the new branch, and the audit log records the change.
- Deleting it: the default branch can't be deleted or renamed on the Branches tab or through the API; choose another first. If a push deletes it (no ruleset stopped it), the default becomes
main, or the first branch by name, and the audit log records that too. - Older repositories keep the branch they had before it was stored:
main, else the first branch by name.
Branches#
The Branches tab lists the repository's branches: the default branch first, then Yours (those you've pushed to), Active (pushed in the last 3 months) and Stale (not since), or All, with a search by name. Each shows who last pushed to it and when, its checks, its open change, and how far it's behind and ahead of the default branch; a shield marks a protected one.
People with write access, and agents, can:
- Create a branch (New branch) from a branch, a tag or a commit;
- Rename one, from its ⋯ menu: open changes from it and into it follow the new name, and clones keep the old name until they fetch;
- Delete one, from the same menu. Right after, Restore puts it back where it was. Through the API, a branch deleted in the last 14 days can be restored, to where its deletion left it.
Each is a push as far as the push guard is concerned: your rulesets decide, it shows in Activity and starts workflows as a push would, and nothing happens if the guard can't be reached. The default branch can't be deleted or renamed here (see above), and an archived repository's branches can't change.
GET /repos/{owner}/{name}/branches?tab=&q= | the branches, with where each stands (tab: yours, active, stale or all) |
POST …/branches ({name, from}) | create one from a branch, tag or commit |
DELETE …/branches/{branch} | delete one |
POST …/branches/{branch}/rename ({name}) | rename one |
POST …/branches/{branch}/restore | restore one deleted in the last 14 days |
Forking#
Fork, under Follow at the top of a repository's page (or on its row in a list), copies a repository you can read into your account or an organization you own, under the same name or another, with its description or another.
- What's copied: its git history, either the default branch only (the default) or every branch and tag. The fork's default branch is the original's. Nothing else comes with it: no changes, reviews, graphs, runs, settings, rulesets, secrets, webhooks, collaborators or followers. Like any new repository, it gets the Release tags ruleset, after its tags are copied.
- Visibility: a public repository's fork may be public or private; a private repository's is always private, and can't be made public later.
- Through the push guard: the copy is a push by you (or your agent); if the guard refuses it, no fork is made.
- Afterwards: the fork says forked from the original, while that exists and you can read it. The two don't sync: push and fetch between them as with any other remote.
Through the API: POST /repos/{owner}/{name}/fork with {owner, name, description, defaultBranchOnly, visibility}; it returns how many branches and tags were copied. Organization followers hear of the new repository as of any other (Following).
Branch and tag protection#
Branches and tags are protected by rulesets, under Settings → Rulesets (with Branches and Tags views). A new repository starts with two:
- Protected branches, on
main: nobody deletes it or force-pushes to it, and agents can never update it, by push or by merge; - Release tags, on
v*: release tags can't be moved or deleted, and agents can't create, move or delete them.
A ruleset can also require changes, so nobody pushes directly; checks to pass, or deployments to succeed, before a change merges; and restrict who creates or updates what, with a bypass list. Branches no ruleset targets can be deleted, and their history rewritten, as usual. The push guard enforces them all.
Merge methods#
Under Settings → General, Merging, choose which merge methods changes may use (merge commit, squash, rebase; at least one) and which is offered first. New repositories allow all three and offer a merge commit. Through the API: mergeMethods and defaultMergeMethod in PUT …/settings.
Collaborators and access#
Under Settings → General, Collaborators, give people read, write (push, open and merge changes) or admin (settings too). Organization members get read access to every repository of the organization. See Access and identity.
Mirrors#
A repository can push to mirrors on other git hosts: GitHub, GitLab, Bitbucket, Codeberg, Gitea, Forgejo or a plain server. After every push Branchscope accepts, and every merge, the same branches and tags go on to each mirror. It's one way only: Branchscope never reads a mirror back, and what the push guard refuses never reaches one.
Administrators set them up under Settings → Mirrors:
- Over SSH (
git@gitlab.com:acme/web.gitorssh://…), Branchscope makes a deploy key for the mirror alone and shows its public key: add it to the repository there, with write access. The host's key is kept on the first sync and checked from then on. This is the safer choice: the key belongs to the mirror, not to a person. - Over HTTPS (
https://github.com/acme/web.git), the mirror signs in with one of your external tokens for that host, which needs write access there. Another administrator can't send your token to a different URL. - Which refs: all branches and tags, or patterns such as
refs/heads/main,refs/tags/v*andrefs/heads/**(every branch). - Deletions reach the mirror only with Mirror deletions on (then Sync now also removes the mirror's branches and tags this repository doesn't have), and force pushes only with Allow force pushes on. Both are off by default, so a mistake here can't empty or rewrite the mirror; a rewrite the mirror refuses is shown on the page.
- Sync now sends everything. A sync that fails is retried after 30 seconds, then 2, 8 and 32 minutes; after that it waits for the next push or Sync now. The page shows each mirror's last sync, what it sent and any error.
Mirrors only go to public hosts. Deploy keys need SECRETS_KEY set on the server. From the CLI: bscope mirror add git@gitlab.com:acme/web.git, bscope mirror list, bscope mirror sync ID and bscope mirror remove ID.
External tokens#
External tokens are your tokens for other git hosts (GitHub, GitLab, Bitbucket, Gitea or Forgejo, or another), saved once under Tokens → External in your account. You pick one when you import a private repository, or when you add an HTTPS mirror, instead of pasting it each time.
- Yours alone: only you see your external tokens, and only you can copy one back (Copy). Managing them needs you signed in to the web app; tokens, agents and apps can't.
- Encrypted: they're kept encrypted, and sent only to the host they're for: a GitHub token only to
github.com, for example. - Deleting one removes it from Branchscope; it still works on its host until you revoke it there.
A server needs EXTERNAL_TOKEN_KEY set to keep them (see Running Branchscope). Without it, you can still paste a token when importing.
Audit log#
Settings → Audit log lists who changed a repository's security settings, and when, newest first: secrets set or deleted; mirrors added, changed, deleted or synced by hand; rulesets added, changed (Protected branches too) or deleted; an environment's protection; webhooks added, changed (or their secret rotated) or deleted; collaborators added, removed or given other access; the repository made public or private, given another default branch, archived, unarchived or transferred; and runs whose secrets were approved. An organization's settings have an Audit log tab too, for its secrets and webhooks and its repositories transferred or deleted, and its repositories' own entries, each with the repository's name; pick This organization only to leave those out (GET /orgs/{org}/audit?repositories=false).
- Who: each entry names the person, and the agent or app if one acted for them. Only repository administrators and organization owners see the log, as people; agents and apps can't. An organization's owners administer all of its repositories, so they see every one's entries.
- Never secret: an entry says what was changed (a secret's name, a mirror's URL, a webhook's host, which fields changed) but never a value, token or key.
- AI provider keys: a key for an app set, replaced or deleted, and its monthly cap changed, are on the log of the repository or organization it belongs to. An app getting the key isn't: that's counted on the key (see AI provider keys).
- Together: a change and its entry are saved together, so neither is ever there without the other. The exceptions are recorded right after the change succeeds: deleting or transferring a repository and changing its default branch (the git service makes those first), approving a run's secrets or a deployment (they start jobs), and Sync now.
- Kept: entries are kept for good, unless the server deletes them after a set number of days (
AUDIT_RETENTION_DAYS, see Running Branchscope). A transferred repository keeps its log, and the move is recorded on both owners; a deleted repository's log goes with it, and its deletion is recorded on its owner. - Yours: saving and deleting your external tokens, transferring or deleting your personal repositories, and your passkeys added, renamed or removed are on your own log, under Settings → Audit log (or
GET /me/audit). A passkey changed in Keycloak itself, by a site administrator or in Keycloak's account page, is recorded too, saying so, when Branchscope next sees it.
Graph review setup#
Code graphs are built from a fresh checkout of each commit, in a throwaway container. Repositories whose types only resolve with dependencies installed need setup commands, one per line, for example:
pnpm install --frozen-lockfile
dotnet restore
Allow package install scripts is off by default for new repositories: npm, pnpm and yarn lifecycle scripts are the repository's code running during the build, and graphs rarely need them.
Commits, files and activity#
- Code: browse files at any branch, tag or commit, as a File list or as Code with the file tree beside it. The Code tab opens in the code view, or in the one you last picked (your browser remembers it). READMEs are rendered, including Mermaid diagrams.
- Commits: the history of a branch. Each commit has a page of its own: its message, who wrote and who committed it, its parents, its checks and its diff.
- History, beside a file or folder: only the commits that changed it. A file's history follows renames, and shows the path it had.
- Blame, beside a file: which commit last changed each line, following moves and copies, with ↺ to blame the file as it was before that commit. For files up to 1 MB or 20,000 lines.
- Activity: every push and merge, with who did it (and which agent), what the push guard decided, and why. The sidebar's Push activity shows all repositories you can read.
- Releases: tags with titles and notes, and a change map since the previous one. See Releases.
- Deployments: what runs in each environment. See Deployments.
The Danger tab#
Repository administrators have a Danger tab, beside Settings, for what's hard or impossible to undo. Each asks you to type the repository's name to confirm.
- Visibility: make a private repository public, or a public one private. Made private, followers without access stop seeing it, and forks already made stay as they are. A fork of a private repository stays private.
- Archive this repository: it becomes read-only. Nobody can push to it or merge, and it takes no new changes, comments, checks, tasks or runs; its settings (other than visibility) and rulesets can't be changed. It can still be read, cloned and forked. Unarchive this repository reverses it.
- Transfer this repository: move it, under the same name, to your account or an organization you own, with its changes, reviews, graphs, runs, webhooks, collaborators and followers. Links and clone URLs under the old name stop working.
- Delete this repository: its git data, changes, reviews, graphs, runs and webhooks are deleted at once. This can't be undone.
Archiving, transferring and deleting need you signed in to the web app; tokens, agents and apps can't. Visibility can also be set through the API (PUT …/settings).