0

The messages template from commit.template is for new commits only. Because of that it isn't used when I do git merge --squash mybranch && git commit -a.

Is there something like merge.template or another solution where I can modify the default message that is presented to me in the editor when doing a merge?

What I see in a usual commit

This opens up in the editor of my choice when doing git commit -a:

This is my commit message template set via "git config commit.template".

# Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen,
# die mit '#' beginnen, werden ignoriert, und eine leere Beschreibung
# bricht den Commit ab.
#
# Auf Branch main
# Ihr Branch ist auf demselben Stand wie 'origin/main'.
#
# Zum Commit vorgemerkte Änderungen:
#       geändert:       README.md
#
# Unversionierte Dateien:
#       my-commit-msg-tempalte

What I see after git merge --squash

This comes up in the editor of my choice when doing git merge --squash myfix && git commit -a. The template message is not there!

Squashed commit of the following:

commit 9474d601e6b3ed33efc432f623c08e7931095ba0
Author: buhtz <c.buhtz@posteo.jp>
Date:   Mon Mar 13 09:22:33 2023 +0100

    commit three

commit 2f6524da10a6c3fba8963761abcd3b5ba3d19f12
Author: buhtz <c.buhtz@posteo.jp>
Date:   Mon Mar 13 09:22:25 2023 +0100

    commit two

commit 5520ea8e2e75a29e06322a742a4b40dbbb74b3ee
Author: buhtz <c.buhtz@posteo.jp>
Date:   Mon Mar 13 09:22:17 2023 +0100

    commit one

# Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen,
# die mit '#' beginnen, werden ignoriert, und eine leere Beschreibung
# bricht den Commit ab.
#
# Auf Branch main
# Ihr Branch ist 1 Commit vor 'origin/main'.
#   (benutzen Sie "git push", um lokale Commits zu publizieren)
#
# Zum Commit vorgemerkte Änderungen:
#       geändert:       README.md
#       geändert:       spiel.py
#
# Unversionierte Dateien:
#       my-commit-msg-tempalte

What I would like to have

After doing git merge --squash myfix && git commit -a I would like my editor comes up with something like this where the template is present. The squash commit message is a nice to have but not mandatory for me.

This is my commit message template set via "git config commit.template".

Squashed commit of the following:

commit 9474d601e6b3ed33efc432f623c08e7931095ba0
Author: buhtz <c.buhtz@posteo.jp>
Date:   Mon Mar 13 09:22:33 2023 +0100

    commit three

commit 2f6524da10a6c3fba8963761abcd3b5ba3d19f12
Author: buhtz <c.buhtz@posteo.jp>
Date:   Mon Mar 13 09:22:25 2023 +0100

    commit two

commit 5520ea8e2e75a29e06322a742a4b40dbbb74b3ee
Author: buhtz <c.buhtz@posteo.jp>
Date:   Mon Mar 13 09:22:17 2023 +0100

    commit one

# Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen,
# die mit '#' beginnen, werden ignoriert, und eine leere Beschreibung
# bricht den Commit ab.
#
# Auf Branch main
# Ihr Branch ist 1 Commit vor 'origin/main'.
#   (benutzen Sie "git push", um lokale Commits zu publizieren)
#
# Zum Commit vorgemerkte Änderungen:
#       geändert:       README.md
#       geändert:       spiel.py
#
# Unversionierte Dateien:
#       my-commit-msg-tempalte
buhtz
  • 10,774
  • 18
  • 76
  • 149
  • That's surprising. This _is_ a "new commit" so what distinction is Git drawing here? Does the `-t` option work to point to the template file? – matt Aug 14 '22 at 13:32
  • 2
    @matt: the `git merge --squash` generated a prototype message already; any `git commit` that has a prototype uses that, rather than starting from a template. The OP can remove the generated prototype message, which will force `git commit` to generate one. (But it's probably better to just massage the generated one.) – torek Aug 14 '22 at 22:13
  • 1
    @torek Ah, it's that prototype / template distinction! – matt Aug 14 '22 at 22:30
  • I still have that problem and don't have a solution. – buhtz Mar 12 '23 at 15:23

4 Answers4

3

While some Git repository remote hosting service, like GitLab, might provide proper merge message template, you would need a local hook to modify the merge message.

For instance, a prepare_commit_msg local hook (Git 2.24+, Q4 2019)

It takes one to three parameters.

  • The first is the name of the file that contains the commit log message.
  • The second is the source of the commit message, and can be:
    • message (if a -m or -F option was given);
    • template (if a -t option was given or the configuration option commit.template is set);
    • or:
      • merge (if the commit is a merge or a .git/MERGE_MSG file exists);
      • squash (if a .git/SQUASH_MSG file exists); or
      • commit, followed by a commit object name (if a -c, -C or --amend option was given).

In that hook , you can then (when the second parameter is merge or squash, write a script which combines merge.template with your current squash message.

  • The content of the template is in the file referenced by git config commit.template.
  • The file to update in order to modify the commit message is either .git/MERGE_MSG or .git/SQUASH_MSG (in your case: the latter).

But modifying .git/SQUASH_MSG and exiting 0, the merge squashed commit created by your git merge --squash will integrate the commit template.


To make this clear. I don't want to modify the commit or the commit message. I want to have my editor open up with the commit message template after I've done merge-squash and commit.

Then your prepare_commit_msg hook can be as simple as:

#!/bin/bash

if [[ ! -e ".git/SQUASH_MSG" ]]; then exit 0; fi

# append the commit template after the default squash message
cat "$(git config commit.template)" >> ".git/SQUASH_MSG"
$EDITOR ".git/SQUASH_MSG"

That would put your template in the commit message being prepared, and open the editor.
Once the editor is closed, the modified .git/SQUASH_MSG will be used for the final commit.
In that instance, no need for git commit -a.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • That is a nice hint but not an answer without the script. It also sounds like a workaround and not as a solution when I need a script for such a fundamental behavior. How do I "combine"? In which language should the script be? Don't use Bash because it is intended for machine-to-machine communication and not humans. What should a script return and how in which format? Even the linked git "docu" is just an command reference and doesn't provide enough information to develop an own solution. – buhtz Mar 13 '23 at 06:38
  • 1
    @buhtz A hook can be written in any language you want, as long as it is an executable. It should return 0 (the message has been updated) or non-zero (commit is aborted). I do not have enough information in your question to provide a script, and I would do it in bash (since it does not involve installing anything). But again, you can use any language you want. – VonC Mar 13 '23 at 07:05
  • How can I modify the commit message template when the script just returns 0 or !0? In the end (after `git merge --squash foo && git comit -a` I want my editor of choice open with the commit message template in it. – buhtz Mar 13 '23 at 07:22
  • Does git take the result (the new commit message template) from stdout? So I just have to do print/echo the result instead of integrate it as a return value of the script itself? This info is missing in the docu and your hint. That is a bug in the docu and a good example of machine-to-machine communication. I don't want to think like a machine. I want to read good documentation! – buhtz Mar 13 '23 at 07:29
  • @buhtz The goal is not to modify the commit message template, but to modify the commit itself, when doing a `merge --squash`. The hook would read the commit message template (through [its path](https://git-scm.com/docs/git-config#Documentation/git-config.txt-committemplate): `git config commit.template`, and would update `.git/SQUASH_MSG` accordingly. – VonC Mar 13 '23 at 07:31
  • @buhtz The new commit message is the existing `.git/MERGE_MSG` or `.git/SQUASH_MSG` that the script would update in order to integrate the commit template content. – VonC Mar 13 '23 at 07:32
  • Then this answer doesn't answer the question at all. I want to use my commit message **template** after merge-squash. I don't want to modify a specific commit message via a script. I do edit all my commit messages myself. But I want the template before. Please stop adding comments. Update your "answer" and show good examples how this would work. – buhtz Mar 13 '23 at 08:11
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/252484/discussion-between-vonc-and-buhtz). – VonC Mar 13 '23 at 08:13
1

When you do git merge --squash a file containing the new commit message is written to .git/SQUASH_MSG, that takes precedence over your commit template, and there isn't any option to override that.

You can simply remove that file after doing the merge.

There's many ways to help you remove that file, but the simplest is to simply create an alias that does that for you:

git config --global alias.my-merge-squash \
  '!f() { git merge --squash $@ && rm -f .git/SQUASH_MSG; }; f'

Now you can do git my-merge-squash mybranch instead of git merge --squash mybranch.

You can give your alias any name you like, like ms.

But if you are typically doing git commit -a after every merge, you can configure an alias to do everything at once:

git config --global alias.msc \
  '!f() { git merge --squash $@ && rm -f .git/SQUASH_MSG && git commit -a; }; f'

It should be possible to prepend your template to the squash message, but that requires writing up a script and adding it to your $PATH. Let me know if you would be interested in that in the comments.

FelipeC
  • 9,123
  • 4
  • 44
  • 38
1

I believe that you can get these results by creating a prepare-commit-msg hook file inside of .git/hooks. When performing git merge --squash mybranch && git commit -a, an editor will open with the original squash message, followed by your commit template:

#!/bin/bash

COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2

if [ "$COMMIT_SOURCE" = "squash" ]; then
  cat "$(git config commit.template)" >> $COMMIT_MSG_FILE
fi

Normally, when a .git/SQUASH_MSG file is present, the COMMIT_SOURCE for the prepare-msg-hook is just "squash". During a normal commit, the COMMIT_SOURCE is your template file. This is why your commit template was not being used.

In order to use your template for a squash commit, you need to add the contents of your commit template to the COMMIT_MSG_FILE.

TonyArra
  • 10,607
  • 1
  • 30
  • 46
1

If you don't mind typeing a few more words, you could try this,

git commit -a -F $(git config --get commit.template) --edit

or in shorter form

git commit -a -F $(git config commit.template) -e

-F reads the commit message from the following file without editing. -e allows to further edit the message. Of course, you could also use the real template path.

You could wrap it with an alias or a bash function. I prefer an executable customized git command. I use git-bash, so I'd create a bash script, for example git-cm, in /usr/bin under the installation path of git-bash and make it executable.

#!/bin/bash

git commit -a -F $(git config commit.template) -e

And then I can use git cm to invoke the script. If commit.template is not set, the command fails without any bad side-effect.

ElpieKay
  • 27,194
  • 6
  • 32
  • 53
  • It seems that `$(git config commit.template)` doesn't work if the value use the tilde as home folder surrogate (e.g. `~/.commit_template` ). – buhtz Mar 18 '23 at 08:22
  • @buhtz Which is why solutions that don't require hacks are better. – FelipeC Mar 24 '23 at 01:50