log: add %S option (like --source) to log --format
diff mbox series

Message ID 20190108132048.57142-1-issactrotts@google.com
State New
Headers show
Series
  • log: add %S option (like --source) to log --format
Related show

Commit Message

Issac Trotts Jan. 8, 2019, 1:20 p.m. UTC
From: Issac Trotts <issac.trotts@gmail.com>

Make it possible to write for example

        git log --format="%H,%S"

where the %S at the end is a new placeholder that prints out the ref
(tag/branch) for each commit.

Using %d might seem like an alternative but it only shows the ref for the last
commit in the branch.

Signed-off-by: Issac Trotts <issactrotts@google.com>

---

This change is based on a question from Stack Overflow:
https://stackoverflow.com/questions/12712775/git-get-source-information-in-format
---
 Documentation/pretty-formats.txt |  2 ++
 builtin/log.c                    |  2 +-
 log-tree.c                       |  1 +
 pretty.c                         | 14 +++++++++
 pretty.h                         |  1 +
 t/t4205-log-pretty-formats.sh    | 50 ++++++++++++++++++++++++++++++++
 t/t6006-rev-list-format.sh       |  4 +++
 7 files changed, 73 insertions(+), 1 deletion(-)

Comments

Junio C Hamano Jan. 8, 2019, 10:21 p.m. UTC | #1
issac.trotts@gmail.com writes:

> From: Issac Trotts <issac.trotts@gmail.com>

Heh, I'll edit this line to match S-o-b: below.

>
> Make it possible to write for example
>
>         git log --format="%H,%S"
>
> where the %S at the end is a new placeholder that prints out the ref
> (tag/branch) for each commit.
>
> Using %d might seem like an alternative but it only shows the ref for the last
> commit in the branch.
>
> Signed-off-by: Issac Trotts <issactrotts@google.com>
>
> ---



> diff --git a/log-tree.c b/log-tree.c
> index 10680c139..3cb14256e 100644
> --- a/log-tree.c
> +++ b/log-tree.c
> @@ -700,6 +700,7 @@ void show_log(struct rev_info *opt)
>  	ctx.color = opt->diffopt.use_color;
>  	ctx.expand_tabs_in_log = opt->expand_tabs_in_log;
>  	ctx.output_encoding = get_log_output_encoding();
> +	ctx.rev = opt;

There are quite a few existing codepaths that change their behaviour
based on NULL-ness of ctx.rev field.  How would we make sure that
this change have no unintended consequence, I wonder?

> +	case 'S':		/* tag/branch like --source */
> +		if (c->pretty_ctx->rev == NULL || c->pretty_ctx->rev->sources == NULL) {
> +			return 0;
> +		}
> +		slot = revision_sources_at(c->pretty_ctx->rev->sources, commit);
> +		if (!(slot && *slot)) {
> +			return 0;
> +		}
> +		strbuf_addstr(sb, *slot);
> +		return 1;

Let's update the style of this hunk here like so:

	if (!c->pretty_ctx->rev || !c->pretty_ctx->rev->sources)
		return 0;
	slot = ...;
	if (!(slot && *slot))
		return 0;
	strbuf_addstr(...);
	return 1;

I wonder if it is even better to apply de-Morgan to one of the above
two, i.e.

	if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
		return 0;


Anyway, thanks.  Will queue.
Issac Trotts Jan. 11, 2019, 6:28 a.m. UTC | #2
On Tue, Jan 8, 2019 at 2:21 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> issac.trotts@gmail.com writes:
>
> > From: Issac Trotts <issac.trotts@gmail.com>
>
> Heh, I'll edit this line to match S-o-b: below.

Thanks. Otherwise I have to set up git send-email again on my work laptop.

> > Make it possible to write for example
> >
> >         git log --format="%H,%S"
> >
> > where the %S at the end is a new placeholder that prints out the ref
> > (tag/branch) for each commit.
> >
> > Using %d might seem like an alternative but it only shows the ref for the last
> > commit in the branch.
> >
> > Signed-off-by: Issac Trotts <issactrotts@google.com>
> >
> > ---
>
>
>
> > diff --git a/log-tree.c b/log-tree.c
> > index 10680c139..3cb14256e 100644
> > --- a/log-tree.c
> > +++ b/log-tree.c
> > @@ -700,6 +700,7 @@ void show_log(struct rev_info *opt)
> >       ctx.color = opt->diffopt.use_color;
> >       ctx.expand_tabs_in_log = opt->expand_tabs_in_log;
> >       ctx.output_encoding = get_log_output_encoding();
> > +     ctx.rev = opt;
>
> There are quite a few existing codepaths that change their behaviour
> based on NULL-ness of ctx.rev field.  How would we make sure that
> this change have no unintended consequence, I wonder?
>
> > +     case 'S':               /* tag/branch like --source */
> > +             if (c->pretty_ctx->rev == NULL || c->pretty_ctx->rev->sources == NULL) {
> > +                     return 0;
> > +             }
> > +             slot = revision_sources_at(c->pretty_ctx->rev->sources, commit);
> > +             if (!(slot && *slot)) {
> > +                     return 0;
> > +             }
> > +             strbuf_addstr(sb, *slot);
> > +             return 1;
>
> Let's update the style of this hunk here like so:
>
>         if (!c->pretty_ctx->rev || !c->pretty_ctx->rev->sources)
>                 return 0;
>         slot = ...;
>         if (!(slot && *slot))
>                 return 0;
>         strbuf_addstr(...);
>         return 1;

Done.

>
> I wonder if it is even better to apply de-Morgan to one of the above
> two, i.e.
>
>         if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
>                 return 0;
>

Done.

>
> Anyway, thanks.  Will queue.
>

Sounds good. Btw, did you queue it yet? I didn't see it at the mirror:
https://github.com/git/git/commits/master.

I'll send out another patch with your suggestions, in case you haven't
already queued it.

Issac
Junio C Hamano Jan. 11, 2019, 5:37 p.m. UTC | #3
Issac Trotts <issac.trotts@gmail.com> writes:

> On Tue, Jan 8, 2019 at 2:21 PM Junio C Hamano <gitster@pobox.com> wrote:
>>
>> issac.trotts@gmail.com writes:
>>
>> > From: Issac Trotts <issac.trotts@gmail.com>
>>
>> Heh, I'll edit this line to match S-o-b: below.
>
> Thanks. Otherwise I have to set up git send-email again on my work laptop.

This in-body From: line is either (1) something you would write
yourself in your MUA, in which case you can just write your Google
address, or (2) the author identity a tool picks up and insert at
the body of the message for you, in which case you would make sure
that the commit is made under your Google identity (e.g. "commit
--amend --author=...").  Either case, I am not sure where the need
for send-email comes from.
Junio C Hamano Jan. 11, 2019, 5:47 p.m. UTC | #4
Issac Trotts <issac.trotts@gmail.com> writes:

> Sounds good. Btw, did you queue it yet? I didn't see it at the mirror:
> https://github.com/git/git/commits/master.

No patch goes to 'master' directly.  

Once we see that a patch is in reviewable shape during the mailing
list discussion, we wait for a few more days and unless there are
more issues to be addressed discovered during that period, it hits
the 'next' branch, and spends a week or so before graduating.

Before all of that happens, i.e. when a patch has not proven itself
'next'-worthy, I may pick it up to make trial merges in order to see
how it interacts with other proposed updates, which happens in the
'pu' (proposed updates) branch.  As there is only limited amount of
time in a day, this obviously cannot happen to all patches sent to
the list, but I try to cover as much as possible.

You'd find it as 5ca3af27 ("log: add %S option (like --source) to
log --format", 2019-01-09) on 'pu'.

Patch
diff mbox series

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 417b638cd..de6953108 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -134,6 +134,8 @@  The placeholders are:
 - '%cI': committer date, strict ISO 8601 format
 - '%d': ref names, like the --decorate option of linkgit:git-log[1]
 - '%D': ref names without the " (", ")" wrapping.
+- '%S': ref name given on the command line by which the commit was reached
+  (like `git log --source`), only works with `git log`
 - '%e': encoding
 - '%s': subject
 - '%f': sanitized subject line, suitable for a filename
diff --git a/builtin/log.c b/builtin/log.c
index e8e51068b..9deff32b8 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -203,7 +203,7 @@  static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
 	    rev->diffopt.filter || rev->diffopt.flags.follow_renames)
 		rev->always_show_header = 0;
 
-	if (source) {
+	if (source || w.source) {
 		init_revision_sources(&revision_sources);
 		rev->sources = &revision_sources;
 	}
diff --git a/log-tree.c b/log-tree.c
index 10680c139..3cb14256e 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -700,6 +700,7 @@  void show_log(struct rev_info *opt)
 	ctx.color = opt->diffopt.use_color;
 	ctx.expand_tabs_in_log = opt->expand_tabs_in_log;
 	ctx.output_encoding = get_log_output_encoding();
+	ctx.rev = opt;
 	if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
 		ctx.from_ident = &opt->from_ident;
 	if (opt->graph)
diff --git a/pretty.c b/pretty.c
index b83a3ecd2..06075d625 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1084,6 +1084,7 @@  static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	struct commit_list *p;
 	const char *arg;
 	int ch;
+	char **slot;
 
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
@@ -1194,6 +1195,16 @@  static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 		load_ref_decorations(NULL, DECORATE_SHORT_REFS);
 		format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
 		return 1;
+	case 'S':		/* tag/branch like --source */
+		if (c->pretty_ctx->rev == NULL || c->pretty_ctx->rev->sources == NULL) {
+			return 0;
+		}
+		slot = revision_sources_at(c->pretty_ctx->rev->sources, commit);
+		if (!(slot && *slot)) {
+			return 0;
+		}
+		strbuf_addstr(sb, *slot);
+		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
 		case 'd':	/* reflog selector */
@@ -1498,6 +1509,9 @@  static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
 	case 'N':
 		w->notes = 1;
 		break;
+	case 'S':
+		w->source = 1;
+		break;
 	}
 	return 0;
 }
diff --git a/pretty.h b/pretty.h
index 7359d318a..87ca5dfcb 100644
--- a/pretty.h
+++ b/pretty.h
@@ -60,6 +60,7 @@  static inline int cmit_fmt_is_mail(enum cmit_fmt fmt)
 
 struct userformat_want {
 	unsigned notes:1;
+	unsigned source:1;
 };
 
 /* Set the flag "w->notes" if there is placeholder %N in "fmt". */
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 978a8a66f..7df8c3d4e 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -621,4 +621,54 @@  test_expect_success 'trailer parsing not fooled by --- line' '
 	test_cmp expect actual
 '
 
+test_expect_success 'set up %S tests' '
+	git checkout --orphan source-a &&
+	test_commit one &&
+	test_commit two &&
+	git checkout -b source-b HEAD^ &&
+	test_commit three
+'
+
+test_expect_success 'log --format=%S paints branch names' '
+	cat >expect <<-\EOF &&
+	source-b
+	source-a
+	source-b
+	EOF
+	git log --format=%S source-a source-b >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --format=%S paints tag names' '
+	git tag -m tagged source-tag &&
+	cat >expect <<-\EOF &&
+	source-tag
+	source-a
+	source-tag
+	EOF
+	git log --format=%S source-tag source-a >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --format=%S paints symmetric ranges' '
+	cat >expect <<-\EOF &&
+	source-b
+	source-a
+	EOF
+	git log --format=%S source-a...source-b >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '%S in git log --format works with other placeholders (part 1)' '
+	git log --format="source-b %h" source-b >expect &&
+	git log --format="%S %h" source-b >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '%S in git log --format works with other placeholders (part 2)' '
+	git log --format="%h source-b" source-b >expect &&
+	git log --format="%h %S" source-b >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index ec42c2f77..da113d975 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -185,6 +185,10 @@  test_expect_success 'basic colors' '
 	test_cmp expect actual
 '
 
+test_expect_success '%S is not a placeholder for rev-list yet' '
+	git rev-list --format="%S" -1 master | grep "%S"
+'
+
 test_expect_success 'advanced colors' '
 	cat >expect <<-EOF &&
 	commit $head2