070-gitlab-ops · git:20260828.6aa2594 · 2026-08-28 · sha256 2d8ffe7b5c53816b

070-gitlab-ops git:20260828.6aa2594A

Immutable. This exact content is served forever at /api/v1/blob/2d8ffe7b5c53816b.

---
description: "When working with GitLab or GitHub — issues, merge requests, pull requests, CI pipelines, labels"
globs: ""
alwaysApply: false
---

# VCS Operations Reference (GitLab & GitHub)

Single source of truth for all VCS CLI commands, label taxonomy, issue templates, and project resolution.

## VCS Auto-Detection

Detect which platform the current repo uses:

```bash
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
if echo "$REMOTE_URL" | grep -q "github.com"; then
  VCS=github    # use `gh`
else
  VCS=gitlab    # use `glab`
fi
```

Session Config overrides:
- `vcs: github|gitlab` -- force a specific platform
- `gitlab-host: <host>` -- override auto-detected GitLab host

## Canonical Project Identity

GitLab REST endpoints accept a URL-encoded `namespace/project` path. Select the GitLab host and project path explicitly; never derive a numeric project ID from `glab repo view`, a search query, or `:id` placeholders. Those forms can resolve through the ambient working directory or a stale search result and target another project after a rename, fork, or scaffold.

Set the identity once per operation sequence and reuse the encoded identifier without encoding it again:

```bash
GITLAB_HOST="<selected GitLab hostname>"
GROUP_PATH="<selected group path>"
PROJECT_NAME="<selected project name>"
PROJECT_PATH="$GROUP_PATH/$PROJECT_NAME"
ENCODED_PROJECT_PATH="$(node -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$PROJECT_PATH")"
```

For a link target in another project, use the same path-first shape instead of a numeric ID:

```bash
TARGET_PROJECT_PATH="<target namespace>/<target project>"
TARGET_ENCODED_PROJECT_PATH="$(node -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$TARGET_PROJECT_PATH")"
```

Pass `--hostname "$GITLAB_HOST"` to every `glab api` call. The endpoint itself then pins the project, including directly after creating a repository when the current directory does not yet identify the new project.

GitHub continues to use an `owner/repo` slug; `gh repo` takes it positionally and rejects `-R`:

```bash
gh repo view --json nameWithOwner -q '.nameWithOwner'
```

---

## Common CLI Commands

**Directive:** every repo-scoped `glab` invocation names host + project path explicitly (`glab -R <host>/<group>/<project> ...` or `glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/..."`). Without `-R` / the encoded endpoint the target is whatever the ambient cwd remote happens to be.

### GitLab (glab)

```bash
# Issues
glab issue list -R <OWNER>/<REPO> --per-page 50                            # All open issues
glab issue list -R <OWNER>/<REPO> --label "status:ready" --per-page 10     # Ready to work on
glab issue list -R <OWNER>/<REPO> --label "priority::high" --per-page 10   # High priority
glab issue list -R <OWNER>/<REPO> --closed --per-page 10                   # Recently closed
glab issue view -R <OWNER>/<REPO> <IID>                                    # View issue details
glab issue view -R <OWNER>/<REPO> <IID> --comments                         # With comments
glab issue create -R <OWNER>/<REPO> --title "title" --label "priority::high,status:ready"
glab issue update -R <OWNER>/<REPO> <IID> --label "status:in-progress"
glab issue close -R <OWNER>/<REPO> <IID>
glab issue note -R <OWNER>/<REPO> <IID> -m "Comment text"                  # Add comment

# MRs
glab mr list -R <OWNER>/<REPO>                                             # Open MRs
glab mr create -R <OWNER>/<REPO> --fill --draft                            # Create draft MR
glab mr merge -R <OWNER>/<REPO> <MR_IID>                                   # Merge MR

# Pipelines
glab pipeline list -R <OWNER>/<REPO> --per-page 5                          # Recent pipelines
glab pipeline status -R <OWNER>/<REPO> <ID>                                # Pipeline details

# API (no --repo exists here — the encoded endpoint and explicit host identify the target)
glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/issues?state=opened&per_page=50"
glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/milestones?state=active"
```

### GitHub (gh)

```bash
# Issues
gh issue list -R <OWNER>/<REPO> --limit 50                                 # All open issues
gh issue list -R <OWNER>/<REPO> --label "status:ready" --limit 10          # Ready to work on
gh issue list -R <OWNER>/<REPO> --label "priority::high" --limit 10        # High priority
gh issue list -R <OWNER>/<REPO> --state closed --limit 10                  # Recently closed
gh issue view -R <OWNER>/<REPO> <NUMBER>                                   # View issue details
gh issue view -R <OWNER>/<REPO> <NUMBER> --comments                        # With comments
gh issue create -R <OWNER>/<REPO> --title "title" --label "priority::high,status:ready"
gh issue edit -R <OWNER>/<REPO> <NUMBER> --add-label "status:in-progress"
gh issue close -R <OWNER>/<REPO> <NUMBER>
gh issue comment -R <OWNER>/<REPO> <NUMBER> --body "Comment text"          # Add comment

# PRs
gh pr list -R <OWNER>/<REPO> --state open                                  # Open PRs
gh pr create -R <OWNER>/<REPO> --fill --draft                              # Create draft PR
gh pr merge -R <OWNER>/<REPO> <NUMBER>                                     # Merge PR

# Workflows (CI)
gh run list -R <OWNER>/<REPO> --limit 5                                    # Recent workflow runs
gh run view -R <OWNER>/<REPO> <RUN_ID>                                     # Run details

# API
gh api "repos/{owner}/{repo}/issues?state=open&per_page=50"
gh api "repos/{owner}/{repo}/milestones?state=open"
```

---

## glab CLI Quirks

These are known differences from `gh` that cause frequent mistakes:

| Quirk | Correct | Wrong |
|-------|---------|-------|
| Listing closed issues | `glab issue list -R <OWNER>/<REPO> --closed` | `glab issue list -R <OWNER>/<REPO> --state closed` |
| Confirmations | glab has NO `--yes` flag | Do not pass `--yes` |
| Comprehensive listing | `glab issue list -R <OWNER>/<REPO> --per-page 100` | Default per-page is small |
| Pagination flag | `--per-page N` (glab) | `--limit N` (that is gh syntax) |

---

## Label Taxonomy

**`priority::<level>` is canonical** (scoped double colon). `area:` / `type:` / `status:` / `from:` stay single-colon.

### Priority Labels
- `priority::critical` -- blocking production or users
- `priority::high` -- important, schedule this sprint
- `priority::medium` -- plan for next sprint
- `priority::low` -- backlog, nice-to-have

### Status Labels
- `status:ready` -- defined, ready to pick up
- `status:in-progress` -- actively being worked on
- `status:review` -- MR/PR created, awaiting review
- `status:blocked` -- waiting on external dependency

### Area Labels
- `area:frontend` | `area:backend` | `area:database`
- `area:ai` | `area:security` | `area:testing`
- `area:ci` | `area:infrastructure` | `area:compliance`
- `area:skills` | `area:vcs` | `area:harness`

### Type Labels
- `bug` | `feature` | `enhancement` | `refactor`
- `chore` | `documentation` | `epic` | `discovery`

---

## Issue Templates

### Bug

```markdown
## Description
What happens vs. what should happen.

## Steps to Reproduce
1.
2.

## Root Cause (if known)

## Acceptance Criteria
- [ ]
```

### Feature

```markdown
## Goal
What should be achieved and why.

## Tasks
- [ ]

## Acceptance Criteria
- [ ]

## Session Type
[housekeeping|feature|deep]
```

### Carryover (from /close)

```markdown
## [Carryover] Original Task Description

### What was completed
- [completed items]

### What remains
- [ ] [remaining task 1]
- [ ] [remaining task 2]

### Context for next session
[relevant context, file paths, decisions made]

### Original Issue
Relates to #ORIGINAL_IID
```

### Discovery Finding

```markdown
## [Discovery] <finding title>

**Probe:** <probe_name>
**Severity:** <priority::critical|high|medium|low>
**Category:** <code|infra|ui|arch|session|audit|vault|feature>

### Finding
<description of the problem>

### Evidence
- **File:** `<file_path>`
- **Line:** <line_number>
- **Code:**
  ```
  <matched_text with surrounding context>
  ```

### Impact
<why this matters>

### Recommended Fix
<concrete fix suggestion>

### Acceptance Criteria
- [ ] <specific, verifiable condition>
- [ ] Quality gates pass after fix
```

Labels for discovery findings: `type:discovery`, `priority::<level>`, `area:<inferred>`, `status:ready`



---

CI pipeline commands are listed in the Common CLI Commands section above (Pipelines/Workflows). Interpret: green=passed, red=failed (investigate before proceeding), pending=in progress.