Redmine Ticket zusammenführen
Redmine Issue Merge
Führt ein Duplikat-Ticket in ein bestehendes Ticket über. Dies ist 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.
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
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 die Workflow-Pflichtfelder. Erzwingt der Workflow beim Schließen Felder, kann der Merge daran scheitern. In diesem Fall 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.