| 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
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 123 -m "Looks good, one question about the cache logic"
glab mr note list 123
glab mr note resolve 3107030349 123
glab mr note reopen 3107030349 123
glab mr note resolve <discussion-id> 123
glab mr note reopen <discussion-id> 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
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 (v1.88.0+)
glab mr view 123 --unresolved
glab mr view 123 --resolved
Useful for quickly checking which review threads still need attention before merging.
v1.87.0 Changes: New glab mr list Flags
The following flags were added to glab mr list in v1.87.0:
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
v1.90.0 Updates
glab mr create adds --auto-merge to set merge-when-ready during MR creation
glab mr note adds list, resolve, and reopen subcommands for discussion management (EXPERIMENTAL)
- For discussion state changes in v1.90.0, prefer
glab mr note resolve / glab mr note reopen; do not imply --resolve / --unresolve can be combined with -m
v1.89.0 Updates
v1.89.0+: glab mr approvers supports --output json / -F json for structured output, ideal for agent automation.
glab mr approvers 123 --output json
glab mr approvers 123 -F json
v1.88.0 Changes
glab mr note: Added --resolve <discussion-id> and --unresolve <discussion-id> flags for discussion state changes; in v1.90.0 docs should prefer the explicit note resolve / note reopen subcommands for user-facing guidance
glab mr view: Added --resolved and --unresolved flags to filter displayed discussion threads by resolution status
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 - Add comment to MR; includes list, resolve, and reopen subcommands in v1.90.0
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