chiark / gitweb /
git-debrebase: provide -f<tag>
[dgit.git] / git-debrebase
index bc92cfab4b88d08cb874a79c0413bbb95bfab81d..a9f510c8f112327b41b19adefcaff4060491be6b 100755 (executable)
@@ -90,6 +90,8 @@ use Dpkg::Version;
 
 our ($opt_force);
 
+our $us = qw(git-debrebase);
+
 sub badusage ($) {
     my ($m) = @_;
     die "bad usage: $m\n";
@@ -252,25 +254,41 @@ sub make_commit ($$) {
     return cmdoutput @cmd;
 }
 
-our $fproblems;
-sub fproblem ($) {
-    my ($msg) = @_;
-    $fproblems++;
-    print STDERR "git-debrebase: safety catch tripped: $msg\n";
+our @fproblem_force_opts;
+our $fproblems_forced;
+our $fproblems_tripped;
+sub fproblem ($$) {
+    my ($tag,$msg) = @_;
+    if (grep { $_ eq $tag } @fproblem_force_opts) {
+       $fproblems_forced++;
+       print STDERR "git-debrebase: safety catch overridden (-f$tag): $msg\n";
+    } else {
+       $fproblems_tripped++;
+       print STDERR "git-debrebase: safety catch tripped (-f$tag): $msg\n";
+    }
 }
+
 sub fproblems_maybe_bail () {
-    if ($fproblems) {
+    if ($fproblems_forced) {
+       printf STDERR
+           "%s: safety catch trips: %d overriden by individual -f options\n",
+           $us, $fproblems_forced;
+    }
+    if ($fproblems_tripped) {
        if ($opt_force) {
            printf STDERR
-               "safety catch trips (%d) overriden by --force\n",
-               $fproblems;
+               "%s: safety catch trips: %d overriden by global --force\n",
+               $us, $fproblems_tripped;
        } else {
            fail sprintf
-               "safety catch trips (%d) (you could --force)",
-               $fproblems;
+  "%s: safety catch trips: %d blockers (you could -f<tag>, or --force)",
+               $us, $fproblems_tripped;
        }
     }
 }
+sub any_fproblems () {
+    return $fproblems_forced || $fproblems_tripped;
+}
 
 # classify returns an info hash like this
 #   CommitId => $objid
@@ -371,7 +389,13 @@ sub classify ($) {
        return $r;
     };
 
+    my $claims_to_be_breakwater =
+       $r->{Msg} =~ m{^\[git-debrebase breakwater.*\]$}m;
+
     if (@p == 1) {
+       if ($claims_to_be_breakwater) {
+           return $unknown->("single-parent git-debrebase breakwater \`merge'");
+       }
        my $d = $r->{Parents}[0]{Differs};
        if ($d == D_PAT_ADD) {
            return $classify->(qw(AddPatches));
@@ -405,8 +429,7 @@ sub classify ($) {
     }
 
     my @identical = grep { !$_->{Differs} } @p;
-    if (@p == 2 && @identical == 1 &&
-       $r->{Msg} !~ m{^\[git-debrebase breakwater.*\]$}m
+    if (@p == 2 && @identical == 1 && !$claims_to_be_breakwater
        # breakwater merges can look like pseudomerges, if they are
        # "declare" commits (ie, there are no upstream changes)
        ) {
@@ -891,18 +914,22 @@ sub cmd_new_upstream_v0 () {
                $piece->($n, Old => $old_upstream->{CommitId}.'^'.$parentix);
            }
        } else {
-           fproblem "previous upstream $old_upstream->{CommitId} is from".
-                 " git-debrebase but not an \`upstream-combine' commit";
+           fproblem 'upstream-confusing',
+               "previous upstream $old_upstream->{CommitId} is from".
+               " git-debrebase but not an \`upstream-combine' commit";
        }
     }
 
     foreach my $pc (values %pieces) {
        if (!$pc->{Old}) {
-           fproblem "introducing upstream piece \`$pc->{Name}'";
+           fproblem 'upstream-new-piece',
+               "introducing upstream piece \`$pc->{Name}'";
        } elsif (!$pc->{New}) {
-           fproblem "dropping upstream piece \`$pc->{Name}'";
+           fproblem 'upstream-rm-piece',
+               "dropping upstream piece \`$pc->{Name}'";
        } elsif (!is_fast_fwd $pc->{Old}, $pc->{New}) {
-           fproblem "not fast forward: $pc->{Name} $pc->{Old}..$pc->{New}";
+           fproblem 'upstream-not-ff',
+               "not fast forward: $pc->{Name} $pc->{Old}..$pc->{New}";
        }
     }
 
@@ -917,7 +944,7 @@ sub cmd_new_upstream_v0 () {
     in_workarea sub {
        my @upstream_merge_parents;
 
-       if (!$fproblems) {
+       if (!any_fproblems()) {
            push @upstream_merge_parents, $old_upstream->{CommitId};
        }
 
@@ -1011,19 +1038,22 @@ sub cmd_gbp2debrebase () {
     }
 
     if (!is_fast_fwd $upstream, $old_head) {
-       fproblem "upstream ($upstream) is not an ancestor of HEAD";
+       fproblem 'upstream-not-ancestor',
+           "upstream ($upstream) is not an ancestor of HEAD";
     } else {
        my $wrong = cmdoutput
            (@git, qw(rev-list --ancestry-path), "$upstream..HEAD",
             qw(-- :/ :!/debian));
        if (length $wrong) {
-           fproblem "history between upstream ($upstream) and HEAD contains direct changes to upstream files - are you sure this is a gbp (patches-unapplied) branch?";
+           fproblem 'unexpected-upstream-changes',
+               "history between upstream ($upstream) and HEAD contains direct changes to upstream files - are you sure this is a gbp (patches-unapplied) branch?";
            print STDERR "list expected changes with:  git log --stat --ancestry-path $upstream_spec..HEAD -- :/ ':!/debian'\n";
        }
     }
 
     if ((git_cat_file "$upstream:debian")[0] ne 'missing') {
-       fproblem "upstream ($upstream) contains debian/ directory";
+       fproblem 'upstream-has-debian',
+           "upstream ($upstream) contains debian/ directory";
     }
 
     fproblems_maybe_bail();
@@ -1110,6 +1140,7 @@ sub cmd_downstream_rebase_launder_v0 () {
 }
 
 GetOptions("D+" => \$debuglevel,
+          'f=s' => \@fproblem_force_opts,
           'force!') or die badusage "bad options\n";
 initdebug('git-debrebase ');
 enabledebug if $debuglevel;