chiark / gitweb /
Split brain: Make pseudomerge
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 18 Sep 2016 22:42:16 +0000 (23:42 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Sep 2016 19:12:52 +0000 (20:12 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
dgit

diff --git a/dgit b/dgit
index bca6745..39efa04 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -63,6 +63,7 @@ our $existing_package = 'dpkg';
 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 $we_are_responder;
@@ -1642,7 +1643,11 @@ sub git_fetch_us () {
     # 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;
 
@@ -2350,6 +2355,114 @@ sub madformat ($) {
     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) = @_;
 
@@ -2566,7 +2679,9 @@ END
  "--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