log: add %S option (like --source) to log --format
PATCH 1/1 log: add %S option (like --source) to log --format
From: Issac Trotts <[email protected]>
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.
---
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 | 15 ++++++++++ pretty.h | 1 + t/t4205-log-pretty-formats.sh | 50 ++++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-)
Documentation/pretty-formats.txt +2 -0
@@ -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
builtin/log.c +1 -1
@@ -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 || (rev->pretty_given && (rev->commit_format ==CMIT_FMT_USERFORMAT ) && w.source)) {init_revision_sources (&revision_sources); rev->sources = &revision_sources; }
log-tree.c +1 -0
@@ -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)
pretty.c +15 -0
@@ -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,17 @@ 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->sources ==NULL ) { +return 0 ; + } + slot =revision_sources_at (c->pretty_ctx->rev->sources, commit); +if (slot && *slot) { +strbuf_addstr (sb, *slot); +return 1 ; + }else { +die (_ ("failed to get info for %%S" )); + }case 'g' :/* reflog info */ switch (placeholder[1 ]) {case 'd' :/* reflog selector */
@@ -1498,6 +1510,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 ; }
pretty.h +1 -0
@@ -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". */
t/t4205-log-pretty-formats.sh +50 -0
54 lines not on this page · raw message
Signature · 1 line
2.19.1
Hi all, friendly ping. Is there still interest in merging this patch?
Thanks,
Issac
Quoted 180 lines · On Wed, Dec 19, 2018 at 12:33 AM <[email protected]> wrote:
From: Issac Trotts <[email protected]>
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 <[email protected]>---
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 | 15 ++++++++++ pretty.h | 1 + t/t4205-log-pretty-formats.sh | 50 ++++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-)Documentation/pretty-formats.txt +2
-0@@ -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 filenamebuiltin/log.c +1
-1@@ -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 || (rev->pretty_given && (rev->commit_format ==CMIT_FMT_USERFORMAT ) && w.source)) {init_revision_sources (&revision_sources); rev->sources = &revision_sources; }log-tree.c +1
-0@@ -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)pretty.c +15
-0@@ -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,17 @@ 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->sources ==NULL ) { +return 0 ; + } + slot =revision_sources_at (c->pretty_ctx->rev->sources, commit); +if (slot && *slot) { +strbuf_addstr (sb, *slot); +return 1 ; + }else { +die (_ ("failed to get info for %%S" )); + }case 'g' :/* reflog info */ switch (placeholder[1 ]) {case 'd' :/* reflog selector */ @@ -1498,6 +1510,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 ; }pretty.h +1
-0@@ -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". */ t/t4205-log-pretty-formats.sh +50
-1@@ -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 --2.19.1
Quoted 1 line · Issac Trotts
Hi all, friendly ping. Is there still interest in merging this patch?
Yes, but I think people are largely absent for holidays at this point. If there hasn't been any movement on it, I'll try to review after Jan 5th (it also wouldn't hurt to re-post around then).
-Peff
Got it, sounds good.
Quoted 10 lines · Jeff King
Quoted 1 line · Issac Trotts
Hi all, friendly ping. Is there still interest in merging this patch?
Yes, but I think people are largely absent for holidays at this point. If there hasn't been any movement on it, I'll try to review after Jan 5th (it also wouldn't hurt to re-post around then).
-Peff
Quoted 32 lines · On 12/19/2018 3:33 AM, [email protected] wrote:
From: Issac Trotts <[email protected]>
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 <[email protected]>---
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 | 15 ++++++++++ pretty.h | 1 + t/t4205-log-pretty-formats.sh | 50 ++++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-)Documentation/pretty-formats.txt +0
-0
Documentation/pretty-formats.txt The placeholders are: · line 138
Quoted 5 lines
Documentation/pretty-formats.txt +2
-0@@ -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`
This "only works with git log" made me think about what would happen with git rev-list --pretty=format:"%h %S" and the answer (on my machine) was a segfault.
Quoted 8 lines
Documentation/pretty-formats.txt +0
-0- '%e': encoding - '%s': subject - '%f': sanitized subject line, suitable for a filenamebuiltin/log.c +0
-0
builtin/log.c static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, · line 209
Quoted 8 lines
builtin/log.c +1
-1@@ -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 || (rev->pretty_given && (rev->commit_format ==CMIT_FMT_USERFORMAT ) && w.source)) {init_revision_sources (&revision_sources); rev->sources = &revision_sources; }
Likely, you'll want to duplicate this initialization in the revision machinery. Keep this one in builtin/log.c as it was before, but add something like this initialization to setup_revisions(). Add a test for rev-list.
[snip]
builtin/log.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ · line 1199
Quoted 6 lines
builtin/log.c +2
-0@@ -1194,6 +1195,17 @@ 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->sources ==NULL ) {
Use "if (!c->pretty_ctx->rev->sources".
builtin/log.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ · line 1203
Quoted 4 lines
builtin/log.c +4
-0+return 0 ; + } + slot =revision_sources_at (c->pretty_ctx->rev->sources, commit); +if (slot && *slot) {
I'm not sure this check for 'slot' being non-null is necessary, as we would already get a failure in the commit-slab code (for revision_sources_at()) if the slab is not initialized.
builtin/log.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ · line 1207
Quoted 4 lines
builtin/log.c +4
-0+strbuf_addstr (sb, *slot); +return 1 ; + }else { +die (_ ("failed to get info for %%S" ));
Here, you die() when you fail to get a slot but above you return 0 when the sources are not initialized.
I don't see another use of die() in this method. Is that the right way to handle failure here? (I'm legitimately asking because I have over-used 'die()' in the past and am still unclear on when it is appropriate.)
Quoted 43 lines
builtin/log.c +41
-0' +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 &&
builtin/log.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
Quoted 10 lines
builtin/log.c +9
-0+ 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
Please also add a simple test to t6006-rev-list-format.sh.
Thanks,
-Stolee
Quoted 11 lines · Derrick Stolee
Documentation/pretty-formats.txt The placeholders are: · line 138
Quoted 7 lines
+++
b/Documentation/pretty-formats.txtDocumentation/pretty-formats.txt +2
-0@@ -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`This "only works with
git log" made me think about what would happen withgit rev-list --pretty=format:"%h %S"and the answer (on my machine) was a segfault.
That's a bad one X-<.
Quoted 13 lines
pretty.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ · line 1203
Quoted 2 lines
pretty.c +2
-0+ slot =revision_sources_at (c->pretty_ctx->rev->sources, commit); +if (slot && *slot) {I'm not sure this check for 'slot' being non-null is necessary, as we would already get a failure in the commit-slab code (for
revision_sources_at()) if the slab is not initialized.pretty.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ · line 1207
Quoted 4 lines
pretty.c +4
-0+strbuf_addstr (sb, *slot); +return 1 ; + }else { +die (_ ("failed to get info for %%S" ));Here, you
die()when you fail to get a slot but above you return 0 when the sources are not initialized.
Quoted 4 lines
I don't see another use of
die()in this method. Is that the right way to handle failure here? (I'm legitimately asking because I have over-used 'die()' in the past and am still unclear on when it is appropriate.)
This is definitely a bad one, too. If '%d' cannot find decoration, it would not "die".
Thanks.
Hi Derrick, thanks for your feedback.
I'll send out a new patch with the changes.
Quoted 29 lines · Derrick Stolee
Quoted 27 lines · On 12/19/2018 3:33 AM, [email protected] wrote:
From: Issac Trotts <[email protected]>
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 <[email protected]>---
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 | 15 ++++++++++ pretty.h | 1 + t/t4205-log-pretty-formats.sh | 50 ++++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-)
Quoted 14 lines
Documentation/pretty-formats.txt The placeholders are: · line 138
Quoted 10 lines
Documentation/pretty-formats.txt +2
-0@@ -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`This "only works with
git log" made me think about what would happen withgit rev-list --pretty=format:"%h %S"and the answer (on my machine) was a segfault.
Good find. Checking for c->pretty_ctx->rev == NULL prevents the seg fault.
Quoted 11 lines
Quoted 11 lines
Documentation/pretty-formats.txt +0
-0- '%e': encoding - '%s': subject - '%f': sanitized subject line, suitable for a filenamebuiltin/log.c +0
-0@@ -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;
Quoted 10 lines
builtin/log.c static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, · line 209
Quoted 5 lines
builtin/log.c +1
-1-if (source) { +if (source || (rev->pretty_given && (rev->commit_format ==CMIT_FMT_USERFORMAT ) && w.source)) {init_revision_sources (&revision_sources); rev->sources = &revision_sources; }Likely, you'll want to duplicate this initialization in the revision machinery. Keep this one in
builtin/log.cas it was before, but add something like this initialization tosetup_revisions(). Add a test for rev-list.
Okay, I added a test to check that rev-list leaves %S alone and implicitly that it doesn't segfault.
I'd like to limit the scope of this change to what's already here, with the check preventing the segfault, if that's okay. Could support for %S in rev-list be in a later patch?
Quoted 22 lines
[snip]
builtin/log.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ · line 1199
Quoted 6 lines
builtin/log.c +2
-0@@ -1194,6 +1195,17 @@ 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->sources ==NULL ) {Use "if (!c->pretty_ctx->rev->sources".
builtin/log.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ · line 1203
Quoted 4 lines
builtin/log.c +4
-0+return 0 ; + } + slot =revision_sources_at (c->pretty_ctx->rev->sources, commit); +if (slot && *slot) {I'm not sure this check for 'slot' being non-null is necessary, as we would already get a failure in the commit-slab code (for
revision_sources_at()) if the slab is not initialized.builtin/log.c static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ · line 1207
Quoted 4 lines
builtin/log.c +4
-0+strbuf_addstr (sb, *slot); +return 1 ; + }else { +die (_ ("failed to get info for %%S" ));
Quoted 7 lines
Here, you
die()when you fail to get a slot but above you return 0 when the sources are not initialized.I don't see another use of
die()in this method. Is that the right way to handle failure here? (I'm legitimately asking because I have over-used 'die()' in the past and am still unclear on when it is appropriate.)
Fixed.
Quoted 48 lines
Quoted 48 lines
builtin/log.c +45
-0' +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)' '
Quoted 8 lines
builtin/log.c
Quoted 6 lines
builtin/log.c +5
-0+ git log --format="%h source-b" source-b >expect && + git log --format="%h %S" source-b >actual && + test_cmp expect actual +' + test_donePlease also add a simple test to
t6006-rev-list-format.sh.
Done.
Quoted 5 lines
Thanks,
-Stolee