Reputation: 37267
I am creating some scripts and programs that fetch commit information using
git log --pretty=<my format> -1 <commit>
I wonder if the output of this command is suitable to be parsed by programs (plumbing) or only meant to be presented to humans (porcelain). For example, in some projects I am fetching commit SHA + author name + commit summary with this:
git log --pretty="%H%n%an%n%s" -1 HEAD
And then I split the output string by the newline character (I'm on Linux).
Besides, in some cases I also do something like this:
git log --pretty='[%h] %an: %s' -1 HEAD
And then parse the result with the following regex, expecting that a short SHA, the author name and the commit summary are in the captured groups:
^\[(\w+)\] ([^:]+): (.*)$
Is it a good approach? If not, what is the preferred way to programmatically get information about commits?
Upvotes: 12
Views: 4332
Reputation: 1
Just to add to kostix's answer: for me, git show-ref -s HEAD
does not output anything and returns with exit code 1.
Instead of:
git cat-file commit `git show-ref -s HEAD`
I use:
git cat-file commit `git show-ref --head -s HEAD`
or:
git cat-file commit `git rev-parse HEAD`
Upvotes: 0
Reputation: 37267
Thanks to kostic and torek for their answers.
Despite what they answered, I believe that some of the pretty format options can be safely treated as plumbing (i.e. safe to be parsed by programs). Examples include
%H
for full commit SHA%T
for full tree SHA%P
for full parent SHAs%an
, %cn
, %ae
, %ce
, %at
, %ct
for author/committer name/email/date (Unix). Also RFC 2822 and ISO 8601 style times are reliable %aD
, %cD
, %aI
, %cI
%s
for commit summary%G?
for signature status%n
for a newline (lol...)Yes, while format specifiers like %ad
and %cN
can be affected by user settings, it's unlikely that the above ones do. So I have decided that my current code that parses the output of git log
with a pretty format combined from above specifiers, is safe and not error-prone.
Upvotes: 0
Reputation: 488589
I agree with kostix; git log
is a porcelain command. But the problem here is that there are some things git log
can do that are too difficult to do with other commands, so we can sometimes make git log
act like a plumbing command.
The key distinction between plumbing and porcelain shows up when comparing, e.g., git branch
and git tag
to git for-each-ref
, or git diff
to git diff-tree
and git diff-files
and git diff-index
. It's not how many porcelains there are per plumbing. Here, for instance, the plumbing git for-each-ref
has two separate porcelain front ends, while the single front-end git diff
has three plumbing back-ends. No, the key is that git diff
changes its behavior based on user-selected configuration items:
diff.algorithm
diff.dirstat
diff.renameLimit
diff.renames
diff.statGraphWidth
diff.submodule
and so on. The plumbing versions ignore all user configuration, so that a script you write behaves the same for Alice, Bob, Carol, and Dave, even though they have different settings.
When using this definition, we can decide whether git log
acts like a plumbing command. This requires enumerating all the git log
configuration options. Unfortunately, there's no clean way to do that—more options can be added at any time, and some have been added over time.
Here's a list I found by scraping through the git log
and git config
manual. Note that I omit all the diff-oriented ones (e.g., color.diff
and the diff.*
items mentioned above) as there are plumbing commands to handle the equivalent of -p
in git log
(though you must work through one commit at a time).
color.decorate.<slot>
core.notesRef
format.pretty
i18n.logOutputEncoding
log.abbrevCommit
log.date
log.decorate
log.follow
log.graphColors
log.mailmap
log.showRoot
log.showSignature
notes.displayRef
pretty.<name>
So, let's say we want to get the committer date from some particular commit, formatted some particular way. To do that we might run:
git log --no-walk --pretty=format:%cd
We find in the main git log
documentation that pretty format %cd
is described this way:
%cd: committer date (format respects --date= option)
We failed to give a --date=
option, so git log
will look up the log.date
setting. That's a user-configuration option, and our git log
output will depend on the user's choice, rather than ours.
To make this git log
act like a plumbing command, then, we must override the log.date
configuration setting, with, e.g., --date=default
or -c log.date=default
:
git -c log.date=default log --no-walk --pretty=format:%cd
or:
git log --no-walk --date=default --pretty=format:%cd
Ideally, Git should have either a plog
command that is defined as plumbing variant of git log, or a git format-log-metadata
plumbing command that takes the --pretty=<directives>
options and formats log metadata. Since it doesn't, it's up to anyone writing a script, that needs git log --pretty=format:...
output, to make sure that they know about configuration options that might affect them.
Upvotes: 5
Reputation: 55483
git log
is a porcelain command.
It actually performs quite a disparate number of tasks — combining walking the revision graph, git diff
and git grep
and whatnot.
A plumbing way to do someting like
git log --pretty='[%h] %an: %s' -1 HEAD
is to combine git show-ref
with git cat-file
and parse the result—something like
git cat-file commit `git show-ref -s HEAD` |
while read line; do
# do some processing
done
Actually the root Git's manual page, git(1)
—run git help git
to read it—contains the breakdown of commands into porcelain and plumbing layers.
Upvotes: 7