Wie kann ich die Merge-Commit-Nachricht von git anpassen?

73

Jedes Mal, wenn ich eine Zusammenführung durchführe, muss ein Zusammenführungs-Commit generiert werden, und ich möchte, dass es mehr als nur die Zusammenfassung aller Commits enthält.

Meine Frage ist, wie ich git-fmt-merge-msg formatieren kann oder was diese automatisierte Nachricht bestimmt (ich kann dies nach einem Commit manuell tun, indem ich es ändere und git-log verwende --pretty = format: '...')

Zum Beispiel möchte ich es so formatieren:

 Merge branch 'test'  
    * test:  
      [BZ: #123] fifth commit subject  
      [BZ: #123] fourth commit subject  
      [BZ: #123] third commit subject  
      [BZ: #123] second commit subject  
      [BZ: #123] first commit subject  

 __________________________________________
 Merge details:  
     [BZ: #123] fifth commit subject  
               at 2010-06-30 11:29:00 +0100  
       - fifth commit body  

     [BZ: #123] fourth commit subject  
               at 2010-06-30 11:22:17 +0100  
       - fourth commit body  

     [BZ: #123] third commit subject  
               at 2010-06-30 11:21:43 +0100  
       - third commit body  

     [BZ: #123] second commit subject  
               at 2010-06-30 11:21:30 +0100  
       - second commit body  

     [BZ: #123] first commit subject  
               at 2010-06-30 11:29:57 +0100  
       - first commit body
shil88
quelle

Antworten:

13

Ich wollte so etwas einfach machen. Ich habe keinen vernünftigen Weg gefunden, um git fmt-merge-msgzur Arbeit zu kommen. Ich denke, es funktioniert nicht so, wie ich es mir erhofft hatte (Übergabe eines vollständig benutzerdefinierten Textes für die Nachricht). Also habe ich stattdessen mit den Befehlen -no-commitund einen anderen Weg gefunden commit -F. Die Ausgabe ist natürlich anpassbar, spiegelt aber fast genau das wider, was Sie sich gewünscht haben.

Beispiel für eine Commit-Nachrichtenausgabe:

Merge branch fix4 into master

::SUMMARY::
Branch fix4 commits:
Add fix4b-4
Add fix4b-3
Add fix4b-2
Add fix4b-1

Branch master commits:
fix4b-5 on master

* * * * * * * * * * * * * * * * * * * * * * * * *
::DETAILS::
commit < 98ffa579e14610b3566e1a3f86556a04dc95a82b
Author: -----
Date:   Fri Aug 17 17:23:26 2018 -0400

    fix4b-5 on master

commit > 7e386dddee16a7c2588954d25dd6793cdaa1b562
Author: -----
Date:   Fri Aug 17 15:18:17 2018 -0400

    Add fix4b-4

    use log output as commit message

    commit 2e630b1998312ec1093d73f9fe77b942407f45e8
    Author: -----
    Date:   Fri Aug 17 15:15:28 2018 -0400

        Add fix4b-3

commit > 2e630b1998312ec1093d73f9fe77b942407f45e8
Author: -----
Date:   Fri Aug 17 15:15:28 2018 -0400

    Add fix4b-3

commit > c9bb199be49c17ca739d019d749263314f05fc46
Author: -----
Date:   Fri Aug 17 15:15:27 2018 -0400

    Add fix4b-2

commit > 5b622a935c9d078c7d0ef9e195bccf1f98cce5e4
Author: -----
Date:   Fri Aug 17 15:15:27 2018 -0400

    Add fix4b-1

Und die Verwendung wäre:

$ git mergelogmsg branch-name

Ich werde den Alias ​​hier kopieren:

[alias]
    mergelogmsg = "!f() { var=$(git symbolic-ref --short HEAD) && printf 'Merge branch %s into %s\n\n::SUMMARY::\nBranch %s commits:\n' $1 $var $1 > temp_merge_msg && git log --format=format:'%s' $var..$1 >> temp_merge_msg && printf '\n\nBranch %s commits:\n' $var >> temp_merge_msg && git log --format=format:'%s' $1..$var >> temp_merge_msg && printf '\n\n* * * * * * * * * * * * * * * * * * * * * * * * *\n::DETAILS::\n' >> temp_merge_msg && git log --left-right $var...$1 >> temp_merge_msg && git merge --no-ff --no-commit $1 && git commit -eF temp_merge_msg; rm -f temp_merge_msg;}; f" 

Wenn Sie es kopieren und einfügen möchten, um es anzupassen, verwenden Sie die oben genannten Schritte. Die folgende Version enthält Zeilenumbrüche, die Sie nicht möchten, aber ich werde verwenden, um zu erklären, was ich tue:

[alias]
1   mergelogmsg = "!f() { var=$(git symbolic-ref --short HEAD) && 
2        printf 'Merge branch %s into %s\n\n::SUMMARY::\nBranch %s commits:\n' $1 $var $1 > temp_merge_msg && 
3        git log --format=format:'%s' $var..$1 >> temp_merge_msg && 
4        printf '\n\nBranch %s commits:\n' $var >> temp_merge_msg && 
5        git log --format=format:'%s' $1..$var >> temp_merge_msg && 
6        printf '\n\n* * * * * * * * * * * * * * * * * * * * * * * * *\n::DETAILS::\n' >> temp_merge_msg && 
7        git log --left-right $var...$1 >> temp_merge_msg && 
8        git merge --no-ff --no-commit $1 && 
9        git commit -eF temp_merge_msg; rm -f temp_merge_msg;}; f"

In Ordung...

Zeile 1 startet die benutzerdefinierte Funktion als Bash-Shell-Skript, damit git weiß, dass es sich nicht um einen git-Befehl handelt. Es setzt den aktuellen Zweig (Master, wenn Sie einen anderen Zweig in Master zusammenführen) auf eine Variable, damit wir ihn später verwenden können.
Zeile 2 druckt die erste Zeile unter Verwendung des aktuellen Zweigs und des Zweignamens, den Sie dem ursprünglichen Befehl gegeben haben (genau wie bei einem normalen Zusammenführungsbefehl). Es schreibt dies in eine temporäre Datei.
Zeile 3 ruft das Protokoll der Commits in der eingehenden Verzweigung ab, die sich nicht in der aktuellen Verzweigung befinden, und schreibt nur die Betreffs dieser Festschreibungen in die temporäre Datei.
Zeile 4 druckt die nächste Zeile nach Temp.
Zeile 5Ruft das Protokoll der Commits im aktuellen Zweig ab, die sich nicht im eingehenden Zweig befinden, und schreibt nur die Betreffs dieser Commits in die temporäre Datei.
Zeile 6 druckt ein kleines horizontales Trennzeichen zwischen dem Zusammenfassungs- und dem Detailteil.
Zeile 7 ruft das Protokoll aller Commits in der aktuellen Verzweigung und der eingehenden Verzweigung auf die Zeit zurück, kurz nachdem sie voneinander abgezweigt oder zuletzt einen Vorfahren geteilt haben. Links-rechts gibt einen Pfeil an, der anzeigt, aus welchem ​​Zweig das Commit stammt. <bedeutet aktuelle Verzweigung und> bedeutet eingehende Verzweigung.
Zeile 8 führt einen Zusammenführungsbefehl mit dem eingehenden Zweig ohne Schnellvorlauf (damit Sie ein Commit erhalten) und ohne Commit (Sie müssen also selbst einen schreiben ... ah, aber Sie tun es nicht!) Aus.
Zeile 9 Führt den Commit-Befehl mit aus das -eund-FParameter, die das Bearbeiten ermöglichen und dem Commit mitteilen, dass die Nachricht mit dem Text in der angegebenen Datei gefüllt werden soll. Sobald Sie die Festschreibungsnachricht wie gewünscht beendet haben, wird die Zusammenführung festgeschrieben und die temporäre Datei gelöscht.

Tada! Die beiden ;am Ende dieses langen Befehls sorgen dafür, dass die printf-Funktionen nicht in die Konsole, sondern nur in die Datei geschrieben werden.

GaetaWoo
quelle
1
Das ist fantastisch!! Es passt perfekt zur Frage und kann einfach angepasst werden. Vielen Dank!
Shil88
In der Tat habe ich es schon ein bisschen mehr angepasst. Ich habe es nur für ein bestimmtes Projekt gemacht, aber ich könnte es für alle Zusammenführungen verwenden.
GaetaWoo
52

Ich bin mir bewusst, dass dies nicht die ursprüngliche Frage beantwortet, aber zum Nutzen von Git-Noobs wie mir, die diese Seite erreichen, weil es derzeit das erste Google-Ergebnis für "Git Change Merge Commit-Nachricht" ist, werde ich erwähnen, dass dies möglich ist zu:

git commit --amend -m"New commit message"

um die Commit-Nachricht eines Merge-Commits zu ändern, ohne die Verbindung zu einem der übergeordneten Elemente des Merge-Commits zu verlieren.

laszlok
quelle
1
Das git log --graphZeichnen von Verzweigungsgraphen wurde gestoppt.
Ciastek
4
Wenn Sie nur das Standard-Merge-Commit von "zusammengeführter Zweig ... in Master" ändern möchten, versuchen Sie es mitgit merge --no-edit -m "your-custom-commit-message"
Elad
4
-1: Dies beantwortet die Frage nicht. Unabhängig davon, welche Fragen Google hier leitet, sollte dies nicht die beste Antwort sein. Es sollte möglicherweise überhaupt keine Antwort auf diese Frage sein.
Jasper
1
@Jasper Technisch korrekt, aber es ist kaum meine Schuld als Antwortender, dass der Titel die Frage im Text nicht genau erfasst. Es ist auch kaum meine Schuld, dass die Leute dies anscheinend hilfreich genug finden, um an die Spitze zu gelangen. Nachdem ich SO schon eine Weile verwendet habe (und einen ausreichenden Ruf dafür habe, nicht zuletzt aufgrund dieser speziellen Antwort), würde ich heutzutage wahrscheinlich stattdessen die Frage bearbeiten, um sowohl den Titel zu klären als auch einen Link zu einem verwandten Q & A hinzuzufügen .
Laszlok
Meiner Meinung nach ist es die Schuld des Antwortenden, nicht zu versuchen, die Frage zu beantworten, sondern eine Frage zu beantworten, die nie gestellt wurde. (Es wäre nicht so schlimm gewesen, wenn diese Frage nicht selbst beantwortet worden wäre, aber das ändert nichts.) Vielleicht wäre ein Kommentar mit einem Link zu der Frage, die ähnlich, aber anders ist, eine bessere Idee.
Jasper
22

Ab Version Git 1.7.8 können Sie git merge --edit ... die Commit-Nachricht angeben.

Und ab 1.7.10 , wird fallen in den Bearbeitungsmodus das Standardverhalten sein

Ab dieser Version startet der Befehl "git merge" in einer interaktiven Sitzung einen Editor, wenn er automatisch die Zusammenführung auflöst, damit der Benutzer das resultierende Commit erklärt, genau wie der Befehl "git commit", wenn ihm kein Befehl erteilt wurde Nachricht festschreiben.

(obwohl ich es in msysgit unter Windows nicht sehe) .

R0MANARMIE
quelle
16

Ich habe festgestellt, dass es zwei Möglichkeiten gibt, dieses Problem zu lösen

Hinweis : Verwenden Sie nicht beide gleichzeitig. Wenn das Commit nicht zusammengeführt werden kann, wird das Protokoll erneut unten hinzugefügt.

Persönlicher Hinweis : Ich verwende die erste Lösung, da sie sich anstelle eines externen Skripts ausschließlich auf die Hooks und Konfigurationseigenschaften von git stützt.
Für eine echte Lösung müsste man einen git-Befehl mit dem Namen 'fmt-merge-msg' erweitern, der die Online-Beschreibungen generiert, wenn die Option --log übergeben wird (wenn Sie diese Lösung wirklich benötigen, müssen Sie Ihren eigenen Patch erstellen (z git) und kompiliere es aus der Quelle).

1. Verwenden von prepare-commit-message, wie VonC vorgeschlagen hat.
Diese Lösung hat das Problem, dass Sie das Commit unterbrechen und dann manuell festschreiben müssen

Festlegen eines Alias, der die gewünschte Festschreibungsnachricht erstellt:

[alias]  
lm = log --pretty=format:'%s%n   by %C(yellow)%an%Creset (%ad)%n %n%b' --date=local

Erstellen des Prepare-Commit-Msg-Hooks durch Erstellen einer ausführbaren Prepare-Commit-Nachricht in $ GIT_DIR / hooks / (Beispielskript unten)

#!/bin/sh
#...

case "$2,$3" in  
  merge,)  
  echo "Merge details:" >> $1  
  echo "" >> $1  
  git lm ORIG_HEAD..MERGE_HEAD >> "$1" ;;  
*) ;;  
esac  

man sollte eine Alias-Commit-Nachricht wie definieren

[alias]  
m = merge --no-ff --no-commit

2. Verwenden Sie einen benutzerdefinierten Befehl, der die Zusammenführung automatisch generiert
(unter Verwendung des in 1. erstellten lm-Alias).

#!/bin/sh

echo ""
echo "merge with commit details -- HEAD..$1"
git merge --no-ff --no-log -m "`git lm HEAD..$1`" --no-commit $1

und dann einen ziemlich starren Befehl ausführen:

./cmd-name <branch to merge>

Wenn Sie weiterhin die Online-Beschreibung der Commits wünschen, müssen Sie dem Argument -m neue Befehle oder was auch immer hinzufügen (wenn Sie --log verwenden, wird es unten generiert).

shil88
quelle
OK, großartig. Aber ehrlich gesagt - das ist weitaus schwieriger als es sein sollte.
Ed Randall
Eine viel bessere Antwort wurde gepostet! Überprüfen Sie die akzeptierte
shil88
11

Sobald Sie Ihr <branch A>to zusammenführen <branch B>, schreibt git automatisch eine Nachricht mit der Aufschrift "Zweig zusammenführen <branch A>in " zusammen<branch B> .

Wenn Sie die Merge-Commit-Nachricht von git anpassen möchten, können Sie Folgendes versuchen:

$ git commit --amend -m "Your merge message"

Dieser Befehl aktualisiert die Merge-Commit-Nachricht Ihres Git auf Ihre Commit-Nachricht.

Sie können auch versuchen:

$ git merge <branch A> --no-commit

es wird Ihr verschmelzen <branch B>mit <branch A>, mit der Liste <Branch B>'sbegehen und Commit - Nachrichten

Wenn der schnelle Vorlauf nicht möglich ist, erhalten Sie Folgendes:

Automatic merge went well; stopped before committing as requested

# check this with git status 
$ git status

Es zeigt Ihnen, dass Ihre Commits bereits zur Bühne hinzugefügt, aber noch nicht festgeschrieben wurden. Sie können sie also festschreiben, ohne sie auszuführen git add:

$ git commit -m "your merge commit message"

Wenn Sie die <branch B>letzte Festschreibungsnachricht ändern möchten, können Sie erneut versuchen:

$ git commit --amend -m "your new commit message"

Im Allgemeinen aktualisieren wir jedoch keine anderen Festschreibungsnachrichten, es sei denn, sie sind falsch.

Angenommen, Sie erhalten einen Konflikt nach dem Zusammenführen von Git, lösen dann einfach Ihren Konflikt und führen Folgendes aus:

$ git add .
$ git commit -m "your commit message"
przbadu
quelle
1
Warum sollten Sie --amendin der letzten Zeile Ihrer Antwort ein Commit durchführen, das noch nicht stattgefunden hat? Sollte es nicht einfach so sein git commit -m "your commit message"?
Darthbith
1
Mein schlechtes, danke für den Hinweis. Es sollte git commit -m "Ihre Festschreibungsnachricht" sein, da keine Festschreibungen für die Zusammenführung durchgeführt werden.
Przbadu
"da keine Commits für das Zusammenführen gemacht werden", wenn Sie das --no-commitFlag angeben , wie Sie es getan haben :-)
Darthbith
Hier führt git merge b --no-commit Zweig b zu Zweig a zusammen, mit allen Commits von Zweig b (was offensichtlich ist) und mit den Festschreibungsnachrichten von Zweig b. Es werden keine zusätzlichen
Festschreibungsnachrichten hinzugefügt
Wenn Ihre Zusammenführung nicht schnell vorspult, wird die Meldung "Die automatische Zusammenführung ist gut gelaufen; vor dem Festschreiben wie gewünscht gestoppt" angezeigt. Jetzt müssen Sie nicht mehr laufen git add ., aber direkt können Sie die Zusammenführung mitgit commit -m "your commit message"
przbadu
6

Es gibt auch eine --logOption für git-mergeden Moment, die die Hälfte von dem macht, was Sie wollen - sie platziert das Shortlog (Commit-Zusammenfassungen) in der Zusammenführungsnachricht. Eine vollständige Lösung muss jedoch einen Haken wie in VonCs Antwort verwenden.

Cascabel
quelle
Nun, ich habe diese Option bereits global festgelegt. Hooks reichen nicht aus, da sie während des Zusammenführens nicht aktiviert werden (es sei denn, Sie stoppen sie mit --no-commit)
shil88
1
"Hooks reichen nicht aus, da sie während des Zusammenführens nicht aktiviert werden (es sei denn, Sie stoppen sie mit --no-commit)"; Das ist eine gute Frage an sich: Warum wird während des Commit-Teils einer Zusammenführung kein Hook aktiviert?
VonC
@VonC: Ich denke, das ist eigentlich absichtlich - von einem kurzen Blick auf die Quelle aus führen Sie Anrufe zusammen commit_tree direkt zusammen.
Cascabel
Die Option -m ist nützlich bei --log. Verwenden Sie für Noobs wie mich auch nicht die Option --oneline, wenn Sie das resultierende Protokoll des Zweigs untersuchen, in den Sie zusammengeführt haben (mithilfe von --log). Andernfalls wird nur die Merge-Commit-Nachricht und nicht die einzelnen Commit-Nachrichten angezeigt des zusammengeführten Zweigs.
Jon
4

Sie können versuchen, eine Prepare-Commit-Nachricht zu definieren Hook zu definieren (im Beispiel werden einige benutzerdefinierte "Standard-Commit-Nachrichten" generiert).

VonC
quelle
1
Funktioniert bis zu einem gewissen Punkt hervorragend, ich muss mit --no-commit zusammenführen und erst dann festschreiben, sonst scheint der Hook prep-commit-msg nicht zu laufen (merge_msg ist Standard). Ich möchte, dass die Zusammenführung vollständig ist Details werden automatisch hinzugefügt, da dies die Commits sind, die ich an CVS
sende
@ shil88: hast du versucht zu sehen, ob der commit-msghook während eines aktiviert wurde git merge?
VonC
@ shil88: Ich habe gerade festgestellt, dass ich Ihre erste Frage bereits beantwortet habe ( stackoverflow.com/questions/2817897/… ): Haben Sie es endlich geschafft, einen Hook zu implementieren, um Git und CVS Repo synchron zu halten?
VonC
1
@VonC Entschuldigung, ich hatte nicht genug Ruf, um Antworten zu kommentieren, aber ich habe einen CVSNT-Postcommand-Hook implementiert, der nach einer kleinen Verzögerung das 'Haupt'-Git-Repo zwingt, einen cvsimport durchzuführen es ist voll verwendbar (automatisches
Festschreiben
1
@VonC Commit-Msg Hook wird nicht aktiviert
Shil88
1

Eine sehr einfache Bash-Funktion, die eine Standardnachricht festlegt und Ihr Argument hinzufügt. Es öffnet Ihren Editor mit dem --editSchalter, wenn Sie Änderungen vornehmen möchten.

edit ~ / .bashrc oder bash_aliases. (Vergessen Sie nicht source ~/.bashrc), um Änderungen in Ihrem Bashrc anzuwenden

function mergedevelop()
{
    git merge --no-ff --edit -m "master <-- develop: $1" develop;
}

verwenden:

mergedevelop "PR #143..." Nachricht haben:

Master <- Entwickeln: PR # 143 ...

nilsM
quelle
1

Wir kommen zu spät zur Party, aber heutzutage können wir einfach
git merge --squash <branch>
einen anderen Zweig zu einem einzigen Commit in meinem aktuellen Zweig zusammenführen und unsere Commit-Nachricht mit allen zusammengeführten Commit-Nachrichten vorab füllen - und auch mit den detaillierten Nachrichten, nicht nur mit den Einzeilern .
Ich habe lange nach diesem Befehl gesucht.

Christian Severin
quelle
0

Neben dem git merge --squashin der genannten Christian Severin ‚s Antwort , haben Sie jetzt die Configmerge.suppressDest als neue Art und Weise einen (kleinen Teil der) verpflichten Nachricht anpassen.

Mit Git 2.29 (Q4 2020) hat " git merge" ( man ) gelernt, " into <branch>" am Ende des Titels der Standard-Merge-Nachricht mit der merge.suppressDestKonfiguration selektiv wegzulassen .

Siehe Commit 6e6029a (29. Juli 2020) und Commit 2153192 (30. Juli 2020) von Junio ​​C Hamano ( gitster) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 341a196 , 01. August 2020)

fmt-merge-msg: Zusammenführungsziel wieder weglassen lassen

Unterstützt von: Linus Torvalds
Unterstützt von: Jeff King

In Git 2.28 haben wir masterbei der Erstellung der Standard-Zusammenführungsnachricht das spezielle Gehäuse ' ' gestoppt , indem wir einfach den Code entfernt haben, um " into 'master'" am Ende der Nachricht zu unterdrücken .

merge.suppressDestFühren Sie eine mehrwertige Konfigurationsvariable ein, die eine Reihe von Globs angibt, die mit dem Namen des Zweigs übereinstimmen, in den die Zusammenführung durchgeführt wird, damit Benutzer angeben können, für welchen Zweig die Ausgabe von fmt-merge-msg gekürzt werden soll.
Wenn es nicht eingestellt ist, 'master wird standardmäßig ' als einziger Wert der Variablen verwendet.

Durch die obige Verschiebung wird die Standardeinstellung vor 2.28 in Repositorys ohne relevante Konfiguration größtenteils zurückgesetzt.

git configenthält jetzt in seiner Manpage :

merge.suppressDest

Wenn Sie dieser mehrwertigen Konfigurationsvariablen einen Glob hinzufügen, der den Namen der Integrationszweige entspricht, wird die für Zusammenführungen in diese Integrationszweige berechnete Standard-Zusammenführungsnachricht weggelassen. " into <branch name> Titel " weggelassen.

Ein Element mit einem leeren Wert kann verwendet werden, um die Liste der aus früheren Konfigurationseinträgen gesammelten Globs zu löschen. Wenn keine merge.suppressDestVariable definiert ist, wird der Standardwert von masteraus Gründen der Abwärtskompatibilität verwendet.

Und:

Revert "fmt-merge-msg: aufhören masterspeziell zu behandeln "

Dadurch wird das Commit 489947cee5095b168cbac111ff7bd1eadbbd90dd zurückgesetzt , wodurch die Zusammenführung in den masterZweig ' ' beim Vorbereiten der Standard-Zusammenführungsnachricht nicht mehr als speziell behandelt wurde .
Da das Ziel darin bestand, keinen einzelnen Zweig als speziell zu kennzeichnen, wurde es gelöst, indem das " into <branchname>" am Ende des Titels der Standardzusammenführungsnachricht für alle Zweige belassen wurde.
Eine naheliegende und einfache Alternative, um alle gleich zu behandeln, könnte darin bestehen, sie für jeden Zweig zu entfernen, was jedoch zu einem Informationsverlust führt.

Wir werden einen neuen Mechanismus einführen, mit dem Endbenutzer Zusammenführungen angeben können, bei denen Zweige das " into <branchname>" im Titel der Standardzusammenführungsnachricht weglassen würden , und den Mechanismus, wenn er nicht konfiguriert ist, dazu bringen, das traditionelle " master" erneut zu behandeln, also alle Änderungen an den zuvor vorgenommenen Tests werden unnötig, da diese Tests ausgeführt werden, ohne den neuen Mechanismus zu konfigurieren.

VonC
quelle