threads / rfc / 43231

Re: [RFC] Possible optimization for gitweb

Subject: Re: [RFC] Possible optimization for gitweb

## tl;dr

8 messages between Dec 19, 2006 and Dec 20, 2006.

replies: 7people: 3as markdown or json

Robert Fitzsimons· Dec 19, 2006, 20:54 UTC · lore

[RFC] Possible optimization for gitweb

While looking at the gitweb source yesterday, I noticed a number of similar expensive workflows used by a number of actions (summary, shortlog, log, rss, atom, and history).

The current workflows are:
	get ~100 sha1's using rev-list
	foreach sha1
		get/parse 1 commit using rev-list
		output commit
The new workflows I'm proposing would be:
	get/parse ~100 commit's using rev-list
	foreach commit
		output commit

The following simplified commands gives an idea of the git only overhead between these two workflows.

time \ for r in `git-rev-list --max-count=100 HEAD --` ; \ do git-rev-list --header --parents --max-count=1 $r -- ; \ done > /dev/null

real 0m0.490s user 0m0.224s sys 0m0.228s

time \ git-rev-list --header --parents --max-count=100 HEAD -- > /dev/null

real 0m0.058s user 0m0.008s sys 0m0.004s

There would seems to be a benefit from making the proposed change to these workflows, when run on my machine against a clone of Linus's tree.

One issue with this change is that, gitweb is page orientated. Page 0 shows the first 100 items from a given hash, page 1 uses the same given hash but show 100 to 199 items, etc. Using 'git-rev-list --header --parents' and then throwing away most of the result is very wasteful.

So I'm suggesting we add a new option to git-rev-list which will only start show results once its has iterated past a given number of items. Using a caret or tilde doesn't seem to return the same result.

I've attached a discussion patch which adds a new option --start-count to git-rev-list and changed the summary and showlog actions of gitweb to use this new option.

I'm sure there are many improvements to this patch, comments?
Robert
-----
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 4059894..a1e0ccc 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1260,6 +1260,30 @@ sub parse_tag {
 	return %tag
 }
 
+sub parse_commits {
+	my $commit_id = shift;
+	my $start_count = shift;
+	my $max_count = shift;
+
+	my @cos;
+	my @commit_lines;
+
+	local $/ = "\0";
+	open my $fd, "-|", git_cmd(), "rev-list",
+		"--header", "--parents", "--start-count=$start_count", "--max-count=$max_count",
+		$commit_id, "--"
+		or return;
+	while (my $commit = <$fd>) {
+		@commit_lines = split '\n', $commit;
+		pop @commit_lines;
+		my %co = parse_commit(undef, \@commit_lines);
+		push @cos, \%co;
+	}
+	close $fd or return;
+
+	return @cos;
+}
+
 sub parse_commit {
 	my $commit_id = shift;
 	my $commit_text = shift;
@@ -2633,29 +2657,29 @@ sub git_project_list_body {
 
 sub git_shortlog_body {
 	# uses global variable $project
-	my ($revlist, $from, $to, $refs, $extra) = @_;
+	my ($commitlist, $from, $to, $refs, $extra) = @_;
 
 	$from = 0 unless defined $from;
-	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
+	$to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
 
 	print "<table class=\"shortlog\" cellspacing=\"0\">\n";
 	my $alternate = 1;
 	for (my $i = $from; $i <= $to; $i++) {
-		my $commit = $revlist->[$i];
+		my $co = $commitlist->[$i];
+		my $commit = $co->{'id'};
 		#my $ref = defined $refs ? format_ref_marker($refs, $commit) : '';
 		my $ref = format_ref_marker($refs, $commit);
-		my %co = parse_commit($commit);
 		if ($alternate) {
 			print "<tr class=\"dark\">\n";
 		} else {
 			print "<tr class=\"light\">\n";
 		}
 		$alternate ^= 1;
-		# git_summary() used print "<td><i>$co{'age_string'}</i></td>\n" .
-		print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
-		      "<td><i>" . esc_html(chop_str($co{'author_name'}, 10)) . "</i></td>\n" .
+		# git_summary() used print "<td><i>$co->{'age_string'}</i></td>\n" .
+		print "<td title=\"$co->{'age_string_age'}\"><i>$co->{'age_string_date'}</i></td>\n" .
+		      "<td><i>" . esc_html(chop_str($co->{'author_name'}, 10)) . "</i></td>\n" .
 		      "<td>";
-		print format_subject_html($co{'title'}, $co{'title_short'},
+		print format_subject_html($co->{'title'}, $co->{'title_short'},
 		                          href(action=>"commit", hash=>$commit), $ref);
 		print "</td>\n" .
 		      "<td class=\"link\">" .
@@ -2952,13 +2976,9 @@ sub git_summary {
 		}
 	}
 
-	open my $fd, "-|", git_cmd(), "rev-list", "--max-count=17",
-		git_get_head_hash($project), "--"
-		or die_error(undef, "Open git-rev-list failed");
-	my @revlist = map { chomp; $_ } <$fd>;
-	close $fd;
+	my @commitlist = parse_commits($head, 0, 17);
 	git_print_header_div('shortlog');
-	git_shortlog_body(\@revlist, 0, 15, $refs,
+	git_shortlog_body(\@commitlist, 0, 15, $refs,
 	                  $cgi->a({-href => href(action=>"shortlog")}, "..."));
 
 	if (@taglist) {
@@ -4313,15 +4333,12 @@ sub git_shortlog {
 	}
 	my $refs = git_get_references();
 
-	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
-	open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash, "--"
-		or die_error(undef, "Open git-rev-list failed");
-	my @revlist = map { chomp; $_ } <$fd>;
-	close $fd;
+	my $max_count = (100 * ($page+1));
+	my @commitlist = parse_commits($hash, (100 * $page), $max_count);
 
-	my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, $#revlist);
+	my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, $max_count);
 	my $next_link = '';
-	if ($#revlist >= (100 * ($page+1)-1)) {
+	if ($max_count >= 100) {
 		$next_link =
 			$cgi->a({-href => href(action=>"shortlog", hash=>$hash, page=>$page+1),
 			         -title => "Alt-n"}, "next");
@@ -4332,7 +4349,7 @@ sub git_shortlog {
 	git_print_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
 	git_print_header_div('summary', $project);
 
-	git_shortlog_body(\@revlist, ($page * 100), $#revlist, $refs, $next_link);
+	git_shortlog_body(\@commitlist, 0, $#commitlist, $refs, $next_link);
 
 	git_footer_html();
 }
diff --git a/list-objects.c b/list-objects.c
index f1fa21c..d96c8bf 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -108,8 +108,12 @@ void traverse_commit_list(struct rev_info *revs,
 	struct object_array objects = { 0, 0, NULL };
 
 	while ((commit = get_revision(revs)) != NULL) {
-		process_tree(revs, commit->tree, &objects, NULL, "");
-		show_commit(commit);
+		if (revs->start_count <= 0) {
+			process_tree(revs, commit->tree, &objects, NULL, "");
+			show_commit(commit);
+		} else {
+			revs->start_count--;
+		}
 	}
 	for (i = 0; i < revs->pending.nr; i++) {
 		struct object_array_entry *pending = revs->pending.objects + i;
diff --git a/revision.c b/revision.c
index 993bb66..3e3d929 100644
--- a/revision.c
+++ b/revision.c
@@ -524,6 +524,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
 	revs->prefix = prefix;
 	revs->max_age = -1;
 	revs->min_age = -1;
+	revs->start_count = -1;
 	revs->max_count = -1;
 
 	revs->prune_fn = NULL;
@@ -756,6 +757,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 		const char *arg = argv[i];
 		if (*arg == '-') {
 			int opts;
+			if (!strncmp(arg, "--start-count=", 14)) {
+				revs->start_count = atoi(arg + 14);
+				continue;
+			}
 			if (!strncmp(arg, "--max-count=", 12)) {
 				revs->max_count = atoi(arg + 12);
 				continue;
diff --git a/revision.h b/revision.h
index 3adab95..c2dce8c 100644
--- a/revision.h
+++ b/revision.h
@@ -75,6 +75,7 @@ struct rev_info {
 	struct grep_opt	*grep_filter;
 
 	/* special limits */
+	int start_count;
 	int max_count;
 	unsigned long max_age;
Jakub Narebski· Dec 19, 2006, 21:45 UTC · re: Robert Fitzsimons · lore
[Please send replies Cc: git mailing list]
Robert Fitzsimons wrote:
Show 14 quoted lines
> While looking at the gitweb source yesterday, I noticed a number of
> similar expensive workflows used by a number of actions (summary,
> shortlog, log, rss, atom, and history).
> 
> The current workflows are:
>       get ~100 sha1's using rev-list
>       foreach sha1
>               get/parse 1 commit using rev-list
>               output commit
> 
> The new workflows I'm proposing would be:
>       get/parse ~100 commit's using rev-list
>       foreach commit
>               output commit
I have tried this approach too. Take a look at
  http://repo.or.cz/w/git/jnareb-git.git?a=log;h=Attic/gitweb/parse_rev_list
or at discussion started with
  Message-Id: <200609061504.40725.jnareb@gmail.com>
  http://mid.gmane.org/200609061504.40725.jnareb@gmail.com
Show 21 quoted lines
> The following simplified commands gives an idea of the git only overhead
> between these two workflows.
> 
> time \
> for r in `git-rev-list --max-count=100 HEAD --` ; \
> do git-rev-list --header --parents --max-count=1 $r -- ; \
> done > /dev/null
> 
> real    0m0.490s
> user    0m0.224s
> sys     0m0.228s
> 
> time \
> git-rev-list --header --parents --max-count=100 HEAD -- > /dev/null
> 
> real    0m0.058s
> user    0m0.008s
> sys     0m0.004s
> 
> There would seems to be a benefit from making the proposed change to
> these workflows, when run on my machine against a clone of Linus's tree.

The problem is that it works only for "log" and "shortlog" views, but it doesn't work for "history" view. Now both share the same infrastructure. The problem is that when there is path limiter (be it file or directory) the history is simplified, and parents are _rewritten_ according to simplified history. And this happen depending on strange combination of --header, --parents and --full-history. Should be somewhere in archives.

And we don't want to use parents from commit object, because there might be grafts, or it might be shallow clone.

On the other hand, we don't really need parents for log, shortlog and history...

Show 12 quoted lines
> One issue with this change is that, gitweb is page orientated.  Page 0
> shows the first 100 items from a given hash, page 1 uses the same given
> hash but show 100 to 199 items, etc.  Using 'git-rev-list --header
> --parents' and then throwing away most of the result is very wasteful.
> 
> So I'm suggesting we add a new option to git-rev-list which will only
> start show results once its has iterated past a given number of items.
> Using a caret or tilde doesn't seem to return the same result.
> 
> I've attached a discussion patch which adds a new option --start-count
> to git-rev-list and changed the summary and showlog actions of gitweb to
> use this new option.
Very nice idea.
 
> I'm sure there are many improvements to this patch, comments?

Perhaps this patch should be split in two? (Usually either second mail is reply to first mail, or both are replies to introductory letter, usually with table of contents and diffstat of series).

[...]
Documentation (of --start-count / --skip option), please?
P.S. Thanks for the patches.

P.P.S. Do you have any comments to latest "[RFC] gitweb wishlist and TODO list" series?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Junio C Hamano· Dec 19, 2006, 22:10 UTC · re: Robert Fitzsimons · lore
Robert Fitzsimons <robfitz@273k.net> writes:
> The new workflows I'm proposing would be:
> 	get/parse ~100 commit's using rev-list
> 	foreach commit
> 		output commit
Absolutely.

And Ok on rev-list part, but perhaps --skip would be more appropriate name.

Jakub Narebski· Dec 19, 2006, 22:22 UTC · re: Junio C Hamano · lore
[Please Cc: git@vger.kernel.org]
Junio C Hamano wrote:
Show 11 quoted lines
> Robert Fitzsimons <robfitz@273k.net> writes:
> 
>> The new workflows I'm proposing would be:
>>      get/parse ~100 commit's using rev-list
>>      foreach commit
>>              output commit
> 
> Absolutely.
> 
> And Ok on rev-list part, but perhaps --skip would be more
> appropriate name.

The only problem that you can't use --parents with "history" view, because together with --full-history it shows also all merges (--full-history without --parents doesn't show merges which does not affect given file or directory; the sequence in which --parents and --full-history are taken is a bit strange to me). So you have to keep current parse_commit (or extend it), and if I remember correctly you do that.

I'm also for --skip (not --start-count), although... --start-count with --max-count seems more natural; one place it can be confusing is that we count skipped commits or not? I.e. we use --start-count=10 --max-count=20 to get second 10 of commits, or --skip=10 --max-count=10 to get second 10 of commits?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Robert Fitzsimons· Dec 20, 2006, 00:29 UTC · re: Jakub Narebski · lore

[PATCH] rev-list: Add a new option --skip.

Added a new option --skip=<N> which is used to allow the caller to specify how many commit items to skip before displaying the commit output. This option is most useful for programs which want to display fixed length pages of commit items, i.e. gitweb.

Signed-off-by: Robert Fitzsimons <robfitz@273k.net>
---
Show 5 quoted lines
> I'm also for --skip (not --start-count), although... --start-count with
> --max-count seems more natural; one place it can be confusing is that we
> count skipped commits or not? I.e. we use --start-count=10 --max-count=20
> to get second 10 of commits, or --skip=10 --max-count=10 to get second 10
> of commits?

Here's the patch with the renamed option. It also does not count skipped commits, so --skip=10 --max-count=10 will display 10 items.

Robert
 Documentation/git-rev-list.txt |    5 +++++
 builtin-rev-list.c             |   17 +++++++++++++++++
 list-objects.c                 |    8 ++++++--
 revision.c                     |    1 +
 revision.h                     |    1 +
 5 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index ec43c0b..7c86abc 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -12,6 +12,7 @@ SYNOPSIS
 'git-rev-list' [ \--max-count=number ]
 	     [ \--max-age=timestamp ]
 	     [ \--min-age=timestamp ]
+	     [ \--skip=number ]
 	     [ \--sparse ]
 	     [ \--no-merges ]
 	     [ \--remove-empty ]
@@ -151,6 +152,10 @@ limiting may be applied.
 
 	Limit the commits output to specified time range.
 
+--skip='number'::
+
+	Skip 'number' commits before starting to display commit output.
+
 --author='pattern', --committer='pattern'::
 
 	Limit the commits output to ones with author/committer
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index fb7fc92..432f901 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -20,6 +20,7 @@ static const char rev_list_usage[] =
 "    --max-count=nr\n"
 "    --max-age=epoch\n"
 "    --min-age=epoch\n"
+"    --skip=nr\n"
 "    --sparse\n"
 "    --no-merges\n"
 "    --remove-empty\n"
@@ -219,6 +220,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 	struct commit_list *list;
 	int i;
 	int read_from_stdin = 0;
+	int skip = -1;
 
 	init_revisions(&revs, prefix);
 	revs.abbrev = 0;
@@ -246,6 +248,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 			read_revisions_from_stdin(&revs);
 			continue;
 		}
+		if (!strncmp(arg, "--skip=", 7)) {
+			skip = atoi(arg + 7);
+			continue;
+		}
 		usage(rev_list_usage);
 
 	}
@@ -261,6 +267,17 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 		/* Only --header was specified */
 		revs.commit_format = CMIT_FMT_RAW;
 
+	/*
+	 * If a skip value is specified set start_count appropriately,
+	 * and if max_count is set it should be adjusted to account
+	 * for the skip value.
+	 */
+	if (skip > 0) {
+		revs.start_count = skip;
+		if (revs.max_count > 0)
+			revs.max_count += skip;
+	}
+
 	list = revs.commits;
 
 	if ((!list &&
diff --git a/list-objects.c b/list-objects.c
index f1fa21c..d96c8bf 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -108,8 +108,12 @@ void traverse_commit_list(struct rev_info *revs,
 	struct object_array objects = { 0, 0, NULL };
 
 	while ((commit = get_revision(revs)) != NULL) {
-		process_tree(revs, commit->tree, &objects, NULL, "");
-		show_commit(commit);
+		if (revs->start_count <= 0) {
+			process_tree(revs, commit->tree, &objects, NULL, "");
+			show_commit(commit);
+		} else {
+			revs->start_count--;
+		}
 	}
 	for (i = 0; i < revs->pending.nr; i++) {
 		struct object_array_entry *pending = revs->pending.objects + i;
diff --git a/revision.c b/revision.c
index 993bb66..70f4861 100644
--- a/revision.c
+++ b/revision.c
@@ -524,6 +524,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
 	revs->prefix = prefix;
 	revs->max_age = -1;
 	revs->min_age = -1;
+	revs->start_count = -1;
 	revs->max_count = -1;
 
 	revs->prune_fn = NULL;
diff --git a/revision.h b/revision.h
index 3adab95..c2dce8c 100644
--- a/revision.h
+++ b/revision.h
@@ -75,6 +75,7 @@ struct rev_info {
 	struct grep_opt	*grep_filter;
 
 	/* special limits */
+	int start_count;
 	int max_count;
 	unsigned long max_age;
 	unsigned long min_age;
-- 
1.4.4.2.g80fef-dirty
Junio C Hamano· Dec 20, 2006, 01:09 UTC · re: Robert Fitzsimons · lore

Re: [PATCH] rev-list: Add a new option --skip.

Robert Fitzsimons <robfitz@273k.net> writes:
Show 15 quoted lines
> diff --git a/builtin-rev-list.c b/builtin-rev-list.c
> index fb7fc92..432f901 100644
> --- a/builtin-rev-list.c
> +++ b/builtin-rev-list.c
> @@ -246,6 +248,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
>  			read_revisions_from_stdin(&revs);
>  			continue;
>  		}
> +		if (!strncmp(arg, "--skip=", 7)) {
> +			skip = atoi(arg + 7);
> +			continue;
> +		}
>  		usage(rev_list_usage);
>  
>  	}
Hmph....

I am having a hard time convincing myself that this is a feature that is a narrow special case for rev-list and does not belong to the generic revision traversal machinery.

That is, would people expect that 'log' family allow the to say:
	$ git log --skip=10 -4 master

Declaring this as a special case for rev-list is certainly safer (no risk to harm the revision machinery which is quite central part of git), but if you define and initialize the new field next to max_count, it makes me feel that it should somehow be handled at the same layer.

In other words,...
---
 revision.c |   46 ++++++++++++++++++++++++++++++++--------------
 revision.h |    1 +
 2 files changed, 33 insertions(+), 14 deletions(-)
diff --git a/revision.c b/revision.c
index 993bb66..aa63d10 100644
--- a/revision.c
+++ b/revision.c
@@ -524,6 +524,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
 	revs->prefix = prefix;
 	revs->max_age = -1;
 	revs->min_age = -1;
+	revs->skip_count = -1;
 	revs->max_count = -1;
 
 	revs->prune_fn = NULL;
@@ -760,6 +761,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 				revs->max_count = atoi(arg + 12);
 				continue;
 			}
+			if (!strncmp(arg, "--skip=", 7)) {
+				revs->skip_count = atoi(arg + 7);
+				continue;
+			}
 			/* accept -<digit>, like traditional "head" */
 			if ((*arg == '-') && isdigit(arg[1])) {
 				revs->max_count = atoi(arg + 1);
@@ -1123,23 +1128,11 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
 			   commit->buffer, strlen(commit->buffer));
 }
 
-struct commit *get_revision(struct rev_info *revs)
+static struct commit *get_revision_1(struct rev_info *revs)
 {
-	struct commit_list *list = revs->commits;
-
-	if (!list)
+	if (!revs->commits)
 		return NULL;
 
-	/* Check the max_count ... */
-	switch (revs->max_count) {
-	case -1:
-		break;
-	case 0:
-		return NULL;
-	default:
-		revs->max_count--;
-	}
-
 	do {
 		struct commit_list *entry = revs->commits;
 		struct commit *commit = entry->item;
@@ -1206,3 +1199,28 @@ struct commit *get_revision(struct rev_info *revs)
 	} while (revs->commits);
 	return NULL;
 }
+
+struct commit *get_revision(struct rev_info *revs)
+{
+	struct commit *c = NULL;
+
+	if (0 < revs->skip_count) {
+		while ((c = get_revision_1(revs)) != NULL) {
+			if (revs->skip_count-- <= 0)
+				break;
+		}
+	}
+
+	/* Check the max_count ... */
+	switch (revs->max_count) {
+	case -1:
+		break;
+	case 0:
+		return NULL;
+	default:
+		revs->max_count--;
+	}
+	if (c)
+		return c;
+	return get_revision_1(revs);
+}
diff --git a/revision.h b/revision.h
index 3adab95..81f522c 100644
--- a/revision.h
+++ b/revision.h
@@ -75,6 +75,7 @@ struct rev_info {
 	struct grep_opt	*grep_filter;
 
 	/* special limits */
+	int skip_count;
 	int max_count;
 	unsigned long max_age;
 	unsigned long min_age;
Robert Fitzsimons· Dec 20, 2006, 14:59 UTC · re: Junio C Hamano · lore

[PATCH] rev-list: Document --skip and add test cases.

Signed-off-by: Robert Fitzsimons <robfitz@273k.net>
---
> I am having a hard time convincing myself that this is a feature
> that is a narrow special case for rev-list and does not belong
> to the generic revision traversal machinery.

Your implementation is much better then mine. Here's some documentation and a set of test cases.

Robert
 Documentation/git-rev-list.txt |    5 ++++
 t/t6005-rev-list-count.sh      |   51 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index ec43c0b..9e0dcf8 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -10,6 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git-rev-list' [ \--max-count=number ]
+	     [ \--skip=number ]
 	     [ \--max-age=timestamp ]
 	     [ \--min-age=timestamp ]
 	     [ \--sparse ]
@@ -139,6 +140,10 @@ limiting may be applied.
 
 	Limit the number of commits output.
 
+--skip='number'::
+
+	Skip 'number' commits before starting to show the commit output.
+
 --since='date', --after='date'::
 
 	Show commits more recent than a specific date.
diff --git a/t/t6005-rev-list-count.sh b/t/t6005-rev-list-count.sh
new file mode 100755
index 0000000..334fccf
--- /dev/null
+++ b/t/t6005-rev-list-count.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+test_description='git-rev-list --max-count and --skip test'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+    for n in 1 2 3 4 5 ; do \
+        echo $n > a ; \
+        git add a ; \
+        git commit -m "$n" ; \
+    done
+'
+
+test_expect_success 'no options' '
+    test $(git-rev-list HEAD | wc -l) = 5
+'
+
+test_expect_success '--max-count' '
+    test $(git-rev-list HEAD --max-count=0 | wc -l) = 0 &&
+    test $(git-rev-list HEAD --max-count=3 | wc -l) = 3 &&
+    test $(git-rev-list HEAD --max-count=5 | wc -l) = 5 &&
+    test $(git-rev-list HEAD --max-count=10 | wc -l) = 5
+'
+
+test_expect_success '--max-count all forms' '
+    test $(git-rev-list HEAD --max-count=1 | wc -l) = 1 &&
+    test $(git-rev-list HEAD -1 | wc -l) = 1 &&
+    test $(git-rev-list HEAD -n1 | wc -l) = 1 &&
+    test $(git-rev-list HEAD -n 1 | wc -l) = 1
+'
+
+test_expect_success '--skip' '
+    test $(git-rev-list HEAD --skip=0 | wc -l) = 5 &&
+    test $(git-rev-list HEAD --skip=3 | wc -l) = 2 &&
+    test $(git-rev-list HEAD --skip=5 | wc -l) = 0 &&
+    test $(git-rev-list HEAD --skip=10 | wc -l) = 0
+'
+
+test_expect_success '--skip --max-count' '
+    test $(git-rev-list HEAD --skip=0 --max-count=0 | wc -l) = 0 &&
+    test $(git-rev-list HEAD --skip=0 --max-count=10 | wc -l) = 5 &&
+    test $(git-rev-list HEAD --skip=3 --max-count=0 | wc -l) = 0 &&
+    test $(git-rev-list HEAD --skip=3 --max-count=1 | wc -l) = 1 &&
+    test $(git-rev-list HEAD --skip=3 --max-count=2 | wc -l) = 2 &&
+    test $(git-rev-list HEAD --skip=3 --max-count=10 | wc -l) = 2 &&
+    test $(git-rev-list HEAD --skip=5 --max-count=10 | wc -l) = 0 &&
+    test $(git-rev-list HEAD --skip=10 --max-count=10 | wc -l) = 0
+'
+
+test_done
-- 
1.4.4.2.g80fef-dirty

← back to recent threads