From: Junio C Hamano <junkio@cox.net>
To: git@vger.kernel.org
Cc: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Subject: [PATCH] (experimental) per-topic shortlog.
Date: Sun, 26 Nov 2006 16:44:18 -0800 [thread overview]
Message-ID: <7v8xhxsopp.fsf@assigned-by-dhcp.cox.net> (raw)
This implements an experimental "git log-fpc" command that shows
short-log style output sorted by topics.
A "topic" is identified by going through the first-parent
chains; this ignores the fast-forward case, but for a top-level
integrator it often is good enough.
For example, if the commit ancestry graph looks like this:
x---x---x---X---o---*---o---o---o HEAD
\ /
o---o---o---o---o
and the command line asks for
git log-fpc --no-merges X..
It first finds all the commits 'o'. Then it emits the four
commits on the upper line (assume the merge '*' has the commit
that is a child of X as its first parent in the picture). When
it does so, it the list of authors for these four commits on one
line, followed by the title of these commits. After that, it
does the same for the five commits on the lower line.
---
I initially wanted to do this inside Johannes's enhanced
shortlog, but ended up doing this as a pretty much independent
thing, because the shortlog implementation stringifies the
information from the commits too early to be easily enhanced for
this purpose.
If this turns out to be a better way to present shortlog,
however, this should become an option to git-shortlog.
A sample output from:
git log-fpc --no-merges v1.4.4.1..f64d7fd2
looks like this (f64d7fd2 was the tip of master when the last
"What's in" message was sent out). It shows that many "fixes"
and git-svn enhancements were directly done on "master" (that is
the first group), while many gitweb enhancements, changing the
output from "prune -n", "git branch" enhancements, etc. were
first cooked in separate topic branches and then later merged
into 'master'.
To this output, I can manually add a topic title to the
beginning of each group and it would make a better overview than
what I currently send out in "What's in" message which is
generated with shortlog.
----------------------------------------------------------------
Eric Wong (6), Junio C Hamano (5), Lars Hjemli, Jakub Narebski,
Iñaki Arenaza, Petr Baudis, Andy Parkins, and René Scharfe
git-fetch: exit with non-zero status when fast-forward check fails
git-svn: exit with status 1 for test failures
git-svn: correctly access repos when only given partial read permissions
git-branch -D: make it work even when on a yet-to-be-born branch
Add -v and --abbrev options to git-branch
git-clone: stop dumb protocol from copying refs outside heads/ and tags/.
gitweb: (style) use chomp without parentheses consistently.
gitweb: Replace SPC with also in tag comment
git-svn: handle authentication without relying on cached tokens on disk
git-cvsimport: add support for CVS pserver method HTTP/1.x proxying
Make git-clone --use-separate-remote the default
refs outside refs/{heads,tags} match less strongly.
Increase length of function name buffer
git-svn: preserve uncommitted changes after dcommit
git-svn: correctly handle revision 0 in SVN repositories
git-svn: error out from dcommit on a parent-less commit
archive-zip: don't use sizeof(struct ...)
Junio C Hamano and Andy Parkins
Typefix builtin-prune.c::prune_object()
Improve git-prune -n output
Peter Baumann
config option log.showroot to show the diff of root commits
Andy Parkins
Add support to git-branch to show local and remote branches
Jakub Narebski (7)
gitweb: Finish restoring "blob" links in git_difftree_body
gitweb: Refactor feed generation, make output prettier, add Atom feed
gitweb: Add an option to href() to return full URL
gitweb: New improved formatting of chunk header in diff
gitweb: Default to $hash_base or HEAD for $hash in "commit" and "commitdiff"
gitweb: Buffer diff header to deal with split patches + git_patchset_body refactoring
gitweb: Protect against possible warning in git_commitdiff
----------------------------------------------------------------
builtin-log.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
builtin.h | 1 +
git.c | 1 +
3 files changed, 179 insertions(+), 0 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index 7acf5d3..1c2838c 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -99,6 +99,183 @@ int cmd_log(int argc, const char **argv, const char *prefix)
return cmd_log_walk(&rev);
}
+/* bits #0..7 in revision.h, #8..11 in commit.c */
+#define FPC_RESULT (1u<<12)
+#define FPC_SHOWN (1u<<13)
+
+struct author_record {
+ char *name;
+ int count;
+};
+struct author_count {
+ int nr, alloc;
+ struct author_record **au;
+};
+
+static int cmp_count(const void *a_, const void *b_)
+{
+ struct author_record **a = (struct author_record **) a_;
+ struct author_record **b = (struct author_record **) b_;
+ return (*b)->count - (*a)->count;
+}
+
+static void add_author(struct commit *c, struct author_count *ac)
+{
+ const char *buf = c->buffer;
+ char *au = strstr(buf, "\nauthor ");
+ char *eon;
+ struct author_record *ar;
+ int i;
+
+ if (!au)
+ return; /* oops */
+ au += 7;
+ while (*au && isspace(*au))
+ au++;
+ if (!*au)
+ return; /* oops */
+ eon = strchr(au, '<');
+ if (!eon)
+ return; /* oops */
+ while (au < --eon && isspace(*eon))
+ ; /* back back back... */
+ eon++;
+ for (i = 0; i < ac->nr; i++)
+ if (!strncmp(ac->au[i]->name, au, eon-au) &&
+ strlen(ac->au[i]->name) == eon - au) {
+ /* found it */
+ ac->au[i]->count++;
+ return;
+ }
+ if (ac->alloc <= ac->nr) {
+ ac->alloc = alloc_nr(ac->alloc);
+ ac->au = xrealloc(ac->au, sizeof(struct author_record *) *
+ ac->alloc);
+ }
+ ar = xcalloc(1, sizeof(struct author_record));
+ ar->name = xmalloc(eon - au + 1);
+ memcpy(ar->name, au, eon - au);
+ ar->name[eon - au] = 0;
+ ar->count = 1;
+ ac->au[ac->nr++] = ar;
+}
+
+static void show_fpc(struct object_array *list)
+{
+ int i;
+ struct author_count ac;
+
+ if (!list->nr)
+ return;
+ memset(&ac, 0, sizeof(ac));
+ for (i = 0; i < list->nr; i++)
+ add_author((struct commit *) list->objects[i].item, &ac);
+ qsort(ac.au, ac.nr, sizeof(struct author_record *), cmp_count);
+
+ for (i = 0; i < ac.nr; i++) {
+ if (i) {
+ if (i < ac.nr - 1)
+ fputs(", ", stdout);
+ else if (ac.nr != 2)
+ fputs(", and ", stdout);
+ else
+ fputs(" and ", stdout);
+ }
+ if (ac.au[i]->count < 2)
+ printf("%s", ac.au[i]->name);
+ else
+ printf("%s (%d)", ac.au[i]->name, ac.au[i]->count);
+ free(ac.au[i]->name);
+ free(ac.au[i]);
+ }
+ free(ac.au);
+ putchar('\n');
+
+ for (i = 0; i < list->nr; i++) {
+ struct commit *c = (struct commit *) list->objects[i].item;
+ char *buf = c->buffer;
+ char *it = "<unnamed>";
+ int len = strlen(it);
+ buf = strstr(buf, "\n\n");
+ if (buf) {
+ char *lineend;
+ while (*buf && isspace(*buf))
+ buf++;
+ if (!*buf)
+ goto emit;
+ lineend = strchr(buf, '\n');
+ if (!lineend)
+ goto emit;
+ while (buf < lineend && isspace(*lineend))
+ lineend--;
+ len = lineend - buf + 1;
+ it = buf;
+ }
+ emit:
+ printf(" %.*s\n", len, it);
+ }
+ putchar('\n');
+}
+
+int cmd_log_fpc(int argc, const char **argv, const char *prefix)
+{
+ struct rev_info rev;
+ struct commit *c;
+ struct object_array result = { 0, 0, NULL };
+ int i;
+
+ git_config(git_log_config);
+ init_revisions(&rev, prefix);
+ rev.always_show_header = 1;
+ cmd_log_init(argc, argv, prefix, &rev);
+
+ prepare_revision_walk(&rev);
+ while ((c = get_revision(&rev)) != NULL)
+ add_object_array(&(c->object), NULL, &result);
+
+ /* clear flags and mark them "relevant" */
+ for (i = 0; i < result.nr; i++)
+ result.objects[i].item->flags |= FPC_RESULT;
+
+ for (;;) {
+ struct object_array current;
+
+ for (i = 0; i < result.nr; i++) {
+ if (!(result.objects[i].item->flags & FPC_SHOWN))
+ break;
+ }
+ if (i >= result.nr)
+ break;
+
+ memset(¤t, 0, sizeof(current));
+ c = (struct commit *) result.objects[i].item;
+ while (c) {
+ int flags = c->object.flags;
+
+ if ((flags & (FPC_RESULT|FPC_SHOWN)) == FPC_RESULT) {
+ add_object_array(&(c->object), NULL, ¤t);
+ c->object.flags |= FPC_SHOWN;
+ }
+ if (!c->object.parsed)
+ parse_object(c->object.sha1);
+ if (!c->parents)
+ break;
+ c = c->parents->item;
+ }
+
+ /* Finally, show the series. */
+ show_fpc(¤t);
+ }
+
+ /* free them */
+ for (i = 0; i < result.nr; i++) {
+ c = (struct commit *) result.objects[i].item;
+ free(c->buffer);
+ free_commit_list(c->parents);
+ }
+ return 0;
+}
+
static int istitlechar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
diff --git a/builtin.h b/builtin.h
index 43fed32..a94540d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -38,6 +38,7 @@ extern int cmd_grep(int argc, const char **argv, const char *prefix);
extern int cmd_help(int argc, const char **argv, const char *prefix);
extern int cmd_init_db(int argc, const char **argv, const char *prefix);
extern int cmd_log(int argc, const char **argv, const char *prefix);
+extern int cmd_log_fpc(int argc, const char **argv, const char *prefix);
extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
diff --git a/git.c b/git.c
index 1aa07a5..65d98bd 100644
--- a/git.c
+++ b/git.c
@@ -243,6 +243,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "help", cmd_help },
{ "init-db", cmd_init_db },
{ "log", cmd_log, RUN_SETUP | USE_PAGER },
+ { "log-fpc", cmd_log_fpc, RUN_SETUP | USE_PAGER },
{ "ls-files", cmd_ls_files, RUN_SETUP },
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
{ "mailinfo", cmd_mailinfo },
--
1.4.4.1.ge3fb
next reply other threads:[~2006-11-27 0:44 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-11-27 0:44 Junio C Hamano [this message]
2006-11-27 1:06 ` [PATCH] (experimental) per-topic shortlog Linus Torvalds
2006-11-27 1:38 ` Junio C Hamano
2006-11-27 1:53 ` Linus Torvalds
2006-11-27 1:55 ` Junio C Hamano
2006-11-27 2:52 ` Linus Torvalds
2006-11-27 6:48 ` Junio C Hamano
2006-11-27 16:20 ` Linus Torvalds
2006-11-27 23:46 ` Johannes Schindelin
2006-11-28 0:09 ` Junio C Hamano
2006-11-28 13:11 ` Jeff King
2006-11-28 13:43 ` Johannes Schindelin
2006-11-28 13:56 ` Jeff King
2006-11-29 0:57 ` Junio C Hamano
2006-12-01 8:11 ` Jeff King
2006-12-01 10:55 ` Junio C Hamano
2006-12-01 11:00 ` Junio C Hamano
2006-12-01 11:23 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7v8xhxsopp.fsf@assigned-by-dhcp.cox.net \
--to=junkio@cox.net \
--cc=Johannes.Schindelin@gmx.de \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).