git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: "git shortlog -sn --follow -- <path>" counts all commits to entire repo

From
Jeff King <peff@peff.net>
Date
Sep 8, 2017, 05:10 UTC
Message-ID
<20170908051015.ybq4egdrddecl4se@sigill.intra.peff.net>
In-Reply-To
<CAGZ79kZAeCERKn6he2LzAj97BXEJ5U+Fy4sorAPNmW_XaCS9Vg@mail.gmail.com>
On Thu, Sep 07, 2017 at 12:30:01PM -0700, Stefan Beller wrote:
Show 10 quoted lines
> > "--follow" switch is not listed on
> > https://git-scm.com/docs/git-shortlog so maybe it's not supported. In
> > this case I would expect error message.
> >
> > Tried the following versions:
> > "git version 2.14.1.windows.1" on Windows 7
> > "git version 2.7.4" on Ubuntu 16.04
> 
> The shortlog takes most (all?) options that git-log
> does, e.g. in git.git:

That's definitely the intent, but I think --follow is just buggy here. We don't seem to trigger a diff, which is where "git log" does the follow check (because of the way it's bolted onto the diff, and not the actual pathspec-pruning mechanism).

Something like the patch below seems to work, but there are a lot of open questions. And it would probably want to do something to prevent nonsense like "shortlog -p" from showing actual diffs.

I suspect a better solution might involve actually building on log-tree.c to do the traversal (since this internal traversal is supposed to be equivalent to "git log | git shortlog").

diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 43c4799ea9..31274a92f5 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -175,8 +175,31 @@ static void get_from_rev(struct rev_info *rev, struct shortlog *log)
 
 	if (prepare_revision_walk(rev))
 		die(_("revision walk setup failed"));
-	while ((commit = get_revision(rev)) != NULL)
-		shortlog_add_commit(log, commit);
+	while ((commit = get_revision(rev)) != NULL) {
+		int show_commit;
+
+		/* trigger a diff to give --follow a chance to kick in */
+		if (!commit->parents) {
+			/* should diff against empty tree or respect --root? */
+			show_commit = 1;
+		} else if (commit->parents->next) {
+			/* how to handle merge commits? */
+			show_commit = 1;
+		} else {
+			struct commit *parent = commit->parents->item;
+
+			parse_commit_or_die(parent);
+			parse_commit_or_die(commit);
+			diff_tree_oid(&parent->tree->object.oid,
+				      &commit->tree->object.oid,
+				      "", &rev->diffopt);
+			show_commit = !diff_queue_is_empty();
+			diff_flush(&rev->diffopt);
+		}
+
+		if (show_commit)
+			shortlog_add_commit(log, commit);
+	}
 }
 
 static int parse_uint(char const **arg, int comma, int defval)
Previous: Stefan BellerNext: Junio C Hamano
Message 3 of 8 in “"git shortlog -sn --follow -- <path>" counts all commits to entire repo”
  1. ВалентинSep 7, 2017
  2. Stefan BellerSep 7, 2017
  3. Jeff KingSep 8, 2017
  4. Junio C HamanoSep 8, 2017
  5. Jeff KingSep 8, 2017
  6. Junio C HamanoSep 8, 2017
  7. Jeff KingSep 9, 2017
  8. Junio C HamanoSep 10, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.