chiark / gitweb /
test suite: gdr-convert-gbp: Save converted-from-gbp
[dgit.git] / git-debrebase
index d04f2a3af54882d2f256ea82341349525e54c5e9..894bad5d227b8e0adcbb47843ad58af2bd4ac800 100755 (executable)
@@ -53,7 +53,7 @@ END
 our ($opt_force, $opt_careful, $opt_noop_ok, @opt_anchors);
 our ($opt_defaultcmd_interactive);
 
-$opt_careful = 1;
+$opt_careful = 0;
 
 our $us = qw(git-debrebase);
 
@@ -112,8 +112,8 @@ sub get_commit ($) {
 sub D_UPS ()      { 0x02; } # upstream files
 sub D_PAT_ADD ()  { 0x04; } # debian/patches/ extra patches at end
 sub D_PAT_OTH ()  { 0x08; } # debian/patches other changes
-sub D_DEB_CLOG () { 0x10; } # debian/ (not patches/ or changelog)
-sub D_DEB_OTH ()  { 0x20; } # debian/changelog
+sub D_DEB_CLOG () { 0x10; } # debian/changelog
+sub D_DEB_OTH ()  { 0x20; } # debian/ (not patches/ or changelog)
 sub DS_DEB ()     { D_DEB_CLOG | D_DEB_OTH; } # debian/ (not patches/)
 
 our $playprefix = 'debrebase';
@@ -187,13 +187,17 @@ sub get_tree ($) {
     # tree object name => ([ $name, $info ], ...)
     # where $name is the sort key, ie has / at end for subtrees
     # $info is the LHS from git-ls-tree (<mode> <type> <hash>)
-    # will crash if $x does not exist, so don't do that
+    # will crash if $x does not exist, so don't do that;
+    # instead pass '' to get ().
     my ($x) = @_;
+
+    return () if !length $x;
+
     our (@get_tree_memo, %get_tree_memo);
     my $memo = $get_tree_memo{$x};
     return @$memo if $memo;
 
-    local $debugcmd_when_debuglevel = 3;
+    local $Debian::Dgit::debugcmd_when_debuglevel = 3;
     my @l;
     my @cmd = (qw(git ls-tree -z --full-tree --), $x);
     my $o = cmdoutput @cmd;
@@ -223,11 +227,15 @@ sub trees_diff_walk ($$$;$) {
     return if !$all and $x eq $y;
     my @x = get_tree $x;
     my @y = get_tree $y;
+    printdebug "trees_diff_walk(..$x,$y..) ".Dumper(\@x,\@y)
+       if $debuglevel >= 3;
     while (@x || @y) {
        my $cmp = !@x       <=> !@y          # eg @y empty? $cmp=-1, use x
             ||    $x[0][0] cmp  $y[0][0];   # eg, x lt y ? $cmp=-1, use x
        my ($n, $ix, $iy);                   # all same? $cmp=0, use both
        $ix=$iy='';
+       printdebug "trees_diff_walk $cmp : @{ $x[0]//[] } | @{ $y[0]//[] }\n"
+           if $debuglevel >= 3;
        ($n, $ix) = @{ shift @x } if $cmp <= 0;
        ($n, $iy) = @{ shift @y } if $cmp >= 0;
        next if !$all and $ix eq $iy;
@@ -241,70 +249,75 @@ sub trees_diff_walk ($$$;$) {
 
 sub get_differs ($$) {
     my ($x,$y) = @_;
-    # This resembles quiltify_trees_differ, in dgit, a bit.
+    # This does a similar job to quiltify_trees_differ, in dgit, a bit.
     # But we don't care about modes, or dpkg-source-unrepresentable
     # changes, and we don't need the plethora of different modes.
     # Conversely we need to distinguish different kinds of changes to
     # debian/ and debian/patches/.
+    # Also, here we have, and want to use, trees_diff_walk, because
+    # we may be calling this an awful lot and we want it to be fast.
 
     my $differs = 0;
+    my @debian_info;
 
-    my $rundiff = sub {
-       my ($opts, $limits, $fn) = @_;
-       my @cmd = (@git, qw(diff-tree -z --no-renames));
-       push @cmd, @$opts;
-       push @cmd, "$_:" foreach $x, $y;
-       push @cmd, '--', @$limits;
-       my $diffs = cmdoutput @cmd;
-       foreach (split /\0/, $diffs) { $fn->(); }
-    };
+    no warnings qw(exiting);
 
-    $rundiff->([qw(--name-only)], [], sub {
-        $differs |= $_ eq 'debian' ? DS_DEB : D_UPS;
-    });
+    my $plain = sub { $_[0] =~ m{^(100|0*)644 blob }s; };
 
-    if ($differs & DS_DEB) {
-       $differs &= ~DS_DEB;
-       $rundiff->([qw(--name-only -r)], [qw(debian)], sub {
-            $differs |=
-               m{^debian/patches/}      ? D_PAT_OTH  :
-               $_ eq 'debian/changelog' ? D_DEB_CLOG :
-                                          D_DEB_OTH;
-       });
-       die "mysterious debian changes $x..$y"
-           unless $differs & (D_PAT_OTH|DS_DEB);
-    }
-
-    if ($differs & D_PAT_OTH) {
-       my $mode;
-       $differs &= ~D_PAT_OTH;
-       my $pat_oth = sub {
-           $differs |= D_PAT_OTH;
-           no warnings qw(exiting);  last;
-       };
-       $rundiff->([qw(--name-status -r)], [qw(debian/patches/)], sub {
-            no warnings qw(exiting);
-            if (!defined $mode) {
-               $mode = $_;  next;
+    trees_diff_walk "$x:", "$y:", sub {
+       my ($n,$ix,$iy) = @_;
+
+       # analyse difference at the toplevel
+
+       if ($n ne 'debian/') {
+           $differs |= D_UPS;
+           next;
+       }
+       if ($n eq 'debian') {
+           # one side has a non-tree for ./debian !
+           $differs |= D_DEB_OTH;
+           next;
+       }
+
+       my $xd = $ix && "$x:debian";
+       my $yd = $iy && "$y:debian";
+       trees_diff_walk $xd, $yd, sub {
+           my ($n,$ix,$iy) = @_;
+           
+           # analyse difference in debian/
+
+           if ($n eq 'changelog' && (!$ix || $plain->($ix))
+                                  &&          $plain->($iy) ) {
+               $differs |= D_DEB_CLOG;
+               next;
            }
-           die unless s{^debian/patches/}{};
-           my $ok;
-           if ($mode eq 'A' && !m/\.series$/s) {
-               $ok = 1;
-           } elsif ($mode eq 'M' && $_ eq 'series') {
-               my $x_s = (git_cat_file "$x:debian/patches/series", 'blob');
-               my $y_s = (git_cat_file "$y:debian/patches/series", 'blob');
-               chomp $x_s;  $x_s .= "\n";
-               $ok = $x_s eq substr($y_s, 0, length $x_s);
-           } else {
-               # nope
+           if ($n ne 'patches/') {
+               $differs |= D_DEB_OTH;
+               next;
            }
-           $mode = undef;
-           $differs |= $ok ? D_PAT_ADD : D_PAT_OTH;
-        });
-       die "mysterious debian/patches changes $x..$y"
-           unless $differs & (D_PAT_ADD|D_PAT_OTH);
-    }
+
+           my $xp = $ix && "$xd/patches";
+           my $yp = $iy && "$yd/patches";
+           trees_diff_walk $xp, $yp, sub {
+               my ($n,$ix,$iy) = @_;
+
+               # analyse difference in debian/patches
+
+               my $ok;
+               if ($n !~ m/\.series$/s && !$ix && $plain->($iy)) {
+                   $ok = 1;
+               } elsif ($n eq 'series' && $plain->($ix) && $plain->($iy)) {
+                   my $x_s = (git_cat_file "$xp/series", 'blob');
+                   my $y_s = (git_cat_file "$yp/series", 'blob');
+                   chomp $x_s;  $x_s .= "\n";
+                   $ok = $x_s eq substr($y_s, 0, length $x_s);
+               } else {
+                   # nope
+               }
+               $differs |= $ok ? D_PAT_ADD : D_PAT_OTH;
+           };    
+       };
+    };
 
     printdebug sprintf "get_differs %s %s = %#x\n", $x, $y, $differs;
 
@@ -1612,6 +1625,18 @@ sub walk ($;$$$) {
                $build = $newcommit;
            } else {
                $build = $cl->{CommitId};
+               trees_diff_walk "$want_upstream:", "$build:", sub {
+                   my ($n) = @_;
+                   no warnings qw(exiting);
+                   next if $n eq 'debian/';
+                   confess "mismatch @_ ?";
+               };
+               trees_diff_walk "$want_debian:debian", "$build:debian", sub {
+                   confess "mismatch @_ ?";
+               };
+               my @old_parents = map { $_->{CommitId} } @{ $cl->{Parents} };
+               confess "mismatch @parents != @old_parents ?"
+                   unless "@parents" eq "@old_parents";
            }
             if (grep { $method eq $_ } qw(DgitImportUpstreamUpdate)) {
                 $last_anchor = $cur;
@@ -1647,7 +1672,7 @@ sub update_head_checkout ($$$) {
 
 sub update_head_postlaunder ($$$) {
     my ($old, $tip, $reflogmsg) = @_;
-    return if $tip eq $old;
+    return if $tip eq $old && !@deferred_updates;
     print "git-debrebase: laundered (head was $old)\n";
     update_head $old, $tip, $reflogmsg;
     # no tree changes except debian/patches
@@ -2250,7 +2275,10 @@ sub cmd_stitch () {
     badusage "no arguments allowed" if @ARGV;
     do_stitch $prose, 0;
 }
-sub cmd_prepush () { cmd_stitch(); }
+sub cmd_prepush () {
+    $opt_noop_ok = 1;
+    cmd_stitch();
+}
 
 sub cmd_quick () {
     badusage "no arguments allowed" if @ARGV;