Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylor Blau <me@ttaylorr.com>2022-10-31 04:04:42 +0300
committerTaylor Blau <me@ttaylorr.com>2022-10-31 04:04:42 +0300
commitc112d8d9c2687cb6443b628e38aa446e335fb21a (patch)
treeb9a479e64d92b967b829c864797d5565f0ab92f1
parent71aa6e3d85eb033ec3300298a132d7898d9969bb (diff)
parent7b11234e3bee123d6d48ed175f11b26b54fa67c6 (diff)
Merge branch 'tb/shortlog-group'
"git shortlog" learned to group by the "format" string. * tb/shortlog-group: shortlog: implement `--group=committer` in terms of `--group=<format>` shortlog: implement `--group=author` in terms of `--group=<format>` shortlog: extract `shortlog_finish_setup()` shortlog: support arbitrary commit format `--group`s shortlog: extract `--group` fragment for translation shortlog: make trailer insertion a noop when appropriate shortlog: accept `--date`-related options
-rw-r--r--Documentation/git-shortlog.txt8
-rw-r--r--builtin/log.c1
-rw-r--r--builtin/shortlog.c87
-rw-r--r--shortlog.h5
-rwxr-xr-xt/t4201-shortlog.sh39
5 files changed, 113 insertions, 27 deletions
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index f64e77047b2..7d0277d033d 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -47,6 +47,11 @@ OPTIONS
Each pretty-printed commit will be rewrapped before it is shown.
+--date=<format>::
+ Show dates formatted according to the given date string. (See
+ the `--date` option in the "Commit Formatting" section of
+ linkgit:git-log[1]). Useful with `--group=format:<format>`.
+
--group=<type>::
Group commits based on `<type>`. If no `--group` option is
specified, the default is `author`. `<type>` is one of:
@@ -59,6 +64,9 @@ OPTIONS
example, if your project uses `Reviewed-by` trailers, you might want
to see who has been reviewing with
`git shortlog -ns --group=trailer:reviewed-by`.
+ - `format:<format>`, any string accepted by the `--format` option of
+ 'git log'. (See the "PRETTY FORMATS" section of
+ linkgit:git-log[1].)
+
Note that commits that do not include the trailer will not be counted.
Likewise, commits with multiple trailers (e.g., multiple signoffs) may
diff --git a/builtin/log.c b/builtin/log.c
index e72869afb36..5eafcf26b49 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1334,6 +1334,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
log.in2 = 4;
log.file = rev->diffopt.file;
log.groups = SHORTLOG_GROUP_AUTHOR;
+ shortlog_finish_setup(&log);
for (i = 0; i < nr; i++)
shortlog_add_commit(&log, list[i]);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 7a1e1fe7c0e..27a87167e19 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -132,7 +132,9 @@ static void read_from_stdin(struct shortlog *log)
match = committer_match;
break;
case SHORTLOG_GROUP_TRAILER:
- die(_("using --group=trailer with stdin is not supported"));
+ die(_("using %s with stdin is not supported"), "--group=trailer");
+ case SHORTLOG_GROUP_FORMAT:
+ die(_("using %s with stdin is not supported"), "--group=format");
default:
BUG("unhandled shortlog group");
}
@@ -170,6 +172,9 @@ static void insert_records_from_trailers(struct shortlog *log,
const char *commit_buffer, *body;
struct strbuf ident = STRBUF_INIT;
+ if (!log->trailers.nr)
+ return;
+
/*
* Using format_commit_message("%B") would be simpler here, but
* this saves us copying the message.
@@ -200,9 +205,34 @@ static void insert_records_from_trailers(struct shortlog *log,
unuse_commit_buffer(commit, commit_buffer);
}
+static int shortlog_needs_dedup(const struct shortlog *log)
+{
+ return HAS_MULTI_BITS(log->groups) || log->format.nr > 1 || log->trailers.nr;
+}
+
+static void insert_records_from_format(struct shortlog *log,
+ struct strset *dups,
+ struct commit *commit,
+ struct pretty_print_context *ctx,
+ const char *oneline)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list_item *item;
+
+ for_each_string_list_item(item, &log->format) {
+ strbuf_reset(&buf);
+
+ format_commit_message(commit, item->string, &buf, ctx);
+
+ if (!shortlog_needs_dedup(log) || strset_add(dups, buf.buf))
+ insert_one_record(log, buf.buf, oneline);
+ }
+
+ strbuf_release(&buf);
+}
+
void shortlog_add_commit(struct shortlog *log, struct commit *commit)
{
- struct strbuf ident = STRBUF_INIT;
struct strbuf oneline = STRBUF_INIT;
struct strset dups = STRSET_INIT;
struct pretty_print_context ctx = {0};
@@ -211,7 +241,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.fmt = CMIT_FMT_USERFORMAT;
ctx.abbrev = log->abbrev;
ctx.print_email_subject = 1;
- ctx.date_mode.type = DATE_NORMAL;
+ ctx.date_mode = log->date_mode;
ctx.output_encoding = get_log_output_encoding();
if (!log->summary) {
@@ -222,30 +252,10 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
}
oneline_str = oneline.len ? oneline.buf : "<none>";
- if (log->groups & SHORTLOG_GROUP_AUTHOR) {
- strbuf_reset(&ident);
- format_commit_message(commit,
- log->email ? "%aN <%aE>" : "%aN",
- &ident, &ctx);
- if (!HAS_MULTI_BITS(log->groups) ||
- strset_add(&dups, ident.buf))
- insert_one_record(log, ident.buf, oneline_str);
- }
- if (log->groups & SHORTLOG_GROUP_COMMITTER) {
- strbuf_reset(&ident);
- format_commit_message(commit,
- log->email ? "%cN <%cE>" : "%cN",
- &ident, &ctx);
- if (!HAS_MULTI_BITS(log->groups) ||
- strset_add(&dups, ident.buf))
- insert_one_record(log, ident.buf, oneline_str);
- }
- if (log->groups & SHORTLOG_GROUP_TRAILER) {
- insert_records_from_trailers(log, &dups, commit, &ctx, oneline_str);
- }
+ insert_records_from_trailers(log, &dups, commit, &ctx, oneline_str);
+ insert_records_from_format(log, &dups, commit, &ctx, oneline_str);
strset_clear(&dups);
- strbuf_release(&ident);
strbuf_release(&oneline);
}
@@ -314,6 +324,7 @@ static int parse_group_option(const struct option *opt, const char *arg, int uns
if (unset) {
log->groups = 0;
string_list_clear(&log->trailers, 0);
+ string_list_clear(&log->format, 0);
} else if (!strcasecmp(arg, "author"))
log->groups |= SHORTLOG_GROUP_AUTHOR;
else if (!strcasecmp(arg, "committer"))
@@ -321,8 +332,15 @@ static int parse_group_option(const struct option *opt, const char *arg, int uns
else if (skip_prefix(arg, "trailer:", &field)) {
log->groups |= SHORTLOG_GROUP_TRAILER;
string_list_append(&log->trailers, field);
- } else
+ } else if (skip_prefix(arg, "format:", &field)) {
+ log->groups |= SHORTLOG_GROUP_FORMAT;
+ string_list_append(&log->format, field);
+ } else if (strchr(arg, '%')) {
+ log->groups |= SHORTLOG_GROUP_FORMAT;
+ string_list_append(&log->format, arg);
+ } else {
return error(_("unknown group type: %s"), arg);
+ }
return 0;
}
@@ -340,6 +358,19 @@ void shortlog_init(struct shortlog *log)
log->in2 = DEFAULT_INDENT2;
log->trailers.strdup_strings = 1;
log->trailers.cmp = strcasecmp;
+ log->format.strdup_strings = 1;
+}
+
+void shortlog_finish_setup(struct shortlog *log)
+{
+ if (log->groups & SHORTLOG_GROUP_AUTHOR)
+ string_list_append(&log->format,
+ log->email ? "%aN <%aE>" : "%aN");
+ if (log->groups & SHORTLOG_GROUP_COMMITTER)
+ string_list_append(&log->format,
+ log->email ? "%cN <%cE>" : "%cN");
+
+ string_list_sort(&log->trailers);
}
int cmd_shortlog(int argc, const char **argv, const char *prefix)
@@ -407,10 +438,11 @@ parse_done:
log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
log.abbrev = rev.abbrev;
log.file = rev.diffopt.file;
+ log.date_mode = rev.date_mode;
if (!log.groups)
log.groups = SHORTLOG_GROUP_AUTHOR;
- string_list_sort(&log.trailers);
+ shortlog_finish_setup(&log);
/* assume HEAD if from a tty */
if (!nongit && !rev.pending.nr && isatty(0))
@@ -479,4 +511,5 @@ void shortlog_output(struct shortlog *log)
log->list.strdup_strings = 1;
string_list_clear(&log->list, 1);
clear_mailmap(&log->mailmap);
+ string_list_clear(&log->format, 0);
}
diff --git a/shortlog.h b/shortlog.h
index 3f7e9aabcae..28d04f951af 100644
--- a/shortlog.h
+++ b/shortlog.h
@@ -2,6 +2,7 @@
#define SHORTLOG_H
#include "string-list.h"
+#include "date.h"
struct commit;
@@ -15,13 +16,16 @@ struct shortlog {
int in2;
int user_format;
int abbrev;
+ struct date_mode date_mode;
enum {
SHORTLOG_GROUP_AUTHOR = (1 << 0),
SHORTLOG_GROUP_COMMITTER = (1 << 1),
SHORTLOG_GROUP_TRAILER = (1 << 2),
+ SHORTLOG_GROUP_FORMAT = (1 << 3),
} groups;
struct string_list trailers;
+ struct string_list format;
int email;
struct string_list mailmap;
@@ -29,6 +33,7 @@ struct shortlog {
};
void shortlog_init(struct shortlog *log);
+void shortlog_finish_setup(struct shortlog *log);
void shortlog_add_commit(struct shortlog *log, struct commit *commit);
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 3095b1b2ffe..8e4effebdb7 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -83,6 +83,13 @@ test_expect_success 'pretty format' '
test_cmp expect log.predictable
'
+test_expect_success 'pretty format (with --date)' '
+ sed "s/SUBJECT/2005-04-07 OBJECT_NAME/" expect.template >expect &&
+ git shortlog --format="%ad %H" --date=short HEAD >log &&
+ fuzz log >log.predictable &&
+ test_cmp expect log.predictable
+'
+
test_expect_success '--abbrev' '
sed s/SUBJECT/OBJID/ expect.template >expect &&
git shortlog --format="%h" --abbrev=35 HEAD >log &&
@@ -237,6 +244,26 @@ test_expect_success 'shortlog --group=trailer:signed-off-by' '
test_cmp expect actual
'
+test_expect_success 'shortlog --group=format' '
+ git shortlog -s --date="format:%Y" --group="format:%cN (%cd)" \
+ HEAD >actual &&
+ cat >expect <<-\EOF &&
+ 4 C O Mitter (2005)
+ 1 Sin Nombre (2005)
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'shortlog --group=<format> DWIM' '
+ git shortlog -s --date="format:%Y" --group="%cN (%cd)" HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'shortlog bogus --group' '
+ test_must_fail git shortlog --group=bogus HEAD 2>err &&
+ grep "unknown group type" err
+'
+
test_expect_success 'trailer idents are split' '
cat >expect <<-\EOF &&
2 C O Mitter
@@ -319,6 +346,18 @@ test_expect_success 'shortlog can match multiple groups' '
test_cmp expect actual
'
+test_expect_success 'shortlog can match multiple format groups' '
+ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" \
+ git commit --allow-empty -m "identical names" &&
+ test_tick &&
+ cat >expect <<-\EOF &&
+ 2 A U Thor
+ 1 C O Mitter
+ EOF
+ git shortlog -ns --group="%cn" --group="%an" -2 HEAD >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'set up option selection tests' '
git commit --allow-empty -F - <<-\EOF
subject