+sub last_commits ($$) {
+ my ($self, $epoch_max) = @_;
+ my $heads = [];
+ for (my $i = $epoch_max; $i >= 0; $i--) {
+ $heads->[$i] = last_epoch_commit($self, $i);
+ }
+ $heads;
+}
+
+*is_ancestor = *PublicInbox::SearchIdx::is_ancestor;
+
+# returns a revision range for git-log(1)
+sub log_range ($$$$$) {
+ my ($self, $sync, $git, $i, $tip) = @_;
+ my $opt = $sync->{-opt};
+ my $pr = $opt->{-progress} if (($opt->{verbose} || 0) > 1);
+ my $cur = $sync->{ranges}->[$i] or do {
+ $pr->("$i.git indexing all of $tip") if $pr;
+ return $tip; # all of it
+ };
+
+ # fast equality check to avoid (v)fork+execve overhead
+ if ($cur eq $tip) {
+ $sync->{ranges}->[$i] = undef;
+ return;
+ }
+
+ my $range = "$cur..$tip";
+ $pr->("$i.git checking contiguity... ") if $pr;
+ if (is_ancestor($git, $cur, $tip)) { # common case
+ $pr->("OK\n") if $pr;
+ my $n = $git->qx(qw(rev-list --count), $range);
+ chomp($n);
+ if ($n == 0) {
+ $sync->{ranges}->[$i] = undef;
+ $pr->("$i.git has nothing new\n") if $pr;
+ return; # nothing to do
+ }
+ $pr->("$i.git has $n changes since $cur\n") if $pr;
+ } else {
+ $pr->("FAIL\n") if $pr;
+ warn <<"";
+discontiguous range: $range
+Rewritten history? (in $git->{git_dir})
+
+ chomp(my $base = $git->qx('merge-base', $tip, $cur));
+ if ($base) {
+ $range = "$base..$tip";
+ warn "found merge-base: $base\n"
+ } else {
+ $range = $tip;
+ warn "discarding history at $cur\n";
+ }
+ warn <<"";
+reindexing $git->{git_dir} starting at
+$range
+
+ $sync->{unindex_range}->{$i} = "$base..$cur";
+ }
+ $range;
+}
+
+sub sync_prepare ($$$) {
+ my ($self, $sync, $epoch_max) = @_;
+ my $pr = $sync->{-opt}->{-progress};
+ my $regen_max = 0;
+ my $head = $self->{-inbox}->{ref_head} || 'refs/heads/master';
+
+ # reindex stops at the current heads and we later rerun index_sync
+ # without {reindex}
+ my $reindex_heads = last_commits($self, $epoch_max) if $sync->{reindex};
+
+ for (my $i = $epoch_max; $i >= 0; $i--) {
+ die 'BUG: already indexing!' if $self->{reindex_pipe};
+ my $git_dir = git_dir_n($self, $i);
+ -d $git_dir or next; # missing epochs are fine