+ my $rm_tree_cached = sub {
+ my ($subdir) = @_;
+ runcmd @git, qw(rm --quiet -rf --cached), $subdir;
+ };
+ my $read_tree_debian = sub {
+ my ($treeish) = @_;
+ $rm_tree_cached->(qw(debian));
+ runcmd @git, qw(read-tree --prefix=debian/), "$treeish:debian";
+ };
+ my $read_tree_upstream = sub {
+ my ($treeish) = @_;
+ runcmd @git, qw(read-tree), $treeish;
+ $read_tree_debian->($build);
+ };
+
+ my $committer_authline = calculate_committer_authline();
+
+ in_workarea sub {
+ mkdir $rd or $!==EEXIST or die $!;
+ my $current_method;
+ foreach my $cl (qw(Debian), (reverse @deb_cl),
+ { SpecialMethod => 'RecordBreakwaterTip' },
+ qw(Upstream), (reverse @ups_cl)) {
+ if (!ref $cl) {
+ $current_method = $cl;
+ next;
+ }
+ $method = $cl->{SpecialMethod} // $current_method;
+ my @parents = ($build);
+ my $cltree = $cl->{CommitId}
+ if ($method eq 'Debian') {
+ $read_tree_debian->($cltree);
+ } elsif ($method eq 'Upstream') {
+ $read_tree_upstream->($cltree);
+ } elsif ($method eq 'StartRewrite') {
+ $rewriting = 1;
+ next;
+ } elsif ($method eq 'RecordBreakwaterTip') {
+ last if $wantdebonly;
+ $breakwater = $build;
+ next;
+ } elsif ($method eq 'DgitImportDebianUpdate') {
+ $read_tree_debian->($cltree);
+ $rm_tree_cached(qw(debian/patches));
+ } elsif ($method eq 'DgitImportUpstreamUpdate') {
+ $read_tree_upstream->($cltree);
+ push @parents, map { $_->{CommitId} } @{ $cl->{OrigParents} };
+ } else {
+ confess "$method ?";
+ }
+ $rewriting ||= $cl ne pop @processed;
+ my $newtree = cmdoutput @git, qw(write-tree);
+ my $ch = $cl->{Hdr};
+ $ch =~ s{^tree .*}{tree $newtree}m or confess "$ch ?";
+ $ch =~ s{^parent .*\n}{}m;
+ $ch =~ s{(?=^author}{
+ map { "parent $_\n" } @parents
+ }me or confess "$ch ?";
+ if ($rewrite) {
+ $ch =~ s{^committer .*$}{$committer_authline}m
+ or confess "$ch ?";
+ }
+ my $cf = "$rd/m$rewrite"
+ open CD, ">", $cf or die $!;
+ print CD $ch, "\n", $cl->{Msg}; or die $!;
+ close CD or die $!;
+ my @cmd = (@git, qw(hash-object));
+ push @cmd, qw(-w) if $rewrite;
+ push @cmd, qw(-t commit), $cf;
+ my $newcommit = cmdoutput @cmd;
+ confess "$ch ?" unless $rewrite or $newcommit eq $cl->{CommitId};
+ $build = $newcommit;
+ }
+ };
+
+ runcmd @git, qw(diff-tree --quiet),
+ map { $wantdebonly ? "$_:debian" : $_ },
+ $input, $build;
+
+ return ($build, $breakwater);
+}