+# --is-ancestor requires git 1.8.0+
+sub is_ancestor ($$$) {
+ my ($git, $cur, $tip) = @_;
+ return 0 unless $git->check($cur);
+ my $cmd = [ 'git', "--git-dir=$git->{git_dir}",
+ qw(merge-base --is-ancestor), $cur, $tip ];
+ my $pid = spawn($cmd);
+ defined $pid or die "spawning ".join(' ', @$cmd)." failed: $!";
+ waitpid($pid, 0) == $pid or die join(' ', @$cmd) .' did not finish';
+ $? == 0;
+}
+
+sub need_update ($$$) {
+ my ($self, $cur, $new) = @_;
+ my $git = $self->{git};
+ return 1 if $cur && !is_ancestor($git, $cur, $new);
+ my $range = $cur eq '' ? $new : "$cur..$new";
+ chomp(my $n = $git->qx(qw(rev-list --count), $range));
+ ($n eq '' || $n > 0);
+}
+
+# The last git commit we indexed with Xapian or SQLite (msgmap)
+# This needs to account for cases where Xapian or SQLite is
+# out-of-date with respect to the other.
+sub _last_x_commit {
+ my ($self, $mm) = @_;
+ my $lm = $mm->last_commit || '';
+ my $lx = '';
+ if (need_xapian($self)) {
+ $lx = $self->{xdb}->get_metadata('last_commit') || '';
+ } else {
+ $lx = $lm;
+ }
+ # Use last_commit from msgmap if it is older or unset
+ if (!$lm || ($lx && $lm && is_ancestor($self->{git}, $lm, $lx))) {
+ $lx = $lm;
+ }
+ $lx;
+}
+
+sub reindex_from ($$) {
+ my ($reindex, $last_commit) = @_;
+ return $last_commit unless $reindex;
+ ref($reindex) eq 'HASH' ? $reindex->{from} : '';
+}
+
+# indexes all unindexed messages (v1 only)