Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save erikw/654386d35ecfdb0354cd2b71763f19ae to your computer and use it in GitHub Desktop.

Select an option

Save erikw/654386d35ecfdb0354cd2b71763f19ae to your computer and use it in GitHub Desktop.
Generate git commit message from git-status. Will generate a commit message like "Added: file1.py file2.py file3.py Modified: file4.py file5.py Deleted: README.md Renamed: test.txt-> test2.txt". Put this in your .gitconfig.

git commit-status alias

An alias that will generate a git commit message staged changes as shown in git-status. Put this alias (section below) in your .gitconfig.

The message generated will be in the format of:

$ git status --porcelain
A file1.py
A file2.py
A file3.py
M file4.py
M file5.py
D README.md
R test.txt-> test2.txt
$ git commit-status
$ git log --no-decorate -n 1
bee4f8e Added: file1.py file2.py file3.py Modified: file4.py file5.py Deleted: README.md Renamed: test.txt-> test2.txt

Shared on Stack Overflow.

[alias]
# commit-status: generate a commit with message from git-status (staged changes).
# Source: https://gist.github.com/erikw/654386d35ecfdb0354cd2b71763f19ae
# Explanation:
# - Get only staged changes
# - Ignore changes in working area (2nd letter, the Y in XY as explained in $(git help status))
# - + split label and file path to separate lines so we can process the labels separately
# - Keep only the first label using awk
# - Add newline before each label section so we later can truncate \n to put everything on one line
# - Make labels human readable e.g. M -> Modified
# - Put everything on one line and trim leading & trailing whitespaces
commit-status = !" \
TMPFILE=$(mktemp /tmp/git-commit-status-message.XXX); \
git status --porcelain \
| grep '^[MARCDT]' \
| sort \
| sed -re 's/^([[:upper:]])[[:upper:]]?[[:space:]]+/\\1:\\n/' \
| awk '!x[$0]++' \
| sed -re 's/^([[:upper:]]:)$/\\n\\1/' \
| sed -re 's/^M:$/Modified: /' \
| sed -re 's/^A:$/Added: /' \
| sed -re 's/^R:$/Renamed: /' \
| sed -re 's/^C:$/Copied: /' \
| sed -re 's/^D:$/Deleted: /' \
| sed -re 's/^T:$/File Type Changed: /' \
| tr '\n' ' ' | xargs \
> $TMPFILE; \
git commit -F $TMPFILE; \
rm -f $TMPFILE \
"
# If you want to have a [Yn] prompt showing the commit message before making the commit,
# then simply inject the following lines below in to the alias above just before the
# "git commit -F $TMPFILE; \" line:
cat $TMPFILE; \
commit=''; \
while :; do \
echo '> Commit with this message? [Yn]: '; \
read commit; \
([ -z \"$commit\" ] || [ \"$commit\" = y ] || [ \"$commit\" = Y ] || [ \"$commit\" = n ]) && break; \
done; \
test \"$commit\" != n || exit; \
@isayakmondal
Copy link

Sorry for the late reply, this seems to work fine till now but the version with [Y/n] prompt is better.

@erikw
Copy link
Author

erikw commented Jan 17, 2022

@isayakmondal Thank you for testing. I added then [Yn] prompt to the Gist as well :)

@tomeo
Copy link

tomeo commented Feb 1, 2022

If you want to add this alias as a oneliner from Powershell:
git config --global alias.cs "! TMPFILE=`$(mktemp /tmp/git-commit-status-message.XXX); git status --porcelain | grep '^[MARCDT]' | sort | sed -re 's/^([[:upper:]])[[:upper:]]?[[:space:]]+/\1:\n/' | awk '!x[`$0]++' | sed -re 's/^([[:upper:]]:)`$/\n\1/' | sed -re 's/^M:`$/Modified: /' | sed -re 's/^A:`$/Added: /' | sed -re 's/^R:`$/Renamed: /' | sed -re 's/^C:`$/Copied: /' | sed -re 's/^D:`$/Deleted: /' | sed -re 's/^T:`$/File Type Changed: /' | xargs > `$TMPFILE; git commit -F `$TMPFILE; rm -f `$TMPFILE"

@erikw
Copy link
Author

erikw commented Feb 1, 2022

Thanks at @tomeo. That's a pretty massive one-liner there 😄

@neitsab
Copy link

neitsab commented Dec 21, 2024

Hi everyone
I just wanted to mention that in Android Termux shell, this produces output like

1:npath/to/file1.md 1:npath/to/file2.txt

Versions it's using:

bash --version
GNU bash, version 5.2.26(1)-release (aarch64-unknown-linux-android)

git --version
git version 2.44.0

sed --version
sed (GNU sed) 4.9

grep --version
grep (GNU grep) 3.11
...
grep -P uses PCRE2 10.43 2024-02-16

awk --version
GNU Awk 5.3.0, API 4.0, (GNU MPFR 4.2.1, GNU MP 6.3.0)

tr --version
tr (GNU coreutils) 9.4

I've tried playing with the double antislashes since it seems to be an escaping issue but cannot get the desired output. Any idea?

@ronaldwolvers
Copy link

ronaldwolvers commented Jun 18, 2025

I have modified the script so that the changed file names are surrounded by backticks:

[alias]
	# commit-status: generate a commit with message from git-status (staged changes).
	# Source: https://gist.github.com/erikw/654386d35ecfdb0354cd2b71763f19ae
	# Explanation:
	# - Get only staged changes
	# - Ignore changes in working area (2nd letter, the Y in XY as explained in $(git help status))
	# - Wrap the file names in backticks
	# - + split label and file path to separate lines so we can process the labels separately
	# - Keep only the first label using awk
	# - Add newline before each label section so we later can truncate \n to put everything on one line
	# - Make labels human readable e.g. M -> Modified
	commit-status = !" \
            TMPFILE=$(mktemp /tmp/git-commit-status-message.XXX); \
            git status --porcelain \
              | grep '^[MARCDT]' \
              | sort \
              | sed -re 's/^([MARCDT][[:space:]]+)(.*)$/\\1 \\`\\2\\`/' \
              | sed -re 's/^([[:upper:]])[[:upper:]]?[[:space:]]+/\\1:\\n/' \
              | awk '!x[$0]++' \
              | sed -re 's/^([[:upper:]]:)$/\\n\\1/' \
              | sed -re 's/^M:$/Modified: /' \
              | sed -re 's/^A:$/Added: /' \
              | sed -re 's/^R:$/Renamed: /' \
              | sed -re 's/^C:$/Copied: /' \
              | sed -re 's/^D:$/Deleted: /' \
              | sed -re 's/^T:$/File Type Changed: /' \
              > $TMPFILE; \
            git commit -F $TMPFILE; \
            rm -f $TMPFILE \
            "

Also removed the linebreak trimming, as I think this looks a bit cleaner. Which of course is highly subjective.
Thank you very much, @erikw, for creating and uploading this gist - and other contributors!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment