Skip to content

Instantly share code, notes, and snippets.

@april
Last active November 4, 2024 22:45
Show Gist options
  • Save april/ee2e104b1435f3113e67663d8875bbef to your computer and use it in GitHub Desktop.
Save april/ee2e104b1435f3113e67663d8875bbef to your computer and use it in GitHub Desktop.
pure shell function for git log as JSON
# attempting to be the most robust solution for outputting git log as JSON,
# using only `git` and the standard shell functions, without requiring
# additional software.
# - uses traditional JSON camelCase
# - includes every major field that git log can output, including the body
# - proper sections for author, committer, and signature
# - multiple date formats (one for reading, ISO for parsing)
# - should properly handle (most? all?) body values, even those that contain
# quotation marks and escaped characters
# - outputs as minimized JSON, can be piped to `jq` for pretty printing
# - can run against the current directory as `git-log-json` or against a file
# or folder with `git-log-json foo`
# - easily piped into `jq`, e.g. this will get all the commit subjects:
# $ git-log-json foo | jq -r '.[] | .subject'
# credit to @nsisodiya, @varemenos, @overengineer, and others for the
# original working code:
# https://gist.github.com/varemenos/e95c2e098e657c7688fd
git-log-json() {
IFS='' read -r -d '' FORMAT << 'EOF'
{
^^^^author^^^^: { ^^^^name^^^^: ^^^^%aN^^^^,
^^^^email^^^^: ^^^^%aE^^^^,
^^^^date^^^^: ^^^^%aD^^^^,
^^^^dateISO8601^^^^: ^^^^%aI^^^^},
^^^^body^^^^: ^^^^%b^^^^,
^^^^commitHash^^^^: ^^^^%H^^^^,
^^^^commitHashAbbreviated^^^^: ^^^^%h^^^^,
^^^^committer^^^^: {
^^^^name^^^^: ^^^^%cN^^^^,
^^^^email^^^^: ^^^^%cE^^^^,
^^^^date^^^^: ^^^^%cD^^^^,
^^^^dateISO8601^^^^: ^^^^%cI^^^^},
^^^^encoding^^^^: ^^^^%e^^^^,
^^^^notes^^^^: ^^^^%N^^^^,
^^^^parent^^^^: ^^^^%P^^^^,
^^^^parentAbbreviated^^^^: ^^^^%p^^^^,
^^^^refs^^^^: ^^^^%D^^^^,
^^^^signature^^^^: {
^^^^key^^^^: ^^^^%GK^^^^,
^^^^signer^^^^: ^^^^%GS^^^^,
^^^^verificationFlag^^^^: ^^^^%G?^^^^},
^^^^subject^^^^: ^^^^%s^^^^,
^^^^subjectSanitized^^^^: ^^^^%f^^^^,
^^^^tree^^^^: ^^^^%T^^^^,
^^^^treeAbbreviated^^^^: ^^^^%t^^^^
},
EOF
FORMAT=$(echo $FORMAT|tr -d '\r\n ')
git log --pretty=format:$FORMAT $1 | \
sed -e ':a' -e 'N' -e '$!ba' -e s'/\^^^^},\n{\^^^^/^^^^},{^^^^/g' \
-e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\^^^^/"/g' -e '$ s/,$//' | \
sed -e ':a' -e 'N' -e '$!ba' -e 's/\r//g' -e 's/\n/\\n/g' -e 's/\t/\\t/g' | \
awk 'BEGIN { ORS=""; printf("[") } { print($0) } END { printf("]\n") }'
}
@april
Copy link
Author

april commented Nov 28, 2022

I wonder if simply doing something like:

local Q=$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM

Would be enough? That's quite a lot of entropy.

@gubasso
Copy link

gubasso commented Dec 20, 2023

@april I'm running into an issue with repos that have only one commit. I've tested this in a few such repositories, using simple commit messages, and got the same error. It seems like the function isn't parsing correctly when there is a single commit.

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