Gitlab Auto Merge
811
Automated merge request management for GitLab. This service monitors your GitLab project and automatically handles merge requests.
merge_request_event source — see Pipeline Cancellation Scope)docker run -d \
--name gitlab-auto-merge \
-p 8711:8711 \
-e EXECUTION_ENVIRONMENT=Docker \
-e GITLAB_SERVER_URL=https://gitlab.example.com \
-e GITLAB_PROJECT=group/project \
-e GITLAB_ACCESS_TOKEN=glpat-xxxx \
neckarit/gitlab-auto-merge:latest \
--mode=Run
services:
gitlab-auto-merge:
image: neckarit/gitlab-auto-merge:latest
container_name: gitlab-auto-merge
restart: unless-stopped
ports:
- "8711:8711"
environment:
- EXECUTION_ENVIRONMENT=Docker
- DEPLOYMENT_STAGE=Production
- GITLAB_SERVER_URL=https://gitlab.example.com
- GITLAB_PROJECT=group/project
- GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
command:
- "--mode=Run"
Create a .env file next to your docker-compose.yml:
GITLAB_ACCESS_TOKEN=glpat-xxxxxxxxxxxx
Then start with:
docker compose up -d
services:
gitlab-auto-merge:
image: neckarit/gitlab-auto-merge:latest
container_name: gitlab-auto-merge
restart: unless-stopped
ports:
- "8711:8711"
volumes:
- /path/to/your/ca.crt:/certs/ca.crt:ro
environment:
- EXECUTION_ENVIRONMENT=Docker
- DEPLOYMENT_STAGE=Production
- GITLAB_SERVER_URL=https://gitlab.example.com
- GITLAB_PROJECT=group/project
- GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
- CA_CERT_PATH=/certs/ca.crt
command:
- "--mode=Run"
If your GitLab instance uses a self-signed certificate or a certificate signed by an internal CA, you can configure the service to trust it.
Pass the certificate directly as a Base64-encoded environment variable. No file mounts needed.
Generate Base64:
# Encode your PEM certificate to Base64
cat /path/to/your/ca.crt | base64 -w0
Docker Run:
docker run -d \
--name gitlab-auto-merge \
-p 8711:8711 \
-e EXECUTION_ENVIRONMENT=Docker \
-e GITLAB_SERVER_URL=https://gitlab.example.com \
-e GITLAB_PROJECT=group/project \
-e GITLAB_ACCESS_TOKEN=glpat-xxxx \
-e CA_CERT_BASE64="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t..." \
neckarit/gitlab-auto-merge:latest \
--mode=Run
Docker Compose:
services:
gitlab-auto-merge:
image: neckarit/gitlab-auto-merge:latest
container_name: gitlab-auto-merge
restart: unless-stopped
ports:
- "8711:8711"
environment:
- EXECUTION_ENVIRONMENT=Docker
- GITLAB_SERVER_URL=https://gitlab.example.com
- GITLAB_PROJECT=group/project
- GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
- CA_CERT_BASE64=${CA_CERT_BASE64}
command:
- "--mode=Run"
Mount the certificate file into the container.
Docker Run:
docker run -d \
--name gitlab-auto-merge \
-p 8711:8711 \
-v /path/to/your/ca.crt:/certs/ca.crt:ro \
-e EXECUTION_ENVIRONMENT=Docker \
-e GITLAB_SERVER_URL=https://gitlab.example.com \
-e GITLAB_PROJECT=group/project \
-e GITLAB_ACCESS_TOKEN=glpat-xxxx \
-e CA_CERT_PATH=/certs/ca.crt \
neckarit/gitlab-auto-merge:latest \
--mode=Run
Docker Compose:
services:
gitlab-auto-merge:
image: neckarit/gitlab-auto-merge:latest
container_name: gitlab-auto-merge
restart: unless-stopped
ports:
- "8711:8711"
volumes:
- /path/to/your/ca.crt:/certs/ca.crt:ro
environment:
- EXECUTION_ENVIRONMENT=Docker
- GITLAB_SERVER_URL=https://gitlab.example.com
- GITLAB_PROJECT=group/project
- GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
- CA_CERT_PATH=/certs/ca.crt
command:
- "--mode=Run"
Notes:
CA_CERT_BASE64 takes precedence over CA_CERT_PATH if both are set| Variable | Description | Required | Default |
|---|---|---|---|
GITLAB_SERVER_URL | GitLab instance URL (e.g., https://gitlab.com) | Yes | - |
GITLAB_PROJECT | Project path (e.g., mygroup/myproject) | Yes | - |
GITLAB_ACCESS_TOKEN | GitLab personal access token with api scope | Yes | - |
MERGE_REQUEST_BADGE_ENABLED | Embed the SVG status badge image in MR descriptions. Set to false when the service host is not reachable from user browsers. | No | true |
CA_CERT_BASE64 | Base64-encoded CA certificate (PEM format). Takes precedence over file path | No | - |
CA_CERT_PATH | Path to custom CA certificate (PEM format) | No | - |
EXECUTION_ENVIRONMENT | Runtime environment type | No | Docker |
DEPLOYMENT_STAGE | Deployment stage | No | - |
SERVICE_HOST | Service host identifier | No | - |
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP collector URL. Setting this single variable enables OpenTelemetry export (Ktor server traces + JVM auto-instrumentation). | No | - |
OTEL_EXPORTER_OTLP_PROTOCOL | OTLP wire protocol: grpc (port 4317) or http/protobuf (port 4318). Match it to your collector's listener. | No | grpc |
OTEL_RESOURCE_ATTRIBUTES | Comma-separated resource attributes tagged onto every signal, e.g. deployment.environment=production. | No | - |
OTEL_SDK_DISABLED | Force telemetry off explicitly. Defaults to true in the image; the entrypoint clears it once OTEL_EXPORTER_OTLP_ENDPOINT is set. | No | true (image) |
Telemetry is off by default — the image exports nothing and never phones home. It only emits traces once you point it at your own OTLP collector by setting OTEL_EXPORTER_OTLP_ENDPOINT. That single variable both selects the destination and lifts the image's OTEL_SDK_DISABLED=true default.
The endpoint's port determines the protocol: 4317 is gRPC (the default), 4318 is HTTP/protobuf. If your collector only speaks HTTP, use port 4318 and set OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf.
Docker Run:
docker run -d \
--name gitlab-auto-merge \
-p 8711:8711 \
-e EXECUTION_ENVIRONMENT=Docker \
-e GITLAB_SERVER_URL=https://gitlab.example.com \
-e GITLAB_PROJECT=group/project \
-e GITLAB_ACCESS_TOKEN=glpat-xxxx \
-e OTEL_EXPORTER_OTLP_ENDPOINT=https://your-collector.example.com:4317 \
neckarit/gitlab-auto-merge:latest \
--mode=Run
Docker Compose:
services:
gitlab-auto-merge:
image: neckarit/gitlab-auto-merge:latest
container_name: gitlab-auto-merge
restart: unless-stopped
ports:
- "8711:8711"
environment:
- EXECUTION_ENVIRONMENT=Docker
- GITLAB_SERVER_URL=https://gitlab.example.com
- GITLAB_PROJECT=group/project
- GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
- OTEL_EXPORTER_OTLP_ENDPOINT=https://your-collector.example.com:4317
- OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production
command:
- "--mode=Run"
The service emits Ktor server traces and the standard JVM auto-instrumentation. To force telemetry off explicitly — for example to silence the service in an environment where OTEL_EXPORTER_OTLP_ENDPOINT is set for other containers — set OTEL_SDK_DISABLED=true.
| Value | Description |
|---|---|
LocalDev | Local development (IDE, hot reload) |
Standalone | JAR running directly on server/VM |
Docker | Running inside a Docker container |
CI | Continuous Integration environment |
| Value | Description |
|---|---|
Development | Development environment (unstable, test data) |
Staging | Pre-production environment |
Production | Live production environment |
| Mode | Description |
|---|---|
DryRun | Only log what would be done (default). No changes to GitLab. |
OnlyLabels | Only update MR labels. No rebase, no merge, no pipeline cancellation. |
RebaseOnly | Rebase MRs and update labels, but don't cancel pipelines or merge. |
NoMerge | Rebase MRs, update labels, cancel pipelines, but don't merge. |
NoPipelineCancellation | Merge, rebase, update labels, but don't cancel pipelines. |
Run | Full execution: merge, rebase, update labels, cancel pipelines. |
Usage:
docker run ... neckarit/gitlab-auto-merge:latest --mode=Run
Use Cases:
DryRun - Test the service without making any changesOnlyLabels - Visualize MR status without affecting CI/CDRebaseOnly - Keep MRs up-to-date without interrupting running pipelinesNoMerge - Prepare MRs for merging, but let humans do the final mergeNoPipelineCancellation - Fully automated merging but let all pipelines run to completionRun - Fully automated merge workflow with pipeline optimization| Endpoint | Description |
|---|---|
GET /api/auto-merge/merge-requests | List categorized merge requests |
GET /api/auto-merge/pipelines | Pipeline status overview |
GET /api/auto-merge/log | Execution log |
POST /api/auto-merge/events/from-gitlab | GitLab webhook endpoint |
Configure a webhook in your GitLab project:
https://your-auto-merge-host/api/auto-merge/events/from-gitlabThe service automatically applies these labels to merge requests:
All Auto-Merge labels use the Merge:: namespace prefix, consistent with other project label namespaces (Component::, Status::, Type::).
| Label | Meaning |
|---|---|
Merge::Mergable | Ready to be merged (pipeline passed, approved) |
Merge::Waiting for CI | Pipeline is running or pending |
Merge::Waiting for CI (Last Failed) | Pipeline running, but previous pipeline failed |
Merge::Rebase Required | Needs rebase onto target branch |
Merge::Rebasing | Currently being rebased by Auto Merge |
Merge::Conflict | Has merge conflicts |
Merge::Todo | Has unresolved discussions or failed pipeline |
Merge::Not Approved | Waiting for approval |
Merge::Empty | MR has no commits |
Merge::Merged | Successfully merged by Auto Merge |
Note: MRs with running pipelines show the Waiting for CI status, while MRs with failed pipelines show Todo (user must take action). GitLab's native UI already displays pipeline status prominently (badge, header, widget).
User labels are manually managed and never automatically added or removed by Auto Merge:
| Label | Meaning |
|---|---|
Merge::Important | Prioritizes this MR — processed before others |
Merge::Low Priority | Only merged when no other MRs are in the queue |
Merge::No Cancel | Pipeline will not be cancelled by Auto Merge |
Merge::Ignore | Ignored by Auto Merge — no rebase, merge, or pipeline management |
Approved MRs waiting to be merged receive queue position labels showing their place in the merge queue:
| Label | Meaning |
|---|---|
Merge::#1 | Next MR to be merged (bright green) |
Merge::#2 | Second in queue |
Merge::#3 | Third in queue |
| ... | Higher positions have muted colors |
Queue labels are automatically updated as MRs move through the queue. When an MR is merged, positions shift automatically.
Auto Merge cancels duplicate pipelines on a strict positive allowlist:
Pipeline source | Cancelled by Auto Merge? |
|---|---|
merge_request_event | yes — the only source Auto Merge ever replaces |
api | no |
trigger | no |
schedule | no |
web | no |
push | no |
| any other source | no |
Auto Merge starts its own MR pipeline as merge_request_event. It only ever
competes with other merge_request_event pipelines on the same MR. API-triggered
verify pipelines, scheduled jobs, manual web triggers, and external triggers all
have their own purpose and are never cancelled — even if they share a SHA with an
MR pipeline.
The allowlist is positive on purpose: any new GitLab pipeline source defaults to "do not cancel", which is the safe default for a destructive operation.
Draft merge requests receive special handling to save CI resources:
When you mark an MR as draft, its pipeline is cancelled. When you mark it ready, the next pipeline will run normally and the MR will be processed.
The service automatically retries failed jobs when specific transient errors are detected in the job trace:
| Error Pattern | Cause |
|---|---|
OOMErrorException: Not enough memory to run compilation | Kotlin compiler OOM |
Insufficient permissions to pull from the repository of project | Temporary auth issue |
Process 'Resolving NPM dependencies using yarn' returns 1 | Network/registry issue |
Jobs are only retried automatically when these specific error messages are found in the job log. Other failures require manual intervention.
To prioritize an important merge request:
Merge::Important to the MRThis is useful for hotfixes or time-sensitive changes that need to be merged quickly.
Current Status: Conflict detection labels MRs that have merge conflicts, but automatic conflict resolution is not yet functional (returns 500 server error from GitLab API).
MRs with conflicts will:
Merge::Conflict label| Endpoint | Method | Description |
|---|---|---|
/api/auto-merge/configuration | GET | Service configuration |
/api/auto-merge/merge-requests | GET | List categorized merge requests |
/api/auto-merge/merge-requests/ascii | GET | MRs as plain text |
/api/auto-merge/pipelines | GET | Pipeline status overview |
/api/auto-merge/pipelines/status | GET | Aggregated pipeline status |
/api/auto-merge/pipelines/by-branch/main | GET | Main branch pipelines |
/api/auto-merge/pipelines/scheduled | GET | Scheduled pipeline list |
/api/auto-merge/runs | GET | Auto-merge run history |
/api/auto-merge/runs/latest | GET | Most recent run details |
/api/auto-merge/actions | GET | Actions timeline |
/api/auto-merge/runners | GET | Runner and job status |
/api/auto-merge/log | GET | Execution log messages |
/api/auto-merge/log/actions | GET | Executed actions log |
/api/auto-merge/events/history | GET | Received GitLab events |
/api/auto-merge/events/from-gitlab | POST | GitLab webhook endpoint |
Proprietary - Neckar IT GmbH
Format: Keep a Changelog 1.1.0.
--merge-request-badge-enabled /
--no-merge-request-badge-enabled (env MERGE_REQUEST_BADGE_ENABLED) controls
whether the SVG status badge image is embedded in MR descriptions. Default
stays enabled; disable in setups where the auto-merge host is not reachable
from the user's browser, otherwise the embedded image renders as broken in
GitLab (!14221)Waiting for CI (Last Failed)
shown when the previous pipeline failed, signalling that a re-run may fail again
(!12648)auto-merge-gitlab-integration/) injects an Auto-Merge status badge directly into
GitLab MR pages with queue position, color-coded status and auto-refresh
(!12416)Low Priority label processes labelled MRs only when
no regular MRs are in the queue and deprioritizes their pipelines under resource
scarcity (!12389)gitlab-auto-merge-service declares its HTTP
port in the Jib container image so OTel's docker_observer finds and scrapes it without
manual port configuration (!14127)useQueryRunDetail hook distinguishes good /
bad / unknown response shapes so the run-detail UI can render each state explicitly
(!13999)🔀 prefix: Auto-Merge labels migrated to proper GitLab
scoped labels (🔀 Status::… and 🔀 Important) with the merge-symbol prefix. Existing
emoji-suffixed and Merge::-prefixed labels are migrated automatically on the next run
(!13166,
!13161)Changelog truncated to fit Docker Hub's 25000-byte description limit. See the full CHANGELOG in the repository.
Content type
Image
Digest
sha256:d5f01a46e…
Size
332.6 MB
Last updated
10 days ago
docker pull neckarit/gitlab-auto-merge