mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
Merge branch 'jk/trailers-placeholder-in-pretty'
In addition to %(subject), %(body), "log --pretty=format:..." learned a new placeholder %(trailers). * jk/trailers-placeholder-in-pretty: ref-filter: add support to display trailers as part of contents pretty: add %(trailers) format for displaying trailers of a commit message
This commit is contained in:
commit
f008159fc2
|
@ -168,6 +168,8 @@ of all lines of the commit message up to the first blank line. The next
|
|||
line is 'contents:body', where body is all of the lines after the first
|
||||
blank line. The optional GPG signature is `contents:signature`. The
|
||||
first `N` lines of the message is obtained using `contents:lines=N`.
|
||||
Additionally, the trailers as interpreted by linkgit:git-interpret-trailers[1]
|
||||
are obtained as 'contents:trailers'.
|
||||
|
||||
For sorting purposes, fields with numeric values sort in numeric order
|
||||
(`objectsize`, `authordate`, `committerdate`, `creatordate`, `taggerdate`).
|
||||
|
|
|
@ -199,6 +199,8 @@ endif::git-rev-list[]
|
|||
than given and there are spaces on its left, use those spaces
|
||||
- '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
|
||||
respectively, but padding both sides (i.e. the text is centered)
|
||||
-%(trailers): display the trailers of the body as interpreted by
|
||||
linkgit:git-interpret-trailers[1]
|
||||
|
||||
NOTE: Some placeholders may depend on other options given to the
|
||||
revision traversal engine. For example, the `%g*` reflog options will
|
||||
|
|
17
pretty.c
17
pretty.c
|
@ -10,6 +10,7 @@
|
|||
#include "color.h"
|
||||
#include "reflog-walk.h"
|
||||
#include "gpg-interface.h"
|
||||
#include "trailer.h"
|
||||
|
||||
static char *user_format;
|
||||
static struct cmt_fmt_map {
|
||||
|
@ -889,6 +890,16 @@ const char *format_subject(struct strbuf *sb, const char *msg,
|
|||
return msg;
|
||||
}
|
||||
|
||||
static void format_trailers(struct strbuf *sb, const char *msg)
|
||||
{
|
||||
struct trailer_info info;
|
||||
|
||||
trailer_info_get(&info, msg);
|
||||
strbuf_add(sb, info.trailer_start,
|
||||
info.trailer_end - info.trailer_start);
|
||||
trailer_info_release(&info);
|
||||
}
|
||||
|
||||
static void parse_commit_message(struct format_commit_context *c)
|
||||
{
|
||||
const char *msg = c->message + c->message_off;
|
||||
|
@ -1292,6 +1303,12 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
|||
strbuf_addstr(sb, msg + c->body_off);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (starts_with(placeholder, "(trailers)")) {
|
||||
format_trailers(sb, msg + c->subject_off);
|
||||
return strlen("(trailers)");
|
||||
}
|
||||
|
||||
return 0; /* unknown placeholder */
|
||||
}
|
||||
|
||||
|
|
22
ref-filter.c
22
ref-filter.c
|
@ -13,6 +13,7 @@
|
|||
#include "utf8.h"
|
||||
#include "git-compat-util.h"
|
||||
#include "version.h"
|
||||
#include "trailer.h"
|
||||
|
||||
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
|
||||
|
||||
|
@ -40,7 +41,7 @@ static struct used_atom {
|
|||
enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT }
|
||||
remote_ref;
|
||||
struct {
|
||||
enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB } option;
|
||||
enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;
|
||||
unsigned int nlines;
|
||||
} contents;
|
||||
enum { O_FULL, O_SHORT } objectname;
|
||||
|
@ -85,6 +86,13 @@ static void subject_atom_parser(struct used_atom *atom, const char *arg)
|
|||
atom->u.contents.option = C_SUB;
|
||||
}
|
||||
|
||||
static void trailers_atom_parser(struct used_atom *atom, const char *arg)
|
||||
{
|
||||
if (arg)
|
||||
die(_("%%(trailers) does not take arguments"));
|
||||
atom->u.contents.option = C_TRAILERS;
|
||||
}
|
||||
|
||||
static void contents_atom_parser(struct used_atom *atom, const char *arg)
|
||||
{
|
||||
if (!arg)
|
||||
|
@ -95,6 +103,8 @@ static void contents_atom_parser(struct used_atom *atom, const char *arg)
|
|||
atom->u.contents.option = C_SIG;
|
||||
else if (!strcmp(arg, "subject"))
|
||||
atom->u.contents.option = C_SUB;
|
||||
else if (!strcmp(arg, "trailers"))
|
||||
atom->u.contents.option = C_TRAILERS;
|
||||
else if (skip_prefix(arg, "lines=", &arg)) {
|
||||
atom->u.contents.option = C_LINES;
|
||||
if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
|
||||
|
@ -194,6 +204,7 @@ static struct {
|
|||
{ "creatordate", FIELD_TIME },
|
||||
{ "subject", FIELD_STR, subject_atom_parser },
|
||||
{ "body", FIELD_STR, body_atom_parser },
|
||||
{ "trailers", FIELD_STR, trailers_atom_parser },
|
||||
{ "contents", FIELD_STR, contents_atom_parser },
|
||||
{ "upstream", FIELD_STR, remote_ref_atom_parser },
|
||||
{ "push", FIELD_STR, remote_ref_atom_parser },
|
||||
|
@ -785,6 +796,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
|
|||
name++;
|
||||
if (strcmp(name, "subject") &&
|
||||
strcmp(name, "body") &&
|
||||
strcmp(name, "trailers") &&
|
||||
!starts_with(name, "contents"))
|
||||
continue;
|
||||
if (!subpos)
|
||||
|
@ -808,6 +820,14 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
|
|||
/* Size is the length of the message after removing the signature */
|
||||
append_lines(&s, subpos, contents_end - subpos, atom->u.contents.nlines);
|
||||
v->s = strbuf_detach(&s, NULL);
|
||||
} else if (atom->u.contents.option == C_TRAILERS) {
|
||||
struct trailer_info info;
|
||||
|
||||
/* Search for trailer info */
|
||||
trailer_info_get(&info, subpos);
|
||||
v->s = xmemdupz(info.trailer_start,
|
||||
info.trailer_end - info.trailer_start);
|
||||
trailer_info_release(&info);
|
||||
} else if (atom->u.contents.option == C_BARE)
|
||||
v->s = xstrdup(subpos);
|
||||
}
|
||||
|
|
|
@ -535,4 +535,30 @@ test_expect_success 'clean log decoration' '
|
|||
test_cmp expected actual1
|
||||
'
|
||||
|
||||
cat >trailers <<EOF
|
||||
Signed-off-by: A U Thor <author@example.com>
|
||||
Acked-by: A U Thor <author@example.com>
|
||||
[ v2 updated patch description ]
|
||||
Signed-off-by: A U Thor <author@example.com>
|
||||
EOF
|
||||
|
||||
test_expect_success 'pretty format %(trailers) shows trailers' '
|
||||
echo "Some contents" >trailerfile &&
|
||||
git add trailerfile &&
|
||||
git commit -F - <<-EOF &&
|
||||
trailers: this commit message has trailers
|
||||
|
||||
This commit is a test commit with trailers at the end. We parse this
|
||||
message and display the trailers using %bT
|
||||
|
||||
$(cat trailers)
|
||||
EOF
|
||||
git log --no-walk --pretty="%(trailers)" >actual &&
|
||||
cat >expect <<-EOF &&
|
||||
$(cat trailers)
|
||||
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -563,4 +563,29 @@ test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
cat >trailers <<EOF
|
||||
Reviewed-by: A U Thor <author@example.com>
|
||||
Signed-off-by: A U Thor <author@example.com>
|
||||
EOF
|
||||
|
||||
test_expect_success 'basic atom: head contents:trailers' '
|
||||
echo "Some contents" > two &&
|
||||
git add two &&
|
||||
git commit -F - <<-EOF &&
|
||||
trailers: this commit message has trailers
|
||||
|
||||
Some message contents
|
||||
|
||||
$(cat trailers)
|
||||
EOF
|
||||
git for-each-ref --format="%(contents:trailers)" refs/heads/master >actual &&
|
||||
sanitize_pgp <actual >actual.clean &&
|
||||
# git for-each-ref ends with a blank line
|
||||
cat >expect <<-EOF &&
|
||||
$(cat trailers)
|
||||
|
||||
EOF
|
||||
test_cmp expect actual.clean
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Loading…
Reference in a new issue