Redmine Ticket zusammenführen
Redmine Issue Merge
Führt ein Duplikat-Ticket in ein bestehendes Ticket über – gedacht für den Dispatch-Workflow, wenn eine Mail ohne [#Ticketnummer] im Betreff ein zweites Ticket zum selben Thema erzeugt hat.
Das Stück Software kann kostenlos verwendet werden. Dafür bekommst Du etwas Cooles und vielleicht auch ein paar Bugs. Aber ohne Gewähr - denn denk dran: No Backup, no mercy.
Wenn es dir hilft, dann kannst Du mich vielleicht unterstützen und mir einen Kaffee spendieren!
Was es tut
Beim Überführen von Quellticket → Zielticket:
- Ein Journal-Eintrag im Zielticket mit Beschreibung + (optional) allen
Notizen des Duplikats. Die erste Zeile ist eine frei editierbare Kopfzeile
(Default aus den Einstellungen, z. B.
Eintrag/Merge aus Duplikat #123). Der Eintrag wird in einem konfigurierbaren CSS-Kasten dargestellt. - Anhänge werden vom Duplikat ins Zielticket umgehängt (nur der Datenbank-Fremdschlüssel wandert, die Dateien bleiben unberührt).
- Beziehung „Dupliziert durch" zwischen Duplikat und Zielticket.
- Das Duplikat wird geschlossen (nicht gelöscht) und erhält einen Rückverweis im Journal – so kann man jederzeit nachschauen.
Keine Schema-Migration, kein manuelles SQL, keine Änderung an Redmine-Core-Dateien. Es werden ausschließlich die normalen Models verwendet.
Installation
bundle exec rake redmine:plugins:migrate RAILS_ENV=production
Docker-Volume-Mount
Ordner redmine_issue_merge nach plugins/ mounten bzw. kopieren, dann:
docker compose exec redmine \
bundle exec rake redmine:plugins:migrate RAILS_ENV=production
docker compose restart redmine
Eine Migration existiert nicht; der Migrate-Task ist nur Konvention und schadet nicht. Entscheidend ist der Restart, damit der Plugin-Code geladen wird. Ein bundle install ist nicht nötig (keine zusätzlichen Gems).
Konfiguration
Nach dem Restart zwei Dinge einstellen:
1. Berechtigung unter Administration → Rollen und Rechte: Den Rollen, die mergen dürfen, das Recht „Tickets zusammenführen" geben. Ohne dieses Recht erscheint der Aktionslink nicht.
2. Plugin-Einstellungen unter Administration → Plugins → Konfiguration (beim Plugin „Redmine Issue Merge"):

Redmine Plugin Konfiguration (German View)
| Einstellung | Bedeutung |
|---|---|
| Vorlage Kopfzeile | Default-Text der ersten Zeile des Merge-Eintrags. Platzhalter %{source} wird durch die Nummer des Duplikats ersetzt. Beim Merge im Formular noch überschreibbar. |
| Notizen des Duplikats mit übernehmen | Wenn aktiv, werden alle Notizen (Mailverlauf) des Duplikats in den Eintrag aufgenommen. Wenn inaktiv, nur die Beschreibung. |
| Status für geschlossenes Duplikat | Status, der beim Überführen auf das Duplikat gesetzt wird (Auswahl nur aus geschlossenen Status). Tipp: eigenen geschlossenen Status „Dupliziert" anlegen. |
| border | CSS-Rahmen des Kastens, z. B. 1px solid #c9a227. |
| padding | CSS-Innenabstand, z. B. 10px 12px. |
| background-color | Hintergrundfarbe, z. B. #fff8e1. |
| color | Textfarbe, z. B. #1a1a1a. |
Benutzung
Auf der Ticketseite des Duplikats in der Aktionsleiste (.contextual, oben
und unten, jeweils vor dem „Mehr"-Menü) den Link „In anderes Ticket
überführen" öffnen. Zielticketnummer eingeben, Kopfzeile ggf. anpassen,
absenden. Das Duplikat wird geschlossen, der Inhalt landet im Zielticket.

Issue merge Dialog (German View)
Wie der CSS-Kasten funktioniert
Redmine sanitized jede Journal-Notiz beim Anzeigen; Inline-HTML mit style
würde entfernt. Das Plugin löst das per JavaScript: Ein kleines Skript wird in
den Seitenkopf injiziert (Hook view_layouts_base_html_head), findet die Notiz
an einem unsichtbaren Marker (%%MERGE%%) am Notizanfang, entfernt den Marker
und setzt die Klasse redmine-merge-box auf den Notiz-Container. Das zugehörige
CSS (border/padding/background-color/color aus den Einstellungen) kommt aus
demselben Hook. Dieser Weg ist unabhängig davon, über welchen internen
Render-Pfad Redmine die Notiz ausgibt (in 6.1 mehrfach umgebaut).
Der Aktionslink wird ebenfalls per JavaScript in alle .contextual-Leisten
eingebunden (jeweils vor span.drdn). Das Icon nutzt Redmines sprite_icon
(Inline-SVG), damit es wie die übrigen Aktionslinks aussieht.
Hinweise / Grenzen
- Ab v1.3.0 ist Bearbeitungsrecht (
edit_issues) auf beiden Projekten nötig – dem des Duplikats und dem des Zieltickets. Private Notizen des Duplikats werden bewusst nicht übernommen. - Die Mailverläufe werden 1:1 als Text übernommen (keine Datumssortierung, bewusst so gewollt). Reihenfolge = chronologisch nach Erstellung.
- Inline per Dateiname referenzierte Bilder verlinken nach dem Umhängen weiterhin korrekt, da die Anhänge nun am Zielticket hängen.
- Der Merge ist in eine Transaktion gekapselt: Schlägt ein Schritt fehl (z. B. Pflichtfeld beim Schließen), wird nichts verändert.
- Das Schließen des Duplikats respektiert eure Workflow-Pflichtfelder. Erzwingt euer Workflow beim Schließen Felder, kann der Merge daran scheitern – dann Pflichtfelder lockern oder passenden Status wählen.
- Die Kasten-Darstellung und der contextual-Link benötigen aktiviertes JavaScript. Der eigentliche Merge (Datenübernahme) läuft rein serverseitig.
Deinstallation
Plugin-Ordner entfernen und Redmine neu starten. Da keine Migration existiert,
sind keine DB-Schritte nötig. Bereits erfolgte Merges bleiben erhalten; der
unsichtbare Marker %%MERGE%% wird dann nicht mehr entfernt und erscheint als
Textzeile am Anfang der jeweiligen Notiz.
Versioning
v1.3.1 - Neuer MERGE Indikator: U+2063 INVISIBLE SEPARATOR-Zeichen.
Der vorherige Marker %%MERGE%% wurde von Textile, da % interpretiert wird.
Die neue Version funktioniert jetzt mit Textile und nicht nur CommonMark