+ return;
+ }
+
+ # is this a number we got before?
+ $num = $sync->{mm_tmp}->num_for($mid);
+ if (defined $num) {
+ $mid0 = $mid;
+ check_unindexed($self, $num, $mid0);
+ } else {
+ $num = $sync->{regen}--;
+ die "BUG: ran out of article numbers" if $num <= 0;
+ if ($self->{mm}->mid_set($num, $mid) != 1) {
+ warn "E: unable to assign $num => <$mid>\n";
+ return;
+ }
+ $mid0 = $mid;
+ }
+ } else { # multiple MIDs are a weird case:
+ my $del = 0;
+ for (@$mids) {
+ $del += delete($sync->{D}->{"$_\0$cid"}) // 0;
+ }
+ if ($del) {
+ unindex_oid_remote($self, $oid, $_) for @$mids;
+ # do not delete from {mm_tmp}, since another
+ # single-MID message may use it.
+ } else { # handle them at the end:
+ multi_mid_q_push($sync, $oid);
+ }
+ return;
+ }
+ $sync->{mm_tmp}->mid_delete($mid0) or
+ die "failed to delete <$mid0> for article #$num\n";
+ $sync->{nr}++;
+ if (do_idx($self, $msgref, $mime, $len, $num, $oid, $mid0)) {
+ reindex_checkpoint($self, $sync, $git);
+ }
+}
+
+# only update last_commit for $i on reindex iff newer than current
+sub update_last_commit ($$$$) {
+ my ($self, $git, $i, $cmt) = @_;
+ my $last = last_epoch_commit($self, $i);
+ if (defined $last && is_ancestor($git, $last, $cmt)) {
+ my @cmd = (qw(rev-list --count), "$last..$cmt");
+ chomp(my $n = $git->qx(@cmd));
+ return if $n ne '' && $n == 0;
+ }
+ last_epoch_commit($self, $i, $cmt);
+}
+
+sub git_dir_n ($$) { "$_[0]->{-inbox}->{inboxdir}/git/$_[1].git" }
+
+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