our $cleanmode;
our $changes_since_version;
our $rmchanges;
+our $overwrite_version;
our $quilt_mode;
-our $quilt_modes_re = 'linear|smash|auto|nofix|nocheck|gbp|unapplied';
+our $quilt_modes_re = 'linear|smash|auto|nofix|nocheck|gbp|dpm|unapplied';
our $we_are_responder;
our $initiator_tempdir;
our $patches_applied_dirtily = 00;
return $c;
}
+sub commit_getclogp ($) {
+ # Returns the parsed changelog hashref for a particular commit
+ my ($objid) = @_;
+ our %commit_getclogp_memo;
+ my $memo = $commit_getclogp_memo{$objid};
+ return $memo if $memo;
+ mkpath '.git/dgit';
+ my $mclog = ".git/dgit/clog-$objid";
+ runcmd shell_cmd "exec >$mclog", @git, qw(cat-file blob),
+ "$objid:debian/changelog";
+ $commit_getclogp_memo{$objid} = parsechangelog("-l$mclog");
+}
+
sub must_getcwd () {
my $d = getcwd();
defined $d or fail "getcwd failed: $!";
sub mktree_in_ud_here () {
runcmd qw(git init -q);
+ runcmd qw(git config gc.auto 0);
rmtree('.git/objects');
symlink '../../../../objects','.git/objects' or die $!;
}
my @output = ($rawimport_mergeinput);
progress "synthesised git commit from .dsc $cversion";
if ($lastpush_mergeinput) {
- my $lastpush_hash = $lastpush_mergeinput->{Commit};
- runcmd @git, qw(reset -q --hard), $lastpush_hash;
- runcmd qw(sh -ec), 'dpkg-parsechangelog >>../changelogold.tmp';
- my $oldclogp = parsecontrol('../changelogold.tmp','previous changelog');
+ my $oldclogp = mergeinfo_getclogp($lastpush_mergeinput);
my $oversion = getfield $oldclogp, 'Version';
my $vcmp =
version_compare($oversion, $cversion);
# deliberately-not-ff, in which case we must fetch everything.
my @specs = deliberately_not_fast_forward ? qw(tags/*) :
- map { "tags/$_" } debiantags('*',access_basedistro);
+ map { "tags/$_" }
+ (quiltmode_splitbrain
+ ? (map { $_->('*',access_basedistro) }
+ \&debiantag_new, \&debiantag_maintview)
+ : debiantags('*',access_basedistro));
push @specs, server_branch($csuite);
push @specs, qw(heads/*) if deliberately_not_fast_forward;
}
sub mergeinfo_getclogp ($) {
- my ($mi) = @_;
# Ensures thit $mi->{Clogp} exists and returns it
- return $mi->{Clogp} if $mi->{Clogp};
- my $mclog = ".git/dgit/clog-$mi->{Commit}";
- mkpath '.git/dgit';
- runcmd shell_cmd "exec >$mclog", @git, qw(cat-file blob),
- "$mi->{Commit}:debian/changelog";
- $mi->{Clogp} = parsechangelog("-l$mclog");
+ my ($mi) = @_;
+ $mi->{Clogp} = commit_getclogp($mi->{Commit});
}
sub mergeinfo_version ($) {
# Finally: we do not necessarily reify the public view (as
# described above). This is so that we do not end up stacking two
# pseudo-merges. So what we actually do is figure out the inputs
- # to any public view psuedo-merge and put them in @mergeinputs.
+ # to any public view pseudo-merge and put them in @mergeinputs.
my @mergeinputs;
# $mergeinputs[]{Commit}
if (defined $skew_warning_vsn) {
mkpath '.git/dgit';
printdebug "SKEW CHECK WANT $skew_warning_vsn\n";
- my $clogf = ".git/dgit/changelog.tmp";
- runcmd shell_cmd "exec >$clogf",
- @git, qw(cat-file blob), "$hash:debian/changelog";
- my $gotclogp = parsechangelog("-l$clogf");
+ my $gotclogp = commit_getclogp($hash);
my $got_vsn = getfield $gotclogp, 'Version';
printdebug "SKEW CHECK GOT $got_vsn\n";
if (version_compare($got_vsn, $skew_warning_vsn) < 0) {
return 1;
}
+sub splitbrain_pseudomerge ($$$$) {
+ my ($clogp, $maintview, $dgitview, $archive_hash) = @_;
+ # => $merged_dgitview
+ printdebug "splitbrain_pseudomerge...\n";
+ #
+ # We: debian/PREVIOUS HEAD($maintview)
+ # expect: o ----------------- o
+ # \ \
+ # o o
+ # a/d/PREVIOUS $dgitview
+ # $archive_hash \
+ # If so, \ \
+ # we do: `------------------ o
+ # this: $dgitview'
+ #
+
+ # We work with tuples [ $thing, $what ]
+ # (often $thing is a commit hash; $what is a description)
+
+ my $tag_lookup = sub {
+ my ($tagname, $what) = @_;
+ printdebug "splitbrain_pseudomerge tag_lookup $what\n";
+ my $lrefname = lrfetchrefs."/tags/$tagname";
+ my $tagobj = $lrfetchrefs_f{$lrefname};
+ defined $tagobj or fail <<END;
+Wanted tag $tagname ($what) on dgit server, but not found
+END
+ printdebug "splitbrain_pseudomerge tag_lookup $tagobj $what\n";
+ return [ git_rev_parse($tagobj), $what ];
+ };
+
+ my $cond_equal = sub {
+ my ($x,$y) = @_;
+ $x->[0] eq $y->[0] or fail <<END;
+$x->[1] ($x->[0]) not equal to $y->[1] ($y->[0])
+END
+ };
+ my $cond_ff = sub {
+ my ($anc,$desc) = @_;
+ is_fast_fwd($anc->[0], $desc->[0]) or fail <<END;
+$anc->[1] ($anc->[0]) .. $desc->[1] ($desc->[0]) is not fast forward
+END
+ };
+
+ my $arch_clogp = commit_getclogp $archive_hash;
+ my $i_arch_v = [ (getfield $arch_clogp, 'Version'),
+ 'version currently in archive' ];
+
+ printdebug "splitbrain_pseudomerge i_arch_v @$i_arch_v\n";
+
+ return $dgitview unless defined $archive_hash;
+
+ if ($overwrite_version) {
+ progress "Declaring that HEAD inciudes all changes in archive...";
+ progress "Checking that $overwrite_version does so...";
+ $cond_equal->([ $overwrite_version, '--overwrite= version' ],
+ $i_arch_v);
+ } else {
+ progress "Checking that HEAD inciudes all changes in archive...";
+ }
+
+ return $dgitview if is_fast_fwd $archive_hash, $dgitview;
+
+ my $t_dep14 = debiantag_maintview $i_arch_v->[0], access_basedistro;
+ my $i_dep14 = $tag_lookup->($t_dep14, "maintainer view tag");
+ my $t_dgit = debiantag_new $i_arch_v->[0], access_basedistro;
+ my $i_dgit = $tag_lookup->($t_dgit, "dgit view tag");
+ my $i_archive = [ $archive_hash, "current archive contents" ];
+
+ printdebug "splitbrain_pseudomerge i_archive @$i_archive\n";
+
+ $cond_equal->($i_dgit, $i_archive);
+ $cond_ff->($i_dep14, $i_dgit);
+ $overwrite_version or $cond_ff->($i_dep14, [ $maintview, 'HEAD' ]);
+
+ my $tree = cmdoutput qw(git rev-parse), "${dgitview}:";
+ my $authline = clogp_authline $clogp;
+
+ mkpath '.git/dgit';
+ my $pmf = ".git/dgit/pseudomerge";
+ open MC, ">", $pmf or die "$pmf $!";
+ print MC <<END or die $!;
+tree $tree
+parent $dgitview
+parent $archive_hash
+author $authline
+commiter $authline
+
+END
+ if ($overwrite_version) {
+ print MC <<END;
+Declare fast forward from $overwrite_version
+
+[dgit --quilt=$quilt_mode --overwrite-version=$overwrite_version]
+END
+ } else {
+ print MC <<END;
+Make fast forward from $i_arch_v->[0]
+
+[dgit --quilt=$quilt_mode]
+END
+ }
+ close MC or die $!;
+
+ progress "Making pseudo-merge of $i_arch_v->[0] into dgit view.";
+ return make_commit($pmf);
+}
+
sub push_parse_changelog ($) {
my ($clogpfn) = @_;
$tw->{Tag} = $tw->{TagFn}($cversion, access_basedistro);
$tw->{Tfn} = sub { $tfbase.$tw->{TfSuffix}.$_[0]; };
}
+ printdebug 'push_tagwants: ', Dumper(\@_, \@tagwants);
return @tagwants;
}
"--quilt=$quilt_mode but no cached dgit view:
perhaps tree changed since dgit build[-source] ?";
$split_brain = 1;
- $dgithead = $dgitview;
+ $dgithead = splitbrain_pseudomerge($clogp,
+ $actualhead, $dgitview,
+ $archive_hash);
$maintviewhead = $actualhead;
changedir '../../../..';
prep_ud(); # so _only_subdir() works, below
responder_send_command("param head $dgithead");
responder_send_command("param csuite $csuite");
responder_send_command("param tagformat $tagformat");
- if (quiltmode_splitbrain) {
+ if (defined $maintviewhead) {
die unless ($protovsn//4) >= 4;
responder_send_command("param maint-view $maintviewhead");
}
my @pushrefs = $forceflag.$dgithead.":".rrref();
foreach my $tw (@tagwants) {
- my $view = $tw->{View};
- next unless $view eq 'dgit'
- or any { $_ eq $view } access_cfg_tagformats();
- # ^ $view is "dgit" or "maint" so this looks for "maint"
- # in archive supported tagformats.
push @pushrefs, $forceflag."refs/tags/$tw->{Tag}";
}
}
fail $msg;
}
+ if ($quilt_mode =~ m/dpm/ &&
+ ($diffbits->{H2A} & 01)) {
+ fail <<END;
+--quilt=$quilt_mode specified, implying patches-applied git tree
+ but git tree differs from result of applying debian/patches to upstream
+END
+ }
if ($quilt_mode =~ m/gbp|unapplied/ &&
($diffbits->{O2A} & 01)) { # some patches
quiltify_splitbrain_needed();
runcmd @git, qw(update-ref refs/heads/dgit-view HEAD);
runcmd @git, qw(checkout -q dgit-view);
}
+ if ($quilt_mode =~ m/gbp|dpm/ &&
+ ($diffbits->{O2A} & 02)) {
+ fail <<END
+--quilt=$quilt_mode specified, implying that HEAD is for use with a
+ tool which does not create patches for changes to upstream
+ .gitignores: but, such patches exist in debian/patches.
+END
+ }
if (($diffbits->{H2O} & 02) && # user has modified .gitignore
!($diffbits->{O2A} & 02)) { # patches do not change .gitignore
quiltify_splitbrain_needed();