Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save erikw/654386d35ecfdb0354cd2b71763f19ae to your computer and use it in GitHub Desktop.
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

isayakmondal commented Jan 16, 2022

@erikw Hey, hope you're doing well. I just found a new bug.
You can clearly see that two files have been modified but the commit message has only 1.

$ git status --porcelain
M  Equal_Coins.cpp
 M Task.cpp

$ git commit-status
Modified: Equal_Coins.cpp 
> Commit with this message? [Y/n]:
n

Looks like there's a space before M Task.cpp that might be causing the issue, but why is there a space in the first place?
Please have a look.

  • Update - Sorry my bad, I forgot to do git add . lol.

@erikw
Copy link
Author

erikw commented Jan 16, 2022

@isayakmondal Hello!

Yes I was just about to write that, that a space before means that the M is is for the file in the working area, not in the staged area (after git add).

Nevertheless, I started to look at this alias and felt a need to simplify it a bit. I worked out an updated version. As you are an active user of this one, would you mind trying if it works for you as well? It works when I've tested it, but it would be great to hear if it works also for at least another person!

	# 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 X from the filename
	# - Keep only the first label using awk
	# - Add newline before each label section
	# - 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 \
		"

@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 😄

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