- name
- glab-mr
- description
- Create, view, manage, approve, and merge GitLab merge requests. Use when working with MRs: creating from branches/issues, reviewing, approving, adding comments, resolving discussion threads, checking out locally, viewing diffs, rebasing, merging, or managing state. Triggers on merge request, MR, pull request, PR, review, approve, merge, resolve thread.
# glab mr
Create, view, and manage GitLab merge requests.
## Rebase completion and issue branches
`mr rebase` and `mr merge --rebase` wait for the queued server rebase to visibly complete rather than treating an initial `rebase_in_progress=false` as success. Polling is bounded to 300 attempts at one-second intervals and responds to cancellation. Rebase errors/timeouts stop the merge; verify server state before an approved retry. `--sha` and `--rebase` are mutually exclusive because rebasing changes the head SHA; `--squash` and `--rebase` are also exclusive. These commands mutate branches/MRs and require approval for the exact target.
`mr for` and `mr create --related-issue` retry branch creation only for HTTP 400 name/hierarchy collisions, trying suffixes `-1` through `-100`. Authentication, permissions, invalid refs, network failures, and unrelated errors stop immediately. Diagnose the original error instead of repeatedly creating branches or retrying all failures. Confirm the issue, project, base branch, and intended writes first.
## Resolve or reopen in another repository
With `--repo`, `mr note resolve` and `mr note reopen` require an explicit MR before the discussion identifier:
```bash
glab mr note resolve 123 abc12345 --repo group/project
glab mr note reopen 123 abc12345 --repo group/project
```
The discussion may be a full ID, a unique prefix of at least eight characters, or a numeric note ID. Without `--repo`, omitting the MR uses the current branch. The binary's usage line lists the operands inconsistently; follow its examples and the implementation: MR first, discussion second. Confirm the target before changing discussion state.
## Checkout, creation, and selection
`glab mr checkout 123 --worktree ../review-mr-123` fetches and checks out the MR in a separate worktree. Reusing that path updates the existing worktree. A branch can be checked out in only one worktree; choose `--branch` for a different local name when needed. Review divergence/reset prompts carefully: worktree isolation does not authorize discarding commits or local changes. Fetching through a matched remote creates the tracking ref.
`mr create --fill` derives title/description from commits and defaults to pushing unless `--push` was explicitly set. Use `glab mr create --fill --push=false` to suppress that push; it still creates an MR and is not a dry run. Ensure the source branch is already available remotely. Draft creation avoids adding a second `Draft:` prefix.
`glab mr update feature-branch --state opened --ready` restricts branch lookup to open MRs. Accepted states are `opened`, `closed`, `merged`, `locked`, and `any` (default); IDs and URLs ignore this selection filter. `--state` does not itself change MR state.
A list filter for exactly one assignee with no reviewers, or exactly one reviewer with no assignees, preserves server ordering. Do not infer the same ordering guarantees for combined multi-user results. `mr view` shows available human-readable spent/estimated time; use JSON for machine consumption.
## Template selection
For `create --template`, a bare name (with optional `.md`) resolves under the repository's `.gitlab/merge_request_templates/` directory. An absolute path or a path containing a separator is read directly; relative paths use the current directory and `~/` is supported. Use `./template.md` for a file in the current directory, rather than a bare template name. A missing template directory means no templates; other directory-listing failures are surfaced and should be repaired before retrying. Read and approve the file contents before posting them; `--description-file` remains mutually exclusive with `--template`.
## Bulk lookup and read output
Multi-MR approve, close, delete, reopen, revoke, subscribe, and unsubscribe commands bound concurrent lookups. Review every target and approval scope; bounded lookups do not make writes atomic. `mr issues` uses the API's total for its header rather than the current page length; a correct total does not mean all matching issues are displayed. `mr view` avoids fetching fields/approval state that the selected output does not use; do not infer missing permissions or unavailable data solely from fewer requests.
## Quick start
```bash
# Create MR from current branch
glab mr create --fill
# Create or update with a multi-line description from a file
glab mr create --title "Fix login bug" --description-file description.md
glab mr update 123 --description-file description.md
# Attach local files to a description
glab mr create --title "Fix login bug" --description "Before and after:" \
--attach ./before.png --attach ./after.png
glab mr update 123 --attach ./latest.png
# List my MRs
glab mr list --assignee=@me
# Review an MR
glab mr checkout 123
glab mr diff
glab mr approve
# Merge an MR
glab mr merge 123 --when-pipeline-succeeds --remove-source-branch
```
For automated patch consumption, use `glab mr diff --raw`. The normal rendered diff is intended for people; `--raw` returns an unmodified Git patch with standard unified diff headers.
## Common workflows
### Creating MRs
**From current branch:**
```bash
glab mr create --fill --label bugfix --assignee @reviewer
# Create now, merge automatically when checks pass
glab mr create --fill --auto-merge
# Start from an MR template file when your project uses one
glab mr create --fill --template .gitlab/merge_request_templates/default.md
```
For one-off multi-line descriptions, use `--description-file <path>` or `--description-file -` for stdin. It is mutually exclusive with `--description`; on create, it is also mutually exclusive with `--template`. A file containing exactly `-` is rejected because `--description -` means "open an editor".
Use the experimental `--attach <path>` repeatedly to upload files and append GitLab-provided Markdown references to the description. `--attach -` reads one file from stdin and cannot share stdin with `--description-file -`. On update, attachments append to the existing description unless a replacement description is supplied. For fork merge requests, `mr create` uploads attachments to the target project so the references resolve there.
In a non-interactive environment, an explicit `--title` is sufficient; glab can create the MR with an empty description instead of requiring a TTY or `--description`. Interactive terminals still prompt for a missing description/template. For deterministic automation, pass `--yes` plus any source/target/repository selectors explicitly.
```bash
GLAB_NO_PROMPT=1 glab mr create \
--title "Fix login timeout" \
--source-branch fix/login-timeout \
--target-branch main \
--yes
```
**Without a local Git checkout:**
`glab mr create` can create an MR outside a Git repository when every
remote-dependent input is supplied as a flag. The source branch must already exist on
the selected source project. Do not use `--push`, `--fill`, or `--template`,
because those require local repository state.
```bash
glab mr create \
--repo group/project \
--source-branch feature-branch \
--target-branch main \
--title "Add feature" \
--description "Details..." \
--yes
# Fork source into an upstream target
glab mr create \
--repo upstream/project \
--head your-namespace/project \
--source-branch feature-branch \
--target-branch main \
--title "Add feature" \
--description "Details..." \
--yes
```
**From issue:**
```bash
glab mr for 456 # Creates MR linked to issue #456
```
**Draft MR:**
```bash
glab mr create --draft --title "WIP: Feature X"
```
### Review workflow
1. **List pending reviews:**
```bash
glab mr list --reviewer=@me --state=opened
```
2. **Checkout and test:**
```bash
glab mr checkout 123
npm test
```
3. **Leave feedback:**
```bash
# Forward command surface for new MR comments/discussions
glab mr note create 123 -m "Looks good, one question about the cache logic"
# Automation/status update that should not create a resolvable thread
glab mr note create 123 -m "Build status: green" --resolvable=false
# Reply inside an existing discussion thread
glab mr note create 123 --reply abc12345 -m "Good catch — updated"
# Internal note visible only to project members
glab mr note create 123 --internal -m "Rotating the leaked token now."
# Native diff comments on the latest MR version
glab mr note create 123 --file src/cache.ts --line 42 -m "Please extract this branch"
glab mr note create 123 --file src/cache.ts --old-line 17 -m "Why was this removed?"
# Stage comments in a private pending review, then publish them together
glab mr note draft create 123 --file src/cache.ts --line 42 -m "Please extract this branch"
glab mr note draft list 123 --output json
glab mr note draft publish 123 --reviewer-state requested_changes --yes
# Attach evidence to a new or existing note
glab mr note create 123 -m "Rendered result" --attach ./result.png
glab mr note update 123 456789 --attach ./updated.png
# List discussion threads and expose note/discussion IDs (experimental)
glab mr note list 123
glab mr note list 123 --state unresolved --type diff
glab mr note list 123 --output json
# Resolve or reopen a discussion by note/discussion ID (experimental)
glab mr note resolve 123 3107030349
glab mr note reopen 123 3107030349
```
For `glab mr note update`, the note ID is always the final positional argument. The help renderer shows required arguments before optional ones, but the command parses the last argument as `<note-id>`; use `glab mr note update <mr> <note-id>` when specifying an MR.
4. **Approve:**
```bash
glab mr approve 123
```
**Automated review workflow:**
For repetitive review tasks, use the automation script bundled with this skill
under `scripts/` (paths below are relative to the skill's own directory):
```bash
scripts/mr-review-workflow.sh 123
scripts/mr-review-workflow.sh 123 "pnpm test"
```
This automatically: checks out → runs tests → posts result → approves if passed.
### Merge strategies
**Auto-merge when pipeline passes:**
```bash
glab mr merge 123 --when-pipeline-succeeds --remove-source-branch
```
Merge output reports the resulting merge request state accurately. Do not assume a successful `glab mr merge --auto-merge` prints `Merged!`; when the MR is only armed for auto-merge, automation should treat the accepted state as pending rather than already merged.
**Squash commits:**
```bash
glab mr merge 123 --squash
```
**Rebase before merge:**
```bash
glab mr rebase 123
glab mr merge 123
```
## Troubleshooting
**Merge conflicts:**
- Checkout MR: `glab mr checkout 123`
- Resolve conflicts manually in your editor
- Commit resolution: `git add . && git commit`
- Push: `git push`
**Cannot approve MR:**
- Check if you're the author (can't self-approve in most configs)
- Verify permissions: `glab mr approvers 123`
- Ensure MR is not in draft state
**Pipeline required but not running:**
- Check `.gitlab-ci.yml` exists in branch
- Verify CI/CD is enabled for project
- Trigger manually: `glab ci run`
**"MR already exists" error:**
- List existing MRs from branch: `glab mr list --source-branch <branch>`
- Close old MR if obsolete: `glab mr close <id>`
- Or update existing: `glab mr update <id> --title "New title"`
## Related Skills
**Working with issues:**
- See `glab-issue` for creating/managing issues
- Use `glab mr for <issue-id>` to create MR linked to issue
- Script: `scripts/create-mr-from-issue.sh` automates branch + MR creation
**CI/CD integration:**
- See `glab-ci` for pipeline status before merging
- Use `glab mr create --auto-merge` to request auto-merge up front, or `glab mr merge --when-pipeline-succeeds` on an existing MR
**Automation:**
- Script: `scripts/mr-review-workflow.sh` for automated review + test workflow
## Listing and targeting MR discussions
`glab mr note list` text output includes each note ID and an eight-character discussion ID prefix for every non-system discussion, plus both relative and absolute timestamps. Pass the characters before the ellipsis directly to `--reply`; use JSON when a workflow needs the full discussion ID. Use verified identifiers with `resolve`, `reopen`, or `--reply` rather than scraping author/body text.
```bash
# Filter the text view
glab mr note list 123 --type diff --state unresolved
glab mr note list 123 --file src/app.ts
# Prefer JSON when an automation needs stable IDs
glab mr note list 123 --output json \
--jq '.[] | {discussion_id: .id, note_ids: [.notes[].id]}'
# Extract full discussion IDs
glab mr note list 123 -F json --jq '.[].id'
# Act on the verified identifier
glab mr note resolve 123 <discussion-or-note-id>
glab mr note reopen 123 <discussion-or-note-id>
```
Upstream's generated help demonstrates the same extraction with an external `jq` pipe. This skill set prefers the supported built-in `--jq` flag so filtering stays inside `glab` and avoids a separate shell process.
`--type` accepts `all`, `general`, `diff`, or `system`; `--state` accepts `all`, `resolved`, or `unresolved`; `--file` limits results to diff notes on one path. These subcommands remain experimental, so confirm live help when scripting across mixed `glab` versions.
In text output, the default `--type all` includes system notes as well as regular discussions. Use `--type system` when you want only system activity, or select a narrower note type when automation should not parse assignment/status events as user feedback.
## Native MR note flow (`glab mr note create`)
`glab mr note create` is the preferred command surface for posting new MR discussions.
### Use native `glab mr note create` when
```bash
# New top-level discussion/comment
glab mr note create 123 -m "Please add a regression test"
# Non-resolvable note for automation/status output
glab mr note create 123 -m "Build status: green" --resolvable=false
# Reply to an existing discussion thread
glab mr note create 123 --reply abc12345 -m "Fixed in the latest push"
# File-level diff comment
glab mr note create 123 --file src/app.ts -m "General concern on this file"
# Line comment on the new side of the diff
glab mr note create 123 --file src/app.ts --line 84 -m "This branch can return null"
# Range comment on the new side
glab mr note create 123 --file src/app.ts --line 84:96 -m "Consider extracting this block"
# Comment on a removed line from the old side
glab mr note create 123 --file src/app.ts --old-line 37 -m "Why was this guard removed?"
```
Flag rules worth remembering from the upstream help/docs:
- `--reply` targets an existing discussion thread instead of starting a new one.
- `--reply` accepts a full discussion ID or a unique prefix of at least 8 characters.
- By default, new top-level notes are created as resolvable discussion threads. Use `--resolvable=false` for bot/status comments that should not block projects requiring all threads to be resolved.
- `--line` and `--old-line` require `--file` and cannot be used together.
- `--file`, `--reply`, and `--unique` are mutually exclusive.
- `--resolvable=false` cannot be combined with `--reply`, `--file`, `--line`, or `--old-line`.
- Pending review comments use `glab mr note draft create`, not `mr note create --draft`. Draft creation supports diff targeting, replies, and attachments, but not `--unique`, `--resolvable`, or `--internal`.
- `--internal` creates a note visible only to project members. It cannot be combined with diff targeting (`--file`, `--line`, or `--old-line`), and a new top-level internal note must not explicitly request `--resolvable=true`.
- With `--reply --internal`, glab refuses to post to a public thread. A reply to an internal thread stays internal even when `--internal` is omitted.
- `--attach` can be repeated and may provide the entire note body; it cannot be combined with `--unique` because each upload produces a fresh URL.
- On `mr note update`, attachment-only input appends to the current note body; pairing `--message` with attachments replaces the body and then appends the new references.
- Omit both `--line` and `--old-line` when you want a file-level diff comment.
### Pending review comments
Use pending comments when you want to stage several review findings before making them visible:
```bash
glab mr note draft create 123 --file src/app.ts --line 84 \
-m "This branch can return null"
glab mr note draft create 123 --reply abc12345 \
-m "I reproduced this locally"
# Inspect only your own pending comments before publishing
glab mr note draft list 123 --output json
# Review state is not an approval; use glab mr approve separately when appropriate.
glab mr note draft publish 123 \
--message "A few blockers, see the comments." \
--reviewer-state requested_changes \
--yes
```
`publish` releases only your own pending comments. `--reviewer-state` accepts `requested_changes` or `reviewed`; neither records a formal approval. If you authored the merge request, GitLab ignores `--reviewer-state` unless you are also listed as a reviewer, and glab warns about that condition. `--internal` applies only to the optional summary note and requires `--message`. Non-interactive runs require `--yes`, and publishing fails when no pending comments exist. Attachments are uploaded immediately even while the comment itself remains pending.
`draft create` prints the numeric pending-comment ID. Preserve it for `draft update` or `draft delete`; it is not a published note ID or discussion ID. When an MR is supplied, the parser expects the draft ID last, despite the renderer placing required arguments first:
```bash
# Inspect the selected draft before changing it
glab mr note draft list 123 --output json
glab mr note draft update 123 456 -m "Revised finding"
# Delete only after explicit approval; this affects your pending review
glab mr note draft delete 123 456 --yes
```
`draft update` changes only the body, not its diff position; image-position drafts cannot be updated from the CLI because their position cannot be preserved. Attachment-only updates append to the existing body, while an explicit message replaces the body before attachment references are appended. `draft delete` prompts unless `--yes` is supplied. The draft command group acts only on your own pending comments; other reviewers' drafts are not listed, edited, deleted, or published. Do not use the removed `mr note publish` command: its `--help` falls back to parent help rather than proving that it still exists.
### Keep the helper/script path when
Use the bundled inline-comment helper or raw `glab api` JSON-body approach when you need stronger anchoring guarantees for automation, especially when:
- you must verify that GitLab created an actual inline discussion rather than a root MR note
- you are posting many comments in batch
View on GitHub