Search code examples
gitgit-merge

how can I customize git's merge commit message?


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

Solution

  • 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.