X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=blobdiff_plain;f=git-debrebase;h=e73526e9e6207606df78647aa5b902e9580175da;hp=b2c15d6f78e26423e5216a2b3edc7cc569e84d38;hb=675a7f895eb4768ae4078342f880852196626948;hpb=025a34d5ceee06d7fc673b5c6f131c0f72f3c3af diff --git a/git-debrebase b/git-debrebase index b2c15d6f..e73526e9 100755 --- a/git-debrebase +++ b/git-debrebase @@ -136,11 +136,12 @@ sub get_commit ($) { return ($`,$'); } -sub D_DEB () { return 0x1; } # debian/ (not including debian/patches/) -sub D_UPS () { return 0x2; } # upstream files -sub D_PAT_ADD () { return 0x4; } # debian/patches/ extra patches at end -sub D_PAT_OTH () { return 0x8; } # debian/patches other changes - +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 DS_DEB () { D_DEB_CLOG | D_DEB_OTH; } # debian/ (not patches/) our $playprefix = 'debrebase'; our $rd; @@ -181,16 +182,19 @@ sub get_differs ($$) { }; $rundiff->([qw(--name-only)], [], sub { - $differs |= $_ eq 'debian' ? D_DEB : D_UPS; + $differs |= $_ eq 'debian' ? DS_DEB : D_UPS; }); - if ($differs & D_DEB) { - $differs &= ~D_DEB; + if ($differs & DS_DEB) { + $differs &= ~DS_DEB; $rundiff->([qw(--name-only -r)], [qw(debian)], sub { - $differs |= $_ eq m{^debian/patches/} ? D_PAT_OTH : D_DEB; + $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|D_DEB); + unless $differs & (D_PAT_OTH|DS_DEB); } if ($differs & D_PAT_OTH) { @@ -260,6 +264,7 @@ sub calculate_committer_authline () { # # Types: # Packaging +# Changelog # Upstream # AddPatches # Mixed @@ -330,10 +335,14 @@ sub classify ($) { return $classify->(qw(AddPatches)); } elsif ($d & (D_PAT_ADD|D_PAT_OTH)) { return $unknown->("edits debian/patches"); - } elsif ($d == D_DEB) { + } elsif ($d & DS_DEB and !($d & ~DS_DEB)) { my ($ty,$dummy) = git_cat_file "$ph[0]:debian"; if ($ty eq 'tree') { - return $classify->(qw(Packaging)); + if ($d == D_DEB_CLOG) { + return $classify->(qw(Changelog)); + } else { + return $classify->(qw(Packaging)); + } } elsif ($ty eq 'missing') { return $classify->(qw(BreakwaterStart)); } else { @@ -341,7 +350,7 @@ sub classify ($) { } } elsif ($d == D_UPS) { return $classify->(qw(Upstream)); - } elsif ($d == (D_DEB|D_UPS)) { + } elsif ($d & DS_DEB and $d & D_UPS and !($d & ~(DS_DEB|D_UPS))) { return $classify->(qw(Mixed)); } elsif ($d == 0) { return $unknown->("no changes"); @@ -390,23 +399,32 @@ sub classify ($) { my ($stype, $series) = git_cat_file "$t:debian/patches/series"; my $haspatches = $stype ne 'missing' && $series =~ m/^\s*[^#\n\t ]/m; -@p = reverse @p; #xxx - # How to decide about l/r ordering of breakwater merges ? git # --topo-order prefers to expand 2nd parent first. There's # already an easy rune to look for debian/ history anyway (git log # debian/) so debian breakwater branch should be 1st parent; that # way also there's also an easy rune to look for the upstream # patches (--topo-order). - if (@p == 2 && - !$haspatches && - !$p[0]{IsOrigin} && # breakwater merge never starts with an origin - !($p[0]{Differs} & ~D_DEB) && - !($p[1]{Differs} & ~D_UPS)) { - return $classify->(qw(BreakwaterUpstreamMerge), - OrigParents => [ $p[1] ]); + + # The above tells us which way *we* will generate them. But we + # might encounter ad-hoc breakwater merges generated manually, + # which might be the other way around. In principle, in some odd + # situations, a breakwater merge might have two identical parents. + # In that case we guess which way round it is (ie, which parent + # has the upstream history). The order of the 2-iteration loop + # controls which guess we make. + + foreach my $prevbrw (qw(0 1)) { + if (@p == 2 && + !$haspatches && + !$p[$prevbrw]{IsOrigin} && # breakwater never starts with an origin + !($p[$prevbrw]{Differs} & ~DS_DEB) && + !($p[!$prevbrw]{Differs} & ~D_UPS)) { + return $classify->(qw(BreakwaterUpstreamMerge), + OrigParents => [ $p[!$prevbrw] ]); + } + # xxx multi-.orig upstreams } - # xxx multi-.orig upstreams return $unknown->("complex merge"); } @@ -481,7 +499,7 @@ sub walk ($;$$) { $cur = $p0; $rewrite_from_here->(); next; - } elsif ($ty eq 'Packaging') { + } elsif ($ty eq 'Packaging' or $ty eq 'Changelog') { push @brw_cl, $cl; $cur = $p0; next; @@ -672,7 +690,14 @@ sub get_head () { return git_rev_parse qw(HEAD); } sub update_head ($$$) { my ($old, $new, $mrest) = @_; - runcmd @git, qw(update-ref -m), "git-debrebase $mrest", $new, $old; + runcmd @git, qw(update-ref -m), "debrebase: $mrest", 'HEAD', $new, $old; +} + +sub update_head_checkout ($$$) { + my ($old, $new, $mrest) = @_; + my $symref = git_get_symref(); + runcmd @git, qw(checkout), $new, qw(.); + update_head $old, $new, $mrest; } sub cmd_launder () { @@ -698,6 +723,51 @@ sub cmd_analyse () { STDOUT->error and die $!; } +sub cmd_downstream_rebase_launder_v0 () { + badusage "needs 1 argument, the baseline" unless @ARGV=0; + my ($base) = @ARGV; + $base = git_rev_parse $base; + my $old_head = get_head(); + my $current = $old_head; + my $topmost_keep; + for (;;) { + if ($current eq $base) { + $topmust_keep //= $current; + print "$current BASE: stopping\n"; + last; + } + my $cl = classify $current; + print " $current $cl->{Type}"; + my $keep = 0; + my $p0 = $cl->{Parents}[0]{CommitId}; + if ($cl->{Type} eq 'Pseudomerge') { + $current = $cl->{Contributor}{CommitId}; + print " ^".($cl->{Contributor}{Ix}+1); + } elsif ($cl->{Type} eq 'AddPatches' or + $cl->{Type} eq 'Changelog') { + print " strip"; + $current = $p0; + } else { + print " keep"; + $current = $p0; + $keep = 1; + } + print "\n"; + if ($keep) { + $topmost_keep //= $current; + } else { + die "to-be stripped changes not on top of the branch\n" + if $topmost_unstripped; + } + } + if ($topmost_keep eq $old_head) { + print "unchanged\n"; + } else { + print "updating to $topmost_keep\n"; + update_head $old_head, $topmost_keep, 'downstream-rebase-launder-v0'; + } +} + GetOptions("D+" => \$debuglevel) or die badusage "bad options\n"; initdebug('git-debrebase '); enabledebug if $debuglevel;