gitlab-branch-triage automates branch cleanup on GitLab using YAML-driven policies. Notify stale branch authors, auto-delete merged branches, detect inactive authors, and automatically close notification issues when branches are removed — all from a single configuration file.
Features
- Policy-driven — define triage rules in a simple YAML file
- Branch triage — detect stale, merged, or abandoned branches and act on them
- Automatic issue lifecycle — notification issues are closed automatically when the branch is deleted
- Inactive author detection — automatically handles branches from blocked/deleted users
- Group-wide — triage all projects in a GitLab group (subgroups included recursively)
- Dry-run by default — safe to test before executing real actions
- GitLab CI ready — ship as a scheduled pipeline job
Installation
gem install gitlab-branch-triageOr add to your Gemfile:
gem "gitlab-branch-triage"Quick Start
1. Generate an example policy file:
gitlab-branch-triage --initThis creates .branch-triage-policies.yml with sensible defaults.
2. Run a dry-run against a project:
export GITLAB_TOKEN="glpat-xxxxx" # needs api scope
# Single project
gitlab-branch-triage --source-id my-group/my-project
# Entire group (all subgroups included)
gitlab-branch-triage --source groups --source-id my-group3. Execute real actions:
gitlab-branch-triage --source-id my-group/my-project --no-dry-runConfiguration
Policies are defined in .branch-triage-policies.yml.
Branch Rules
resource_rules:
branches:
rules:
- name: Notify stale branches (60+ days)
conditions:
inactive_days: 60
merged: false
protected: false
has_open_mr: false
forbidden_name:
matches: "^(main|master|develop)$"
limits:
most_recent: 50
actions:
notify:
title: "Stale branch: `{{name}}` in {{project_path}}"
body: |
@{{author_username}}, branch `{{name}}` has been inactive
for **{{days_inactive}} days**. It will be deleted on **{{delete_date}}**.
labels:
- branch-cleanup
- name: Delete abandoned branches (90+ days)
conditions:
inactive_days: 90
merged: false
protected: false
actions:
delete: trueBranch Conditions
| Condition | Example | Description |
|---|---|---|
inactive_days |
60 |
Days since last commit |
merged |
true / false
|
Branch merge status |
protected |
true / false
|
Branch protection status |
has_open_mr |
true / false
|
Has an open merge request |
name |
{matches: "^feature/.*"} |
Branch name pattern (matches, contains, starts_with, ends_with) |
forbidden_name |
{matches: "^main$"} |
Exclude branches by name |
author |
{email_domain: "company.com"} |
Filter by author (email_domain, name_matches, username) |
forbidden_author |
{email_domain: "bot.com"} |
Exclude by author |
date |
see below | Flexible date matching |
Date condition:
date:
attribute: committed_date
condition: older_than # or more_recent_than
interval_type: days # days | weeks | months | years
interval: 60Branch Actions
| Action | Config | Description |
|---|---|---|
notify |
{title, body, labels} |
Create an issue to notify the author. Closed automatically when the branch is deleted. |
delete |
true |
Delete the branch and close the associated notification issue. |
print |
"template string" |
Log a message |
comment |
{issue_iid, body} |
Comment on an existing issue |
Template Variables
{{name}}, {{author_name}}, {{author_email}}, {{author_username}}, {{committed_date}}, {{days_inactive}}, {{delete_date}}, {{commit_title}}, {{short_sha}}, {{project_path}}, {{today}}
Issue Lifecycle
gitlab-branch-triage manages the full lifecycle of notification issues automatically.
When notify runs, an issue is created and assigned to the branch author with a deletion deadline ({{delete_date}}). The issue has the label branch-cleanup.
When the branch is deleted by a delete rule, the tool searches for any open branch-cleanup issue whose title contains the branch name and closes it automatically.
When the author deletes the branch themselves (before the scheduled date), the next triage run detects that the branch no longer exists and closes the orphaned issue automatically.
This means issues are never left open after the branch is gone, regardless of who or what deleted it.
Inactive Author Detection
When the notify action detects that a branch author is inactive (blocked, deactivated, or deleted from GitLab), it automatically deletes the branch and creates a cleanup issue assigned to a project maintainer. This prevents stale notifications to users who can no longer act on them.
CLI Options
Usage: gitlab-branch-triage [options]
Connection:
-t, --token TOKEN GitLab API token (or GITLAB_TOKEN env var)
-H, --host-url URL GitLab host (default: https://gitlab.com)
Source:
-s, --source TYPE 'projects' (default) or 'groups'
-i, --source-id ID Project or group path/ID
Group filters:
--[no-]exclude-archived Exclude archived projects (default: true)
--[no-]exclude-forks Exclude forked projects (default: true)
Policies:
-f, --policies-file FILE YAML file (default: .branch-triage-policies.yml)
Behaviour:
-n, --dry-run Don't perform real actions (default: on)
--no-dry-run Execute real actions
-d, --debug Print extra debug information
Helpers:
--init Create example policy file
--init-ci Print example .gitlab-ci.yml snippet
-v, --version Print version
-h, --help Print help
GitLab CI Integration
Run as a scheduled pipeline job:
branch-triage:
stage: triage
image: ruby:3.2-slim
before_script:
- gem install gitlab-branch-triage --no-document
script:
- gitlab-branch-triage --token $GITLAB_TOKEN --source-id $CI_PROJECT_PATH --no-dry-run
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "web"
when: manual
allow_failure: trueGenerate the snippet with gitlab-branch-triage --init-ci.
Contributing
Bug reports and pull requests are welcome on GitHub.
- Fork it
- Create your feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -am 'feat: add my feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request
License
Released under the MIT License. Copyright (c) 2026 SolucTeam.