# Git Providers & Related Repos

Forge is **provider-native**: it resolves which git host a repository lives on
and adapts its behavior — issue creation, change-request terminology, CLI —
to that host. GitLab works natively, and GitHub and other hosts plug in through
the same adapter layer rather than through special cases.

::: tip Why this exists
Before this layer, forge's behavior was split: issue export was GitLab-only
(and hard-refused a GitHub remote), while the branch/PR skills assumed GitHub.
The adapter layer unifies both behind one resolution path.
:::

## Supported providers

| Provider | CLI | Change request | Issues path |
|---|---|---|---|
| GitLab | `glab` | merge request | `/-/issues` |
| GitHub | `gh` | pull request | `/issues` |
| Gitea | `tea` | pull request | `/issues` |
| Bitbucket | — | pull request | `/issues` |
| Generic | — | change request | — |

`Generic` is the safe fallback for an unrecognized or missing remote: forge
still works, it just won't attempt host-specific actions.

## How the provider is resolved

1. **`repo.provider`** in `.forge/config.yaml`, if set — an explicit override.
2. Otherwise **auto-detected from the git remote**. The remote URL is parsed in
   all common forms — SCP-style (`git@gitlab.com:group/sub/repo.git`),
   `ssh://` (including a port), and `https://` (including embedded
   credentials) — with GitLab subgroups and a trailing `.git` handled.
3. **Self-hosted hosts** are matched via the `repo.hosts` map, then by a
   host-name heuristic (a host containing `gitlab` resolves to GitLab), then
   Generic.

## Configuration

```yaml
# .forge/config.yaml
repo:
  provider: ""                   # force gitlab|github|gitea|bitbucket|generic; empty = auto-detect
  hosts:
    gitlab.example.com: gitlab   # self-hosted host → provider kind
  related:
    - name: api
      path: ../api               # a local sibling checkout
    - name: web
      url: https://github.com/acme/web
      # provider: github         # optional; else derived from the url/path
```

Every field is optional — with no `repo:` section at all, forge auto-detects
from the remote.

## `forge provider`

Read-only. Shows the resolved provider for this repo and every related repo:

```sh
$ forge provider
This repository:
  provider: GitLab
  location: gitlab.com/acme/platform/api
  cli:      glab (merge requests)

Related repos:
  - api              GitHub     git@github.com:acme/api.git
  - infra            GitLab     https://git.acme.internal/ops/infra.git
```

Note `infra` above: a **self-hosted** host resolved to GitLab through
`repo.hosts`, and `api` resolved to GitHub from its URL — three different
hosts, one command.

## `forge issues create` — provider-native issue export

Turns a change's outstanding tasks into issues **on whichever host this repo
uses**:

```sh
# preview the exact commands — writes nothing
forge issues create --change add-billing --dry-run

# create them
forge issues create --change add-billing --label forge
```

It reads `.forge/changes/<change>/tasks.md`, **skips tasks already done**, and
creates one issue per remaining task with its task ID, status, and dependencies
in the body. Omit `--change` and the single active change is used.

The argv comes from the resolved provider's adapter, so the same command emits:

```sh
# GitLab
glab issue create --title "Add the parser" --description "…" --label forge
# GitHub
gh issue create   --title "Add the parser" --body "…"        --label forge
```

::: warning
Forge never creates issues outside the repository's own remote. If the resolved
provider has no supported CLI (Bitbucket, Generic), the command stops and points
you at the host's issues URL instead of guessing.
:::

## `forge deliver` — open the merge/pull request

Once a change's tasks are done, `forge deliver` opens the change request on the
same resolved host — using that host's terminology and flags:

```sh
forge deliver --dry-run                    # preview; writes nothing
forge deliver --label forge --base main    # open it
forge deliver --draft --allow-incomplete   # early draft
```

```sh
# GitLab
glab mr create --title "Add billing" --description "…" --target-branch main
# GitHub
gh   pr create --title "Add billing" --body        "…" --base main
```

- **Title** defaults to the change name humanized (`add-billing` → "Add
  billing"); override with `--title`.
- **Body** is assembled from the change's `proposal.md` plus a checked task
  list, so a reviewer sees intent and scope without opening the repo.
- **Readiness gate** — delivery refuses while any task is not done, listing the
  blockers and exiting non-zero (mirroring [`forge archive`](/guide/workflow)).
  `--allow-incomplete` is the deliberate override, e.g. to open a draft early.

::: tip
`--draft` is honored where the host supports it (GitLab and GitHub). Gitea has
no draft flag, so it is ignored there rather than failing.
:::

### `--require-ci` — don't deliver on red

```sh
forge deliver --require-ci
# CI is failing on branch "main"; refusing to deliver (drop --require-ci to override)
```

Off by default. When set, forge queries the branch's pipeline through the
provider (`gh run list --json status,conclusion` / `glab ci status`) before
opening anything — including under `--dry-run`, so the preview is honest.

**It fails open by design.** Reading CI status means parsing provider CLI
output, which is brittle, so the gate blocks *only* on a confident `failed`:

| Verdict | Behavior |
|---|---|
| failed | **refuses**, non-zero exit |
| success | proceeds (`CI: success on branch …`) |
| pending / still running | warns, proceeds |
| unparseable, no CI support, branch unresolvable, query failed | warns, proceeds |

That asymmetry is deliberate: a harness gate that blocks on uncertainty trains
people to bypass it. This one only stops you when CI is definitively red.

## Related repos

`repo.related` makes forge aware of siblings in a multi-repo project — a
frontend, a backend, an infra repo. Today each is resolved to its own provider
(shown by `forge provider` and `forge profile`), which is the foundation for
coordinating a single logical change across repositories.

## See also

- [Repo Adaptivity](/features/adaptivity) — the stack/provider profile forge adapts to
- [Multi-Repo Workspace](/features/workspace) — siblings, and the changes that span them
- [Configuration](/guide/configuration) — the full `repo:` reference
- [Team Collaboration](/features/team) — sharing `.forge/` across a team
