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

[PATCH/RFC 2/2] Make path-limiting be incremental when possible.

From
Linus Torvalds <torvalds@osdl.org>
Date
Mar 31, 2006, 01:05 UTC
Message-ID
<Pine.LNX.4.64.0603301652531.27203@g5.osdl.org>
In-Reply-To
<Pine.LNX.4.64.0603301648530.27203@g5.osdl.org>

This makes git-rev-list able to do path-limiting without having to parse all of history before it starts showing the results.

This makes it things like "git log -- pathname" much more pleasant to use.

This is actually a pretty small patch, and the biggest part of it is purely cleanups (turning the "goto next" statements into "continue"), but it's conceptually a lot bigger than it looks.

What it does is that if you do a path-limited revision list, and you do _not_ ask for pseudo-parenthood information, it won't do all the path-limiting up-front, but instead do it incrementally in "get_revision()".

This is an absolutely huge deal for anything like "git log -- <pathname>", but also for some things that we don't do yet - like the "find where things changed" logic I've described elsewhere, where we want to find the previous revision that changed a file.

The reason I put "RFC" in the subject line is that while I've validated it various ways, like doing

	git-rev-list HEAD -- drivers/char/ | md5sum 

before-and-after on the kernel archive, it's "git-rev-list" after all. In other words, it's that really really subtle and complex central piece of software. So while I think this is important and should go in asap, I also think it should get lots of testing and eyeballs looking at the code.

Btw, don't even bother testing this with the git archive. git itself is so small that parsing the whole revision history for it takes about a second even with path limiting. The thing that _really_ shows this off is doing

	git log drivers/
on the kernel archive, or even better, on the _historic_ kernel archive.

With this change, the response is instantaneous (although seeking to the end of the result will obviously take as long as it ever did). Before this change, the command would think about the result for tens of seconds - or even minutes, in the case of the bigger old kernel archive - before starting to output the results.

NOTE NOTE NOTE! Using path limiting with things like "gitk", which uses the "--parents" flag to actually generate a pseudo-history of the resulting commits won't actually see the improvement in interactivity, since that forces git-rev-list to do the whole-history thing after all.

MAYBE we can fix that too at some point, but I won't promise anything.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
diff --git a/revision.c b/revision.c
index 0330f9f..0e3f074 100644
--- a/revision.c
+++ b/revision.c
@@ -702,7 +702,13 @@ int setup_revisions(int argc, const char
 	if (revs->prune_data) {
 		diff_tree_setup_paths(revs->prune_data);
 		revs->prune_fn = try_to_simplify_commit;
-		revs->limited = 1;
+
+		/*
+		 * If we fix up parent data, we currently cannot
+		 * do that on-the-fly.
+		 */
+		if (revs->parents)
+			revs->limited = 1;
 	}
 
 	return left;
@@ -763,23 +769,32 @@ struct commit *get_revision(struct rev_i
 
 	do {
 		struct commit *commit = revs->commits->item;
+
+		revs->commits = revs->commits->next;
 
+		/*
+		 * If we haven't done the list limiting, we need to look at
+		 * the parents here
+		 */
+		if (!revs->limited)
+			add_parents_to_list(revs, commit, &revs->commits);
 		if (commit->object.flags & SHOWN)
-			goto next;
+			continue;
 		if (!(commit->object.flags & BOUNDARY) &&
 		    (commit->object.flags & UNINTERESTING))
-			goto next;
+			continue;
 		if (revs->min_age != -1 && (commit->date > revs->min_age))
-			goto next;
+			continue;
 		if (revs->max_age != -1 && (commit->date < revs->max_age))
 			return NULL;
 		if (revs->no_merges &&
 		    commit->parents && commit->parents->next)
-			goto next;
+			continue;
 		if (revs->prune_fn && revs->dense) {
 			if (!(commit->object.flags & TREECHANGE))
-				goto next;
-			rewrite_parents(commit);
+				continue;
+			if (revs->parents)
+				rewrite_parents(commit);
 		}
 		/* More to go? */
 		if (revs->max_count) {
@@ -792,13 +807,9 @@ struct commit *get_revision(struct rev_i
 				revs->commits = it->next;
 				free(it);
 			}
-			else
-				pop_most_recent_commit(&revs->commits, SEEN);
 		}
 		commit->object.flags |= SHOWN;
 		return commit;
-next:
-		pop_most_recent_commit(&revs->commits, SEEN);
 	} while (revs->commits);
 	return NULL;
 }
Previous: Linus TorvaldsNext: Linus Torvalds
Message 2 of 17 in “Move "--parent" parsing into generic revision.c library code”
  1. 1/2 Move "--parent" parsing into generic revision.c library codeLinus Torvalds, Mar 31, 2006
  2. 2/2 Make path-limiting be incremental when possible.Linus Torvalds, Mar 31, 2006
  3. Linus TorvaldsMar 31, 2006
  4. Junio C HamanoMar 31, 2006
  5. Linus TorvaldsMar 31, 2006
  6. Junio C HamanoMar 31, 2006
  7. Linus TorvaldsMar 31, 2006
  8. Junio C HamanoMar 31, 2006
  9. Linus TorvaldsMar 31, 2006
  10. Junio C HamanoMar 31, 2006
  11. Linus TorvaldsApr 2, 2006
  12. Junio C HamanoApr 2, 2006
  13. revision: simplify argument parsing.Junio C Hamano, Apr 2, 2006
  14. revision: --max-age alone does not need limit_list() anymore.Junio C Hamano, Apr 2, 2006
  15. Junio C HamanoMar 31, 2006
  16. Linus TorvaldsMar 31, 2006
  17. Junio C HamanoApr 3, 2006

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.