how can I customize git's merge commit message

2020-01-27 00:34发布

问题:

Every time I do a merge I need for a merge commit to be generated and I would like it to have more than just the summary of all the commits.

My question is how can I format git-fmt-merge-msg or what determines this automated message (I can do this manually after a commit by amending it and using git-log --pretty=format:'...')

For example I would like to format it as such:

 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

回答1:

I wanted to do something just like this. I didn't find any reasonable way to get git fmt-merge-msg to work. I think it doesn't work the way I was hoping (passing in a completely custom text to use for the message). So instead I figured out another way using the -no-commit and commit -F commands. The output is of course customizable but it reflects almost exactly what you said you wanted the output to be.

Sample Commit Message Output:

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

And the usage would be:

$ git mergelogmsg branch-name

I'll copy the alias here:

[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" 

If you want to copy and paste it to customize it, use the above. The below version has line breaks which you do not want but I'll use to explain what I'm doing:

[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"

Alright...

Line 1 starts the custom function as a bash shell script so git knows it's not a git command. It sets the current branch (master if you are merging a different branch into master) to a variable so we can use it later.
Line 2 prints the first line using the current branch and the branch name you've given the original command (just as you would in a normal merge command). It writes this to a temp file.
Line 3 gets the log of the commits in the incoming branch that are not in the current branch, and writes out only the subjects of those commits to the temp file.
Line 4 prints the next line to temp.
Line 5 gets the log of the commits in the current branch that are not in the incoming branch, and writes out only the subjects of those commits to the temp file.
Line 6 prints a little horizontal separator between the summary and detail portions.
Line 7 gets the log of all the commits in the current branch and incoming branch back to the time just after they branched off from each other, or last shared an ancestor. The left-right gives an arrow that shows which branch the commit comes from. < means current branch and > means incoming branch.
Line 8 executes a merge command with the incoming branch with no fast-forward (so you get a commit) and with no commit (so you have to write one yourself... ah but you don't!)
Line 9 executes the commit command with the -e and -F parameters to allow for editing and to tell the commit to populate the message with the text in the specified file. Once you've finished the commit message as desired, it commits the merge and deletes the temp file.

Tada! The two ; at the end of that long command make it so the printf functions do not write out to the console, only to the file.



回答2:

I'm aware this isn't answering the original question, but for the benefit of git noobs like myself who reach this page because it's currently the first Google result for "git change merge commit message", I'll mention that it is possible to:

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

to change the commit message of a merge commit without losing the link to any of the parents of the merge commit.



回答3:

Looks like as of version Git 1.7.8 you can do git merge --edit ... to specify the commit message.

And as of 1.7.10, dropping into edit mode will be the default behavior

From this release on, the "git merge" command in an interactive session will start an editor when it automatically resolves the merge for the user to explain the resulting commit, just like the "git commit" command does when it wasn't given a commit message.

(though I'm not seeing it on in msysgit on windows).



回答4:

I've found there are two ways for solving this problem

note: don't use both at the same time, as if the commit fails to merge it will add the log again to the bottom.

personal note: I'm using the first solution as it relies entirely on git's hooks and config properties, instead of an external script.
For a real solution one would have to extend a git command named 'fmt-merge-msg' that generates the oneline descriptions when passing the --log option (if you really need this solution you'll have to create your own patch (for git) and compile it from source).

1. using prepare-commit-message as VonC suggested
this solution has the problem that you need to interrupt the commit and then commit manually

setting an alias that will build the desired commit message:

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

creating the prepare-commit-msg hook by creating an executable prepare-commit-msg in $GIT_DIR/hooks/ (example script below)

#!/bin/sh
#...

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

one should define an alias commit msg such as

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

2. using a custom command that will generate the merge automatically
(using the lm alias created in 1.)

#!/bin/sh

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

and then execute a rather rigid command:

./cmd-name <branch to merge>

if you still wish to have the oneline description of the commits you'll need to add new commands or whatever to the -m argument (if you use --log then it will be generated on the bottom)



回答5:

Once you merge your <branch A> to <branch B>, git will automatically commit a message saying "merge branch <branch A> into <branch B>.

If you want to customize git's merge commit message you can try:

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

This command will update your git's merge commit message to your commit message.

you can also try :

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

it will merge your <branch B> with <branch A>, with list of <Branch B>'s commit and commit messages

If it fails to do fast-forward, then you will get something like this:

Automatic merge went well; stopped before committing as requested

# check this with git status 
$ git status

It will show you, your commits are already added to stage but not yet commited so, you can commit them without running git add:

$ git commit -m "your merge commit message"

If you want to change <branch B>'s last commit message then again you can try:

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

But, generally, we don't update other commit messages, unless they are incorrect.

Suppose, you get conflict after git merge, then simply resolve your conflict and do:

$ git add .
$ git commit -m "your commit message"


回答6:

There's also a --log option for git-merge now, which does half of what you want - it places the shortlog (commit summaries) in the merge message. A full solution will have to use a hook like in VonC's answer, though.



回答7:

You could try defining a prepare-commit-msg hook (the sample one does generate some custom "default commit messages")



回答8:

A very simple bash function that set's a default message and adds your argument. It opens your editor with the --edit switch if you want make changes.

edit ~/.bashrc or bash_aliases. (Don't forget to source ~/.bashrc) to apply changes in your bashrc

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

use:

mergedevelop "PR #143..." to have message:

master <-- develop: PR #143...



回答9:

Coming late to the party, but nowadays we can just use
git merge --squash <branch>
to merge another branch into a single commit on my current branch and prepopulating our commit message with all the merged commit messages -- and the detailed messages, too, not just the one-liners.
I looked for ages for this command.



标签: git git-merge