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

[PATCH v9a 5/5] Speed up log -L... -M

From
Thomas Rast <trast@student.ethz.ch>
Date
Mar 23, 2013, 06:44 UTC
Message-ID
<f9e5d31f6414ccd28399e468cbf10251659ee8cd.1364020899.git.trast@student.ethz.ch>
In-Reply-To
<cover.1364020899.git.trast@student.ethz.ch>

So far log -L only used the implicit diff filtering by pathspec. If the user specifies -M, we cannot do that, and so we simply handed the whole diff queue (which is approximately 'git show --raw') to diffcore_std().

Unfortunately this is very slow. We can optimize a lot if we throw out files that we know cannot possibly be interesting, in the same spirit that the pathspec filtering reduces the number of files.

However, in this case, we have to be more careful. Because we want to look out for renames, we need to keep all filepairs where something was deleted.

This is a bit hacky and should really be replaced by equivalent support in --follow, and just using that. However, in the meantime it speeds up 'log -M -L' by an order of magnitude.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
 line-log.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 52 insertions(+), 4 deletions(-)
diff --git a/line-log.c b/line-log.c
index 81c8d74..4327327 100644
--- a/line-log.c
+++ b/line-log.c
@@ -750,7 +750,50 @@ static void move_diff_queue(struct diff_queue_struct *dst,
 	DIFF_QUEUE_CLEAR(src);
 }
 
-static void queue_diffs(struct diff_options *opt,
+static void filter_diffs_for_paths(struct line_log_data *range, int keep_deletions)
+{
+	int i;
+	struct diff_queue_struct outq;
+	DIFF_QUEUE_CLEAR(&outq);
+
+	for (i = 0; i < diff_queued_diff.nr; i++) {
+		struct diff_filepair *p = diff_queued_diff.queue[i];
+		struct line_log_data *rg = NULL;
+
+		if (!DIFF_FILE_VALID(p->two)) {
+			if (keep_deletions)
+				diff_q(&outq, p);
+			else
+				diff_free_filepair(p);
+			continue;
+		}
+		for (rg = range; rg; rg = rg->next) {
+			if (!strcmp(rg->spec->path, p->two->path))
+				break;
+		}
+		if (rg)
+			diff_q(&outq, p);
+		else
+			diff_free_filepair(p);
+	}
+	free(diff_queued_diff.queue);
+	diff_queued_diff = outq;
+}
+
+static inline int diff_might_be_rename(void)
+{
+	int i;
+	for (i = 0; i < diff_queued_diff.nr; i++)
+		if (!DIFF_FILE_VALID(diff_queued_diff.queue[i]->one)) {
+			/* fprintf(stderr, "diff_might_be_rename found creation of: %s\n", */
+			/* 	diff_queued_diff.queue[i]->two->path); */
+			return 1;
+		}
+	return 0;
+}
+
+static void queue_diffs(struct line_log_data *range,
+			struct diff_options *opt,
 			struct diff_queue_struct *queue,
 			struct commit *commit, struct commit *parent)
 {
@@ -766,7 +809,12 @@ static void queue_diffs(struct diff_options *opt,
 
 	DIFF_QUEUE_CLEAR(&diff_queued_diff);
 	diff_tree(&desc1, &desc2, "", opt);
-	diffcore_std(opt);
+	if (opt->detect_rename) {
+		filter_diffs_for_paths(range, 1);
+		if (diff_might_be_rename())
+			diffcore_std(opt);
+		filter_diffs_for_paths(range, 0);
+	}
 	move_diff_queue(queue, &diff_queued_diff);
 
 	if (tree1)
@@ -1050,7 +1098,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
 	if (commit->parents)
 		parent = commit->parents->item;
 
-	queue_diffs(&rev->diffopt, &queue, commit, parent);
+	queue_diffs(range, &rev->diffopt, &queue, commit, parent);
 	changed = process_all_files(&parent_range, rev, &queue, range);
 	if (parent)
 		add_line_range(rev, parent, parent_range);
@@ -1075,7 +1123,7 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
 	for (i = 0; i < nparents; i++) {
 		parents[i] = p->item;
 		p = p->next;
-		queue_diffs(&rev->diffopt, &diffqueues[i], commit, parents[i]);
+		queue_diffs(range, &rev->diffopt, &diffqueues[i], commit, parents[i]);
 	}
 
 	for (i = 0; i < nparents; i++) {
-- 
1.8.2.235.g4032450
Previous: Thomas Rast
Message 8 of 8 in “git log -L”
  1. 0/5 git log -LThomas Rast, Mar 23, 2013
  2. 1/5 Refactor parse_locThomas Rast, Mar 23, 2013
  3. 2/5 Export rewrite_parents() for 'log -L'Thomas Rast, Mar 23, 2013
  4. 3/5 Implement line-history search (git log -L)Thomas Rast, Mar 23, 2013
  5. Antoine PelisseMar 23, 2013
  6. Antoine PelisseMar 23, 2013
  7. 4/5 log -L: :pattern:file syntax to find by funcnameThomas Rast, Mar 23, 2013
  8. 5/5 Speed up log -L... -MThomas Rast, Mar 23, 2013

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.