+ if (grep { $method eq $_ } qw(DgitImportUpstreamUpdate)) {
+ $last_anchor = $cur;
+ }
+ }
+ };
+
+ my $final_check = get_differs $build, $input;
+ die sprintf "internal error %#x %s %s", $final_check, $build, $input
+ if $final_check & ~D_PAT_ADD;
+
+ my @r = ($build, $breakwater, $last_anchor);
+ printdebug "*** WALK RETURN @r\n";
+ return @r
+}
+
+sub get_head () {
+ git_check_unmodified();
+ return git_rev_parse qw(HEAD);
+}
+
+sub update_head ($$$) {
+ my ($old, $new, $mrest) = @_;
+ push @deferred_updates, "update HEAD $new $old";
+ run_deferred_updates $mrest;
+}
+
+sub update_head_checkout ($$$) {
+ my ($old, $new, $mrest) = @_;
+ update_head $old, $new, $mrest;
+ runcmd @git, qw(reset --hard);
+}
+
+sub update_head_postlaunder ($$$) {
+ my ($old, $tip, $reflogmsg) = @_;
+ return if $tip eq $old;
+ print "git-debrebase: laundered (head was $old)\n";
+ update_head $old, $tip, $reflogmsg;
+ # no tree changes except debian/patches
+ runcmd @git, qw(rm --quiet --ignore-unmatch -rf debian/patches);
+}
+
+sub do_launder_head ($) {
+ my ($reflogmsg) = @_;
+ my $old = get_head();
+ record_ffq_auto();
+ my ($tip,$breakwater) = walk $old;
+ update_head_postlaunder $old, $tip, $reflogmsg;
+ return ($tip,$breakwater);
+}
+
+sub cmd_launder_v0 () {
+ badusage "no arguments to launder-v0 allowed" if @ARGV;
+ my $old = get_head();
+ my ($tip,$breakwater,$last_anchor) = walk $old;
+ update_head_postlaunder $old, $tip, 'launder';
+ printf "# breakwater tip\n%s\n", $breakwater;
+ printf "# working tip\n%s\n", $tip;
+ printf "# last anchor\n%s\n", $last_anchor;
+}
+
+sub defaultcmd_rebase () {
+ push @ARGV, @{ $opt_defaultcmd_interactive // [] };
+ my ($tip,$breakwater) = do_launder_head 'launder for rebase';
+ runcmd @git, qw(rebase), @ARGV, $breakwater if @ARGV;
+}
+
+sub cmd_analyse () {
+ die if ($ARGV[0]//'') =~ m/^-/;
+ badusage "too many arguments to analyse" if @ARGV>1;
+ my ($old) = @ARGV;
+ if (defined $old) {
+ $old = git_rev_parse $old;
+ } else {
+ $old = git_rev_parse 'HEAD';
+ }
+ my ($dummy,$breakwater) = walk $old, 1,*STDOUT;
+ STDOUT->error and die $!;
+}
+
+sub ffq_prev_branchinfo () {
+ # => ('status', "message", [$current, $ffq_prev, $gdrlast])
+ # 'status' may be
+ # branch message is undef
+ # weird-symref } no $current,
+ # notbranch } no $ffq_prev
+ my $current = git_get_symref();
+ return ('detached', 'detached HEAD') unless defined $current;
+ return ('weird-symref', 'HEAD symref is not to refs/')
+ unless $current =~ m{^refs/};
+ my $ffq_prev = "refs/$ffq_refprefix/$'";
+ my $gdrlast = "refs/$gdrlast_refprefix/$'";
+ printdebug "ffq_prev_branchinfo branch current $current\n";
+ return ('branch', undef, $current, $ffq_prev, $gdrlast);
+}
+
+sub record_ffq_prev_deferred () {
+ # => ('status', "message")
+ # 'status' may be
+ # deferred message is undef
+ # exists
+ # detached
+ # weird-symref
+ # notbranch
+ # if not ff from some branch we should be ff from, is an snag
+ # if "deferred", will have added something about that to
+ # @deferred_update_messages, and also maybe printed (already)
+ # some messages about ff checks
+ my ($status, $message, $current, $ffq_prev, $gdrlast)
+ = ffq_prev_branchinfo();
+ return ($status, $message) unless $status eq 'branch';
+
+ my $currentval = get_head();
+
+ my $exists = git_get_ref $ffq_prev;
+ return ('exists',"$ffq_prev already exists") if $exists;
+
+ return ('not-branch', 'HEAD symref is not to refs/heads/')
+ unless $current =~ m{^refs/heads/};
+ my $branch = $';
+
+ my @check_specs = split /\;/, (cfg "branch.$branch.ffq-ffrefs",1) // '*';
+ my %checked;
+
+ printdebug "ffq check_specs @check_specs\n";
+
+ my $check = sub {
+ my ($lrref, $desc) = @_;
+ printdebug "ffq might check $lrref ($desc)\n";
+ my $invert;
+ for my $chk (@check_specs) {
+ my $glob = $chk;
+ $invert = $glob =~ s{^[!^]}{};
+ last if fnmatch $glob, $lrref;
+ }
+ return if $invert;
+ my $lrval = git_get_ref $lrref;
+ return unless defined $lrval;
+
+ if (is_fast_fwd $lrval, $currentval) {
+ print "OK, you are ahead of $lrref\n" or die $!;
+ $checked{$lrref} = 1;
+ } elsif (is_fast_fwd $currentval, $lrval) {
+ $checked{$lrref} = -1;
+ snag 'behind', "you are behind $lrref, divergence risk";
+ } else {
+ $checked{$lrref} = -1;
+ snag 'diverged', "you have diverged from $lrref";