diff --git a/Documentation/git-format-rev.adoc b/Documentation/git-format-rev.adoc index c2268c92b5..184f5ca2e9 100644 --- a/Documentation/git-format-rev.adoc +++ b/Documentation/git-format-rev.adoc @@ -9,7 +9,7 @@ git-format-rev - EXPERIMENTAL: Pretty format revisions on demand SYNOPSIS -------- [synopsis] -(EXPERIMENTAL!) git format-rev --stdin-mode= --format= [--[no-]notes=] [-z] [--[no-]null-output] [--[no-]null-input] +(EXPERIMENTAL!) git format-rev [] --stdin-mode= --format= DESCRIPTION ----------- @@ -33,8 +33,8 @@ OPTIONS The argument `rev` is also accepted. `text`;; Formats all commit object names found in freeform text. These - must be full object names, i.e. abbreviated hexadecimal object - names will not be interpreted. + must be full object names, i.e. abbreviated hexadecimal (_hex_) + object names will not be interpreted. + Anything that is parsed as an object name but that is not found to be a commit object name is left alone (echoed). @@ -76,6 +76,44 @@ This is useful if the output could contain newlines, for example if the + This is useful if the input revision expressions could contain newlines. +`--color[=]`:: +`--no-color`:: + Respect color formatting. The default color behavior is + `auto`. Bare `--color` is the same as `--color=always`. ++ +Giving `--no-color` is the same as `--color=never`. ++ +__ must be one of: ++ +-- +`always`;; + Always use color, even if the output is something like a file. +`never`;; + Never use color. +`auto`;; + Use color when the output is a terminal but not when the output + is something like a file. +-- + +`--abbrev[=]`:: +`--no-abbrev`:: + Abbreviate the commit hex output. Without __ it will find the + minimum length which can describe the commit uniquely, with some + extra slack. Giving __ specifies the minimum length; a longer + length will be used if needed. ++ +Giving `--no-abbrev` will turn off abbreviation, showing the full commit +hex output. ++ +Note that some pretty formats use `--abbrev`. This behavior can be +controlled with these two options. + +`--date=`:: + Date format for pretty formats. Note that date atoms like `%aI` + are not affected. This option cannot be negated. ++ +include::rev-list-option-date-alternatives.adoc[] + [[io]] INPUT AND OUTPUT FORMAT ----------------------- diff --git a/Documentation/rev-list-option-date-alternatives.adoc b/Documentation/rev-list-option-date-alternatives.adoc new file mode 100644 index 0000000000..141570b105 --- /dev/null +++ b/Documentation/rev-list-option-date-alternatives.adoc @@ -0,0 +1,55 @@ +-- +`--date=relative` shows dates relative to the current time, +e.g. ``2 hours ago''. The `-local` option has no effect for +`--date=relative`. + +`--date=local` is an alias for `--date=default-local`. + +`--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format. +The differences to the strict ISO 8601 format are: + + - a space instead of the `T` date/time delimiter + - a space between time and time zone + - no colon between hours and minutes of the time zone + +`--date=iso-strict` (or `--date=iso8601-strict`) shows timestamps in strict +ISO 8601 format. + +`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822 +format, often found in email messages. + +`--date=short` shows only the date, but not the time, in `YYYY-MM-DD` format. + +`--date=raw` shows the date as seconds since the epoch (1970-01-01 +00:00:00 UTC), followed by a space, and then the timezone as an offset +from UTC (a `+` or `-` with four digits; the first two are hours, and +the second two are minutes). I.e., as if the timestamp were formatted +with `strftime("%s %z")`). +Note that the `-local` option does not affect the seconds-since-epoch +value (which is always measured in UTC), but does switch the accompanying +timezone value. + +`--date=human` shows the timezone if the timezone does not match the +current time-zone, and doesn't print the whole date if that matches +(ie skip printing year for dates that are "this year", but also skip +the whole date itself if it's in the last few days and we can just say +what weekday it was). For older dates the hour and minute is also +omitted. + +`--date=unix` shows the date as a Unix epoch timestamp (seconds since +1970). As with `--raw`, this is always in UTC and therefore `-local` +has no effect. + +`--date=format:` feeds the __ to your system `strftime`, +except for `%s`, `%z`, and `%Z`, which are handled internally. +Use `--date=format:%c` to show the date in your system locale's +preferred format. See the `strftime`(3) manual for a complete list of +format placeholders. When using `-local`, the correct syntax is +`--date=format-local:`. + +`--date=default` is the default format, and is based on ctime(3) +output. It shows a single line with three-letter day of the week, +three-letter month, day-of-month, hour-minute-seconds in "HH:MM:SS" +format, followed by 4-digit year, plus timezone information, unless +the local time zone is used, e.g. `Thu Jan 1 00:00:00 1970 +0000`. +-- diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc index fd831f0ec6..6e6093f474 100644 --- a/Documentation/rev-list-options.adoc +++ b/Documentation/rev-list-options.adoc @@ -1132,61 +1132,7 @@ include::pretty-options.adoc[] author's). If `-local` is appended to the format (e.g., `iso-local`), the user's local time zone is used instead. + --- -`--date=relative` shows dates relative to the current time, -e.g. ``2 hours ago''. The `-local` option has no effect for -`--date=relative`. - -`--date=local` is an alias for `--date=default-local`. - -`--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format. -The differences to the strict ISO 8601 format are: - - - a space instead of the `T` date/time delimiter - - a space between time and time zone - - no colon between hours and minutes of the time zone - -`--date=iso-strict` (or `--date=iso8601-strict`) shows timestamps in strict -ISO 8601 format. - -`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822 -format, often found in email messages. - -`--date=short` shows only the date, but not the time, in `YYYY-MM-DD` format. - -`--date=raw` shows the date as seconds since the epoch (1970-01-01 -00:00:00 UTC), followed by a space, and then the timezone as an offset -from UTC (a `+` or `-` with four digits; the first two are hours, and -the second two are minutes). I.e., as if the timestamp were formatted -with `strftime("%s %z")`). -Note that the `-local` option does not affect the seconds-since-epoch -value (which is always measured in UTC), but does switch the accompanying -timezone value. - -`--date=human` shows the timezone if the timezone does not match the -current time-zone, and doesn't print the whole date if that matches -(ie skip printing year for dates that are "this year", but also skip -the whole date itself if it's in the last few days and we can just say -what weekday it was). For older dates the hour and minute is also -omitted. - -`--date=unix` shows the date as a Unix epoch timestamp (seconds since -1970). As with `--raw`, this is always in UTC and therefore `-local` -has no effect. - -`--date=format:` feeds the __ to your system `strftime`, -except for `%s`, `%z`, and `%Z`, which are handled internally. -Use `--date=format:%c` to show the date in your system locale's -preferred format. See the `strftime`(3) manual for a complete list of -format placeholders. When using `-local`, the correct syntax is -`--date=format-local:`. - -`--date=default` is the default format, and is based on ctime(3) -output. It shows a single line with three-letter day of the week, -three-letter month, day-of-month, hour-minute-seconds in "HH:MM:SS" -format, followed by 4-digit year, plus timezone information, unless -the local time zone is used, e.g. `Thu Jan 1 00:00:00 1970 +0000`. --- +include::rev-list-option-date-alternatives.adoc[] ifdef::git-rev-list[] `--header`:: diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 60cbbfb4b7..fa20a2774b 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -21,6 +21,7 @@ #include "revision.h" #include "notes.h" #include "write-or-die.h" +#include "date.h" /* * One day. See the 'name a rev shortly after epoch' test in t6120 when @@ -772,20 +773,36 @@ int cmd_name_rev(int argc, return 0; } -struct format_nul_data { +struct format_rev_data { + const char *format; + const char *stdin_mode; bool nul_input; bool nul_output; + struct string_list notes; + struct rev_info rev; + int color; }; static int format_nul_cb(const struct option *option, const char *arg, int unset) { - struct format_nul_data *data = option->value; - data->nul_input = 1; - data->nul_output = 1; + struct format_rev_data *data = option->value; BUG_ON_OPT_NEG(unset); BUG_ON_OPT_ARG(arg); + data->nul_input = 1; + data->nul_output = 1; + return 0; +} + +static int date_cb(const struct option *option, + const char *arg, + int unset) +{ + struct rev_info *data = option->value; + BUG_ON_OPT_NEG(unset); + parse_date_format(arg, &data->date_mode); + data->date_mode_explicit = 1; return 0; } @@ -802,9 +819,8 @@ static enum stdin_mode parse_stdin_mode(const char *stdin_mode) } static char const *const format_rev_usage[] = { - N_("(EXPERIMENTAL!) git format-rev --stdin-mode= " - "--format= [--[no-]notes=] " - "[-z] [--[no-]null-output] [--[no-]null-input]"), + N_("(EXPERIMENTAL!) git format-rev [] " + "--stdin-mode= --format="), NULL }; @@ -813,32 +829,37 @@ int cmd_format_rev(int argc, const char *prefix, struct repository *repo UNUSED) { - const char *format = NULL; + struct format_rev_data data = { + .notes = STRING_LIST_INIT_NODUP, + .rev = REV_INFO_INIT, + .color = GIT_COLOR_AUTO, + }; enum stdin_mode stdin_mode; - const char *stdin_mode_arg = NULL; - struct format_nul_data nul_data = { 0, 0 }; char output_terminator; strbuf_getline_fn getline_fn; struct display_notes_opt format_notes_opt; - struct rev_info format_rev = REV_INFO_INIT; struct pretty_format format_pp = { 0 }; - struct string_list notes = STRING_LIST_INIT_NODUP; struct strbuf scratch_buf = STRBUF_INIT; struct command cmd; struct option opts[] = { - OPT_STRING(0, "format", &format, N_("format"), + OPT_STRING(0, "format", &data.format, N_("format"), N_("pretty format to use")), - OPT_STRING(0, "stdin-mode", &stdin_mode_arg, N_("stdin-mode"), + OPT_STRING(0, "stdin-mode", &data.stdin_mode, N_("stdin-mode"), N_("how revs are processed")), - OPT_STRING_LIST(0, "notes", ¬es, N_("notes"), + OPT_STRING_LIST(0, "notes", &data.notes, N_("notes"), N_("display notes for pretty format")), - OPT_CALLBACK_F('z', "null", &nul_data, N_("z"), - N_("Use NUL for input and output termination"), + OPT__ABBREV(&data.rev.abbrev), + OPT__COLOR(&data.color, N_("use colored output")), + OPT_CALLBACK_F(0, "date", &data.rev, N_("date"), + N_("date format"), + PARSE_OPT_NONEG, date_cb), + OPT_CALLBACK_F('z', "null", &data, N_("z"), + N_("use NUL for input and output termination"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, format_nul_cb), - OPT_BOOL(0, "null-input", &nul_data.nul_input, - N_("Use NUL for input termination")), - OPT_BOOL(0, "null-output", &nul_data.nul_output, - N_("Use NUL for output termination")), + OPT_BOOL(0, "null-input", &data.nul_input, + N_("use NUL for input termination")), + OPT_BOOL(0, "null-output", &data.nul_output, + N_("use NUL for output termination")), OPT_END(), }; @@ -849,32 +870,32 @@ int cmd_format_rev(int argc, usage_with_options(format_rev_usage, opts); } - if (!format) + if (!data.format) die(_("'%s' is required"), "--format"); - if (!stdin_mode_arg) + if (!data.stdin_mode) die(_("'%s' is required"), "--stdin-mode"); - getline_fn = nul_data.nul_input ? strbuf_getline_nul : strbuf_getline_lf; - output_terminator = nul_data.nul_output ? '\0' : '\n'; + getline_fn = data.nul_input ? strbuf_getline_nul : strbuf_getline_lf; + output_terminator = data.nul_output ? '\0' : '\n'; init_display_notes(&format_notes_opt); - stdin_mode = parse_stdin_mode(stdin_mode_arg); + stdin_mode = parse_stdin_mode(data.stdin_mode); - get_commit_format(format, &format_rev); - format_pp.ctx.rev = &format_rev; - format_pp.ctx.fmt = format_rev.commit_format; - format_pp.ctx.abbrev = format_rev.abbrev; - format_pp.ctx.date_mode_explicit = format_rev.date_mode_explicit; - format_pp.ctx.date_mode = format_rev.date_mode; - format_pp.ctx.color = GIT_COLOR_AUTO; + get_commit_format(data.format, &data.rev); + format_pp.ctx.rev = &data.rev; + format_pp.ctx.fmt = data.rev.commit_format; + format_pp.ctx.abbrev = data.rev.abbrev; + format_pp.ctx.date_mode_explicit = data.rev.date_mode_explicit; + format_pp.ctx.date_mode = data.rev.date_mode; + format_pp.ctx.color = data.color; - userformat_find_requirements(format, + userformat_find_requirements(data.format, &format_pp.want); if (format_pp.want.notes) { int ignore_show_notes = 0; struct string_list_item *n; - for_each_string_list_item(n, ¬es) + for_each_string_list_item(n, &data.notes) enable_ref_display_notes(&format_notes_opt, &ignore_show_notes, n->string); @@ -933,8 +954,9 @@ int cmd_format_rev(int argc, BUG("uncovered case: %d", stdin_mode); } + date_mode_release(&data.rev.date_mode); strbuf_release(&scratch_buf); - string_list_clear(¬es, 0); + string_list_clear(&data.notes, 0); release_display_notes(&format_notes_opt); return 0; } diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index 7a7c46658a..a15da979ab 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -1017,4 +1017,62 @@ do ' done input <<-\EOF && + third + second + first + EOF + git -C repo-format log --stdin --no-walk \ + --format="$format" "$opts" >expect actual expect && + test_must_fail git -C repo-format format-rev \ + --stdin-mode=revs --format="$format" "$opts" 2>actual && + test_cmp expect actual +} + +test_expect_success 'format-rev --color' ' + format_rev_cmp_log --color=always && + format_rev_cmp_log --color && + format_rev_cmp_log --no-color && + format_rev_err_cmp_log --color=not-valid +' + +test_expect_success 'format-rev --abbrev' ' + format_rev_cmp_log --abbrev && + format_rev_cmp_log --abbrev=31 && + format_rev_cmp_log --no-abbrev +' + +test_expect_success 'format-rev --date' ' + format_rev_cmp_log --date=relative && + format_rev_cmp_log --date=iso-strict && + # This also tests the only case where we need to release + # the data for the parsed format + format_rev_cmp_log --date="format:%c" && + format_rev_err_cmp_log --date=not-valid && + # Test --date (no arg) next + # We cannot compare the output to git-log(1) + # because that command uses a slightly different + # error message (different library) + cat >expect <<-EOF && + error: option \`date${SQ} requires a value + EOF + test_must_fail git -C repo-format format-rev \ + --stdin-mode=revs --format="$format" --date 2>actual && + test_cmp expect actual +' + test_done