pretty-formats: add 'format:<string>'
With this patch, $ git show -s \ --pretty=format:' Ze komit %h woss%n dunn buy ze great %an' shows something like Ze komit 04c5c88 woss dunn buy ze great Junio C Hamano The supported placeholders are: '%H': commit hash '%h': abbreviated commit hash '%T': tree hash '%t': abbreviated tree hash '%P': parent hashes '%p': abbreviated parent hashes '%an': author name '%ae': author email '%ad': author date '%aD': author date, RFC2822 style '%ar': author date, relative '%at': author date, UNIX timestamp '%cn': committer name '%ce': committer email '%cd': committer date '%cD': committer date, RFC2822 style '%cr': committer date, relative '%ct': committer date, UNIX timestamp '%e': encoding '%s': subject '%b': body '%Cred': switch color to red '%Cgreen': switch color to green '%Cblue': switch color to blue '%Creset': reset color '%n': newline Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
437b1b20df
commit
e52a5de45a
@ -77,9 +77,53 @@ displayed in full, regardless of whether --abbrev or
|
|||||||
true parent commits, without taking grafts nor history
|
true parent commits, without taking grafts nor history
|
||||||
simplification into account.
|
simplification into account.
|
||||||
|
|
||||||
|
* 'format:'
|
||||||
|
+
|
||||||
|
The 'format:' format allows you to specify which information
|
||||||
|
you want to show. It works a little bit like printf format,
|
||||||
|
with the notable exception that you get a newline with '%n'
|
||||||
|
instead of '\n'.
|
||||||
|
|
||||||
|
E.g, 'format:"The author of %h was %an, %ar%nThe title was >>%s<<"'
|
||||||
|
would show something like this:
|
||||||
|
|
||||||
|
The author of fe6e0ee was Junio C Hamano, 23 hours ago
|
||||||
|
The title was >>t4119: test autocomputing -p<n> for traditional diff input.<<
|
||||||
|
|
||||||
|
The placeholders are:
|
||||||
|
|
||||||
|
- '%H': commit hash
|
||||||
|
- '%h': abbreviated commit hash
|
||||||
|
- '%T': tree hash
|
||||||
|
- '%t': abbreviated tree hash
|
||||||
|
- '%P': parent hashes
|
||||||
|
- '%p': abbreviated parent hashes
|
||||||
|
- '%an': author name
|
||||||
|
- '%ae': author email
|
||||||
|
- '%ad': author date
|
||||||
|
- '%aD': author date, RFC2822 style
|
||||||
|
- '%ar': author date, relative
|
||||||
|
- '%at': author date, UNIX timestamp
|
||||||
|
- '%cn': committer name
|
||||||
|
- '%ce': committer email
|
||||||
|
- '%cd': committer date
|
||||||
|
- '%cD': committer date, RFC2822 style
|
||||||
|
- '%cr': committer date, relative
|
||||||
|
- '%ct': committer date, UNIX timestamp
|
||||||
|
- '%e': encoding
|
||||||
|
- '%s': subject
|
||||||
|
- '%b': body
|
||||||
|
- '%Cred': switch color to red
|
||||||
|
- '%Cgreen': switch color to green
|
||||||
|
- '%Cblue': switch color to blue
|
||||||
|
- '%Creset': reset color
|
||||||
|
- '%n': newline
|
||||||
|
|
||||||
|
|
||||||
--encoding[=<encoding>]::
|
--encoding[=<encoding>]::
|
||||||
The commit objects record the encoding used for the log message
|
The commit objects record the encoding used for the log message
|
||||||
in their encoding header; this option can be used to tell the
|
in their encoding header; this option can be used to tell the
|
||||||
command to re-code the commit log message in the encoding
|
command to re-code the commit log message in the encoding
|
||||||
preferred by the user. For non plumbing commands this
|
preferred by the user. For non plumbing commands this
|
||||||
defaults to UTF-8.
|
defaults to UTF-8.
|
||||||
|
|
||||||
|
195
commit.c
195
commit.c
@ -3,6 +3,7 @@
|
|||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "pkt-line.h"
|
#include "pkt-line.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
#include "interpolate.h"
|
||||||
|
|
||||||
int save_commit_buffer = 1;
|
int save_commit_buffer = 1;
|
||||||
|
|
||||||
@ -36,8 +37,11 @@ struct cmt_fmt_map {
|
|||||||
{ "full", 5, CMIT_FMT_FULL },
|
{ "full", 5, CMIT_FMT_FULL },
|
||||||
{ "fuller", 5, CMIT_FMT_FULLER },
|
{ "fuller", 5, CMIT_FMT_FULLER },
|
||||||
{ "oneline", 1, CMIT_FMT_ONELINE },
|
{ "oneline", 1, CMIT_FMT_ONELINE },
|
||||||
|
{ "format:", 7, CMIT_FMT_USERFORMAT},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static char *user_format;
|
||||||
|
|
||||||
enum cmit_fmt get_commit_format(const char *arg)
|
enum cmit_fmt get_commit_format(const char *arg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -46,6 +50,12 @@ enum cmit_fmt get_commit_format(const char *arg)
|
|||||||
return CMIT_FMT_DEFAULT;
|
return CMIT_FMT_DEFAULT;
|
||||||
if (*arg == '=')
|
if (*arg == '=')
|
||||||
arg++;
|
arg++;
|
||||||
|
if (!prefixcmp(arg, "format:")) {
|
||||||
|
if (user_format)
|
||||||
|
free(user_format);
|
||||||
|
user_format = xstrdup(arg + 7);
|
||||||
|
return CMIT_FMT_USERFORMAT;
|
||||||
|
}
|
||||||
for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
|
for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
|
||||||
if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
|
if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
|
||||||
!strncmp(arg, cmt_fmts[i].n, strlen(arg)))
|
!strncmp(arg, cmt_fmts[i].n, strlen(arg)))
|
||||||
@ -710,6 +720,188 @@ static char *logmsg_reencode(const struct commit *commit,
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *xstrndup(const char *text, int len)
|
||||||
|
{
|
||||||
|
char *result = xmalloc(len + 1);
|
||||||
|
memcpy(result, text, len);
|
||||||
|
result[len] = '\0';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_person(struct interp *table, const char *msg, int len)
|
||||||
|
{
|
||||||
|
int start, end, tz = 0;
|
||||||
|
unsigned long date;
|
||||||
|
char *ep;
|
||||||
|
|
||||||
|
/* parse name */
|
||||||
|
for (end = 0; end < len && msg[end] != '<'; end++)
|
||||||
|
; /* do nothing */
|
||||||
|
start = end + 1;
|
||||||
|
while (end > 0 && isspace(msg[end - 1]))
|
||||||
|
end--;
|
||||||
|
table[0].value = xstrndup(msg, end);
|
||||||
|
|
||||||
|
if (start >= len)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* parse email */
|
||||||
|
for (end = start + 1; end < len && msg[end] != '>'; end++)
|
||||||
|
; /* do nothing */
|
||||||
|
|
||||||
|
if (end >= len)
|
||||||
|
return;
|
||||||
|
|
||||||
|
table[1].value = xstrndup(msg + start, end - start);
|
||||||
|
|
||||||
|
/* parse date */
|
||||||
|
for (start = end + 1; start < len && isspace(msg[start]); start++)
|
||||||
|
; /* do nothing */
|
||||||
|
if (start >= len)
|
||||||
|
return;
|
||||||
|
date = strtoul(msg + start, &ep, 10);
|
||||||
|
if (msg + start == ep)
|
||||||
|
return;
|
||||||
|
|
||||||
|
table[5].value = xstrndup(msg + start, ep - msg + start);
|
||||||
|
|
||||||
|
/* parse tz */
|
||||||
|
for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
|
||||||
|
; /* do nothing */
|
||||||
|
if (start + 1 < len) {
|
||||||
|
tz = strtoul(msg + start + 1, NULL, 10);
|
||||||
|
if (msg[start] == '-')
|
||||||
|
tz = -tz;
|
||||||
|
}
|
||||||
|
|
||||||
|
interp_set_entry(table, 2, show_date(date, tz, 0));
|
||||||
|
interp_set_entry(table, 3, show_rfc2822_date(date, tz));
|
||||||
|
interp_set_entry(table, 4, show_date(date, tz, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static long format_commit_message(const struct commit *commit,
|
||||||
|
const char *msg, char *buf, unsigned long space)
|
||||||
|
{
|
||||||
|
struct interp table[] = {
|
||||||
|
{ "%H" }, /* commit hash */
|
||||||
|
{ "%h" }, /* abbreviated commit hash */
|
||||||
|
{ "%T" }, /* tree hash */
|
||||||
|
{ "%t" }, /* abbreviated tree hash */
|
||||||
|
{ "%P" }, /* parent hashes */
|
||||||
|
{ "%p" }, /* abbreviated parent hashes */
|
||||||
|
{ "%an" }, /* author name */
|
||||||
|
{ "%ae" }, /* author email */
|
||||||
|
{ "%ad" }, /* author date */
|
||||||
|
{ "%aD" }, /* author date, RFC2822 style */
|
||||||
|
{ "%ar" }, /* author date, relative */
|
||||||
|
{ "%at" }, /* author date, UNIX timestamp */
|
||||||
|
{ "%cn" }, /* committer name */
|
||||||
|
{ "%ce" }, /* committer email */
|
||||||
|
{ "%cd" }, /* committer date */
|
||||||
|
{ "%cD" }, /* committer date, RFC2822 style */
|
||||||
|
{ "%cr" }, /* committer date, relative */
|
||||||
|
{ "%ct" }, /* committer date, UNIX timestamp */
|
||||||
|
{ "%e" }, /* encoding */
|
||||||
|
{ "%s" }, /* subject */
|
||||||
|
{ "%b" }, /* body */
|
||||||
|
{ "%Cred" }, /* red */
|
||||||
|
{ "%Cgreen" }, /* green */
|
||||||
|
{ "%Cblue" }, /* blue */
|
||||||
|
{ "%Creset" }, /* reset color */
|
||||||
|
{ "%n" } /* newline */
|
||||||
|
};
|
||||||
|
enum interp_index {
|
||||||
|
IHASH = 0, IHASH_ABBREV,
|
||||||
|
ITREE, ITREE_ABBREV,
|
||||||
|
IPARENTS, IPARENTS_ABBREV,
|
||||||
|
IAUTHOR_NAME, IAUTHOR_EMAIL,
|
||||||
|
IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE,
|
||||||
|
IAUTHOR_TIMESTAMP,
|
||||||
|
ICOMMITTER_NAME, ICOMMITTER_EMAIL,
|
||||||
|
ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822,
|
||||||
|
ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP,
|
||||||
|
IENCODING,
|
||||||
|
ISUBJECT,
|
||||||
|
IBODY,
|
||||||
|
IRED, IGREEN, IBLUE, IRESET_COLOR,
|
||||||
|
INEWLINE
|
||||||
|
};
|
||||||
|
struct commit_list *p;
|
||||||
|
char parents[1024];
|
||||||
|
int i;
|
||||||
|
enum { HEADER, SUBJECT, BODY } state;
|
||||||
|
|
||||||
|
if (INEWLINE + 1 != ARRAY_SIZE(table))
|
||||||
|
die("invalid interp table!");
|
||||||
|
|
||||||
|
/* these are independent of the commit */
|
||||||
|
interp_set_entry(table, IRED, "\033[31m");
|
||||||
|
interp_set_entry(table, IGREEN, "\033[32m");
|
||||||
|
interp_set_entry(table, IBLUE, "\033[34m");
|
||||||
|
interp_set_entry(table, IRESET_COLOR, "\033[m");
|
||||||
|
interp_set_entry(table, INEWLINE, "\n");
|
||||||
|
|
||||||
|
/* these depend on the commit */
|
||||||
|
if (!commit->object.parsed)
|
||||||
|
parse_object(commit->object.sha1);
|
||||||
|
interp_set_entry(table, IHASH, sha1_to_hex(commit->object.sha1));
|
||||||
|
interp_set_entry(table, IHASH_ABBREV,
|
||||||
|
find_unique_abbrev(commit->object.sha1,
|
||||||
|
DEFAULT_ABBREV));
|
||||||
|
interp_set_entry(table, ITREE, sha1_to_hex(commit->tree->object.sha1));
|
||||||
|
interp_set_entry(table, ITREE_ABBREV,
|
||||||
|
find_unique_abbrev(commit->tree->object.sha1,
|
||||||
|
DEFAULT_ABBREV));
|
||||||
|
for (i = 0, p = commit->parents;
|
||||||
|
p && i < sizeof(parents) - 1;
|
||||||
|
p = p->next)
|
||||||
|
i += snprintf(parents + i, sizeof(parents) - i - 1, "%s ",
|
||||||
|
sha1_to_hex(p->item->object.sha1));
|
||||||
|
interp_set_entry(table, IPARENTS, parents);
|
||||||
|
for (i = 0, p = commit->parents;
|
||||||
|
p && i < sizeof(parents) - 1;
|
||||||
|
p = p->next)
|
||||||
|
i += snprintf(parents + i, sizeof(parents) - i - 1, "%s ",
|
||||||
|
find_unique_abbrev(p->item->object.sha1,
|
||||||
|
DEFAULT_ABBREV));
|
||||||
|
interp_set_entry(table, IPARENTS_ABBREV, parents);
|
||||||
|
|
||||||
|
for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
|
||||||
|
int eol;
|
||||||
|
for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
|
||||||
|
; /* do nothing */
|
||||||
|
|
||||||
|
if (state == SUBJECT) {
|
||||||
|
table[ISUBJECT].value = xstrndup(msg + i, eol - i);
|
||||||
|
i = eol;
|
||||||
|
}
|
||||||
|
if (i == eol) {
|
||||||
|
state++;
|
||||||
|
/* strip empty lines */
|
||||||
|
while (msg[eol + 1] == '\n')
|
||||||
|
eol++;
|
||||||
|
} else if (!prefixcmp(msg + i, "author "))
|
||||||
|
fill_person(table + IAUTHOR_NAME,
|
||||||
|
msg + i + 7, eol - i - 7);
|
||||||
|
else if (!prefixcmp(msg + i, "committer "))
|
||||||
|
fill_person(table + ICOMMITTER_NAME,
|
||||||
|
msg + i + 10, eol - i - 10);
|
||||||
|
else if (!prefixcmp(msg + i, "encoding "))
|
||||||
|
table[IENCODING].value = xstrndup(msg + i, eol - i);
|
||||||
|
i = eol;
|
||||||
|
}
|
||||||
|
if (msg[i])
|
||||||
|
table[IBODY].value = xstrdup(msg + i);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(table); i++)
|
||||||
|
if (!table[i].value)
|
||||||
|
interp_set_entry(table, i, "<unknown>");
|
||||||
|
|
||||||
|
interpolate(buf, space, user_format, table, ARRAY_SIZE(table));
|
||||||
|
interp_clear_table(table, ARRAY_SIZE(table));
|
||||||
|
|
||||||
|
return strlen(buf);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
||||||
const struct commit *commit,
|
const struct commit *commit,
|
||||||
unsigned long len,
|
unsigned long len,
|
||||||
@ -727,6 +919,9 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
|||||||
char *reencoded;
|
char *reencoded;
|
||||||
char *encoding;
|
char *encoding;
|
||||||
|
|
||||||
|
if (fmt == CMIT_FMT_USERFORMAT)
|
||||||
|
return format_commit_message(commit, msg, buf, space);
|
||||||
|
|
||||||
encoding = (git_log_output_encoding
|
encoding = (git_log_output_encoding
|
||||||
? git_log_output_encoding
|
? git_log_output_encoding
|
||||||
: git_commit_encoding);
|
: git_commit_encoding);
|
||||||
|
1
commit.h
1
commit.h
@ -47,6 +47,7 @@ enum cmit_fmt {
|
|||||||
CMIT_FMT_FULLER,
|
CMIT_FMT_FULLER,
|
||||||
CMIT_FMT_ONELINE,
|
CMIT_FMT_ONELINE,
|
||||||
CMIT_FMT_EMAIL,
|
CMIT_FMT_EMAIL,
|
||||||
|
CMIT_FMT_USERFORMAT,
|
||||||
|
|
||||||
CMIT_FMT_UNSPECIFIED,
|
CMIT_FMT_UNSPECIFIED,
|
||||||
};
|
};
|
||||||
|
@ -211,7 +211,7 @@ void show_log(struct rev_info *opt, const char *sep)
|
|||||||
sha1, sha1);
|
sha1, sha1);
|
||||||
opt->diffopt.stat_sep = buffer;
|
opt->diffopt.stat_sep = buffer;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
|
||||||
fputs(diff_get_color(opt->diffopt.color_diff, DIFF_COMMIT),
|
fputs(diff_get_color(opt->diffopt.color_diff, DIFF_COMMIT),
|
||||||
stdout);
|
stdout);
|
||||||
if (opt->commit_format != CMIT_FMT_ONELINE)
|
if (opt->commit_format != CMIT_FMT_ONELINE)
|
||||||
|
Loading…
Reference in New Issue
Block a user