| 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.
Quick start
glab mr create --fill
glab mr list --assignee=@me
glab mr checkout 123
glab mr diff
glab mr approve
glab mr merge 123 --when-pipeline-succeeds --remove-source-branch
Common workflows
Creating MRs
From current branch:
glab mr create --fill --label bugfix --assignee @reviewer
glab mr create --fill --auto-merge
glab mr create --fill --template .gitlab/merge_request_templates/default.md
From issue:
glab mr for 456
Draft MR:
glab mr create --draft --title "WIP: Feature X"
Review workflow
-
List pending reviews:
glab mr list --reviewer=@me --state=opened
-
Checkout and test:
glab mr checkout 123
npm test
-
Leave feedback:
glab mr note create 123 -m "Looks good, one question about the cache logic"
glab mr note create 123 --reply abc12345 -m "Good catch — updated"
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?"
glab mr note list 123
glab mr note resolve 3107030349 123
glab mr note reopen 3107030349 123
-
Approve:
glab mr approve 123
Automated review workflow:
For repetitive review tasks, use the automation script:
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:
glab mr merge 123 --when-pipeline-succeeds --remove-source-branch
Squash commits:
glab mr merge 123 --squash
Rebase before merge:
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
Native MR note flow (glab mr note create)
As of glab v1.94.0, glab mr note create is the preferred command surface for posting new MR discussions.
Use native glab mr note create when
glab mr note create 123 -m "Please add a regression test"
glab mr note create 123 --reply abc12345 -m "Fixed in the latest push"
glab mr note create 123 --file src/app.ts -m "General concern on this file"
glab mr note create 123 --file src/app.ts --line 84 -m "This branch can return null"
glab mr note create 123 --file src/app.ts --line 84:96 -m "Consider extracting this block"
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.
--line and --old-line require --file and cannot be used together.
--file, --reply, and --unique are mutually exclusive.
- Omit both
--line and --old-line when you want a file-level diff comment.
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 silently falling back to a general MR note
- you are posting many comments in batch
- you are targeting tricky diffs (new files, renamed files, complex paths, or line-code fallback cases)
glab mr note create is now enough for most interactive reply and diff-comment workflows. The helper remains valuable for robust automated review pipelines.
Posting Inline Comments on MR Diffs
The glab api --field Problem
glab api --field position[new_line]=N silently falls back to a general (non-inline) comment
when GitLab rejects the position data. This happens with:
- Entirely new files (
new_file: true in the diff)
- Files with complex/encoded paths
- Any nested position field that doesn't survive form encoding
There is no error — GitLab just drops the position and creates a general discussion. You won't know
it failed unless you check the returned note's position field.
The Fix: Always Use JSON Body
Post inline comments via the REST API with a Content-Type: application/json body:
import json, urllib.request, urllib.parse, subprocess
token = subprocess.run(
["glab", "config", "get", "token", "--host", "gitlab.com"],
capture_output=True, text=True
).stdout.strip()
project = urllib.parse.quote("mygroup/myproject", safe="")
mr_iid = 42
r = urllib.request.urlopen(urllib.request.Request(
f"https://gitlab.com/api/v4/projects/{project}/merge_requests/{mr_iid}/versions",
headers={"PRIVATE-TOKEN": token}
))
v = json.loads(r.read())[0]
payload = {
"body": "Your comment here",
"position": {
"base_sha": v["base_commit_sha"],
"start_sha": v["start_commit_sha"],
"head_sha": v["head_commit_sha"],
"position_type": "text",
"new_path": "src/utils/helpers.ts",
"new_line": 16,
"old_path": "src/utils/helpers.ts",
"old_line": None
}
}
req = urllib.request.Request(
f"https://gitlab.com/api/v4/projects/{project}/merge_requests/{mr_iid}/discussions",
data=json.dumps(payload).encode(),
headers={"PRIVATE-TOKEN": token, "Content-Type": "application/json"},
method="POST"
)
with urllib.request.urlopen(req) as resp:
result = json.loads(resp.read())
note = result["notes"][0]
is_inline = note.get("position") is not None
print("inline:", is_inline, "| disc_id:", result["id"])
Finding the Correct Line Number
Line numbers must point to an added line (+ prefix) in the diff — context lines and removed
lines will cause the position to be rejected:
import re
def get_new_line_number(diff_text, keyword):
"""Find the new_file line number of the first added line containing keyword."""
new_line = 0
for line in diff_text.split("\n"):
hunk = re.match(r"@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@", line)
if hunk:
new_line = int(hunk.group(1)) - 1
continue
if line.startswith("-") or line.startswith("\\"):
continue
new_line += 1
if line.startswith("+") and keyword in line:
return new_line
return None
diffs = json.loads(...)
for d in diffs:
if d["new_path"] == "src/utils/helpers.ts":
line = get_new_line_number(d["diff"], "safeParse")
print("line:", line)
Reusable Script
For scripted or automated MR reviews, use the bundled helper:
python3 scripts/post-inline-comment.py \
--project "mygroup/myproject" \
--mr 42 \
--file "src/utils/helpers.ts" \
--line 16 \
--body "This returns the wrapper object — use .data instead."
python3 scripts/post-inline-comment.py \
--project "mygroup/myproject" \
--mr 42 \
--batch comments.json
Batch file format:
[
{ "file": "src/utils/helpers.ts", "line": 16, "body": "Comment 1" },
{ "file": "src/routes/+page.svelte", "line": 58, "body": "Comment 2" }
]
The script auto-reads your token from glab config, fetches fresh SHAs and diffs, and uses a two-step anchoring strategy:
- Try the normal
position[new_line] inline payload first.
- If GitLab rejects it with a
line_code validation error, compute the diff anchor and retry with position[line_range][start/end][line_code].
That retry path is the preferred recovery for failures like:
400 Bad request - Note {:line_code=>["can't be blank", "must be a valid line code"]}
Only if that retry also fails should your broader review workflow fall back to a root MR note that clearly says inline anchoring failed while preserving the exact finding text and reviewer identity.
Filtering discussion threads by resolution
glab mr view 123 --unresolved
glab mr view 123 --resolved
Useful for quickly checking which review threads still need attention before merging.
glab mr list filtering flags
glab mr list supports the following filtering and sorting flags:
glab mr list --author <username>
glab mr list --source-branch feature/my-branch
glab mr list --target-branch main
glab mr list --draft
glab mr list --not-draft
glab mr list --label bugfix
glab mr list --not-label wip
glab mr list --order updated_at --sort desc
glab mr list --order merged_at --sort asc
glab mr list --created-after 2026-01-01
glab mr list --created-before 2026-03-01
glab mr list --search "login fix"
glab mr list \
--assignee @me \
--author vince \
--reviewer @me \
--label bugfix \
--not-label wip \
--source-branch feature/x \
--target-branch main \
--milestone "v2.0" \
--draft \
--state opened \
--order updated_at \
--sort desc \
--search "auth" \
--created-after 2026-01-01
Structured output
glab mr approvers supports --output json / -F json for structured output, which is useful for agent automation.
glab mr approvers 123 --output json
glab mr approvers 123 -F json
Command reference
For complete command documentation and all flags, see references/commands.md.
Available commands:
approve - Approve merge requests
checkout - Check out an MR locally
close - Close merge request
create - Create new MR
delete - Delete merge request
diff - View changes in MR
for - Create MR for an issue
list - List merge requests
merge - Merge/accept MR
note - MR discussion commands; use glab mr note create for new comments, plus list, resolve, and reopen
rebase - Rebase source branch
reopen - Reopen merge request
revoke - Revoke approval
subscribe / unsubscribe - Manage notifications
todo - Add to-do item
update - Update MR metadata
view - Display MR details