Expert guidance for using the GitLab CLI (glab) to manage GitLab issues, merge requests, CI/CD pipelines, repositories, and other GitLab operations from the command line...
Provides guidance for using glab, the official GitLab CLI, to perform GitLab operations from the terminal.
Invoke when the user needs to:
Verify glab installation before executing commands:
glab --version
If not installed, inform the user and provide platform-specific installation guidance.
Most glab operations require authentication:
# Interactive authentication
glab auth login
# Check authentication status
glab auth status
# For self-hosted GitLab
glab auth login --hostname gitlab.example.org
# Using environment variables
export GITLAB_TOKEN=your-token
export GITLAB_HOST=gitlab.example.org # for self-hosted
# 1. Ensure branch is pushed
git push -u origin feature-branch
# 2. Create MR
glab mr create --title "Add feature" --description "Implements X"
# With reviewers and labels
glab mr create --title "Fix bug" --reviewer=alice,bob --label="bug,urgent"
# 1. List MRs awaiting your review
glab mr list --reviewer=@me
# 2. Checkout MR locally to test
glab mr checkout <mr-number>
# 3. After testing, approve
glab mr approve <mr-number>
# 4. Add a general comment
glab mr note <mr-number> -m "Please update tests"
To anchor a comment to a specific line in the diff (a DiffNote), you must use a JSON body with the Content-Type: application/json header. Using -F form fields will create an unanchored DiscussionNote.
# Get SHA values from the MR
glab mr view <id> --output=json | grep -oP '"(base_sha|head_sha|start_sha)":\s*"\K[0-9a-f]{40}'
# Post a DiffNote on a new line
glab api --method POST "projects/:id/merge_requests/:iid/discussions" \
-H "Content-Type: application/json" \
--input - <<'JSONEOF'
{
"body": "Your review comment here",
"position": {
"base_sha": "<base_sha>",
"start_sha": "<start_sha>",
"head_sha": "<head_sha>",
"position_type": "text",
"new_path": "path/to/file.js",
"new_line": 42
}
}
JSONEOF
Key rules for DiffNotes:
--input - with a heredoc and -H "Content-Type: application/json". Never use -F for the position object — it will silently create a DiscussionNote instead.@@ -old,count +new,count @@), not the diff output line numbers. Count only context lines and + lines from the hunk start.git fetch origin <branch> then git grep), not the current working branch.glab api --method PUT "projects/:id/merge_requests/:iid/notes/:note_id" -H "Content-Type: application/json" --input - <<< '{"body":"updated text"}'glab api "projects/:id/merge_requests/:iid/discussions" --paginate# Create issue with labels
glab issue create --title "Bug in login" --label=bug
# Link MR to issue
glab mr create --title "Fix login" --description "Closes #<issue-number>"
# List your assigned issues
glab issue list --assignee=@me
# Watch pipeline in progress
glab pipeline ci view
# Check pipeline status
glab ci status
# View logs if failed
glab ci trace
# Retry failed pipeline
glab ci retry
# Lint CI config before pushing
glab ci lint
When not in a Git repository, specify the repository:
glab mr list -R owner/repo
glab issue list -R owner/repo
Set hostname for all commands:
export GITLAB_HOST=gitlab.example.org
# or per-command
glab repo clone gitlab.example.org/owner/repo
glab api "projects/:id/merge_requests/{mr}/discussions?per_page=100" | jq '[.[] | select(.notes[0].resolvable == true and .notes[0].resolved == false) | {id: .notes[0].id, body: .notes[0].body[0:100], path: .notes[0].position.new_path, line: .notes[0].position.new_line}]'
Use JSON output for parsing:
glab mr list --output=json | jq '.[] | .title'
glab mr note creates standalone comments. To reply within a discussion thread, use the API:
# 1. Find the discussion_id containing the note
glab api "projects/:id/merge_requests/{mr}/discussions" | jq '.[] | select(.notes[].id == {note_id}) | .id'
# 2. Post reply to the discussion thread
glab api --method POST "projects/:id/merge_requests/{mr}/discussions/{discussion_id}/notes" --field body="Your reply"
Example:
# Get discussion_id for note 13698970
glab api "projects/:id/merge_requests/1013/discussions" | jq '.[] | select(.notes[].id == 13698970) | {id}'
# Returns: {"id": "5356c3552e72e7b4c49276eb4dacfe3efe5c2c5c"}
# Reply to that thread
glab api --method POST "projects/:id/merge_requests/1013/discussions/5356c3552e72e7b4c49276eb4dacfe3efe5c2c5c/notes" --field body="Thanks for the review!"
The glab api command provides direct GitLab API access:
# Basic API call
glab api projects/:id/merge_requests
# IMPORTANT: Pagination uses query parameters in URL, NOT flags
# ❌ WRONG: glab api --per-page=100 projects/:id/jobs
# ✓ CORRECT: glab api "projects/:id/jobs?per_page=100"
# Auto-fetch all pages
glab api --paginate "projects/:id/pipelines/123/jobs?per_page=100"
# POST with data
glab api --method POST projects/:id/issues --field title="Bug" --field description="Details"
glab auth status--help to explore command options: glab <command> --helpglab ci lintgit remote -vMerge Requests:
glab mr list --assignee=@me - Your assigned MRsglab mr list --reviewer=@me - MRs for you to reviewglab mr create - Create new MRglab mr checkout <number> - Test MR locallyglab mr approve <number> - Approve MRglab mr merge <number> - Merge approved MRIssues:
glab issue list - List all issuesglab issue create - Create new issueglab issue close <number> - Close issueCI/CD:
glab pipeline ci view - Watch pipelineglab ci status - Check statusglab ci lint - Validate .gitlab-ci.ymlglab ci retry - Retry failed pipelineRepository:
glab repo clone owner/repo - Clone repositoryglab repo view - View repo detailsglab repo fork - Fork repositoryFor detailed command documentation, refer to:
Load these references when:
"command not found: glab" - Install glab or verify PATH
"401 Unauthorized" - Run glab auth login
"404 Project Not Found" - Verify repository name and access permissions
"not a git repository" - Navigate to repo or use -R owner/repo flag
"source branch already has a merge request" - Use glab mr list to find existing MR
For detailed troubleshooting, load references/troubleshooting.md.
--web flag to open in browser--output=json for scripting and automation