I needed to have a bash script do multi-line git commits for me, so here are two options I came up with:
- Write to a temporary file then commit with the contents of the file as the message: -  printf "first line\nsecond line\nthird line" > "file.txt"
 git commit -F "file.txt"
 
- (My preferred approach): Write to a temporary variable then commit with the contents of the variable as the message. Note that the quotes around - $MSGwhen doing any command to recall the contents of the variable are required! Without them, you'll lose your newlines.
 -  MSG="$(printf "first line\nsecond line\nthird line")"
 git commit -m "$MSG"
 
As an extension of this 2nd approach, in case you need to script building the message in multiple pieces or steps, that is possible too. WATCH OUT though! Notice where I place my newline (\n) characters. I do NOT place them at the end of any printf string. That's because if I do they will get gobbled up, because bash automatically removes any trailing newline characters, since it's dumb like that. So, do it like this instead, which works just fine:
    MSG="$(printf "first line")"
    MSG="$(printf "${MSG}\nsecond line")"
    MSG="$(printf "${MSG}\nthird line")"
    git commit -m "$MSG"
Sample git log output from any of the above git commits:
commit e1983659c6ae2e9d2eb4332657329837582fc32b (HEAD -> master)
Author: Gabriel Staples <email@gmail.com>
Date:   Tue Mar 24 00:55:31 2020 -0700
    first line
    second line
    third line
References:
- Unix & Linux: "Why does shell Command Substitution gobble up a trailing newline char?"
- VERY USEFUL! ==> How can I have a newline in a string in sh? <==