3 # Script helping make fast-forwarding histories while still rebasing
4 # upstream deltas when working on Debian packaging
6 # Copyright (C)2017 Ian Jackson
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
29 my @cmd = qw(git config -z);
30 push @cmd, qw(--get-all) if wantarray;
32 my $out = cmdoutput @cmd;
33 return split /\0/, $out;
39 # git debrebase launder
43 my ($type,$data) = git_cat_file $objid;
44 die unless $type eq 'commit';
45 $data =~ m/(?<=\n)\n/;
49 sub D_DEB () { return 0x1; }
50 sub D_UPS () { return 0x2; }
51 sub D_PAT_ADD () { return 0x4; }
52 sub D_PAT_OTH () { return 0x8; }
57 my ($h,$m) = get_commit $objid;
59 my ($t) = $h =~ m/^tree (\w+)$/m or die $cur;
60 my (@ph) = $h =~ m/^parent (\w+)$/m;
70 foreach my $ph (@ph) {
74 Differs => (get_differs $t, $ph),
79 my $d = $r->{Parents}[0]{Differs};
80 if ($d == D_DPAT_ADD) {
81 return $classify->(qw(AddPatches));
82 } elsif ($d & (D_DPAT_ADD|D_DPAT_OTH)) {
83 return $unknown->("edits debian/patches");
84 } elsif ($d == D_DEB) {
85 return $classify->(qw(Packaging));
86 } elsif ($d == D_UPS) {
87 return $classify->(qw(Upstream));
88 } elsif ($d == D_DEB|D_UPS) {
89 return $classify->(qw(Mixed));
91 return $unknown->("no changes");
93 confess "internal error $objid ?";
97 return $unknown->("origin commit");
100 my @identical = grep { !$_->{Differs} } @p;
101 if (@p == 2 && @identical == 1) {
102 my @overwritten = grep { $_->{Differs} } @p;
103 confess "internal error $objid ?" unless @overwritten==1;
104 return $classify->(qw(Pseudomerge),
105 Overwritten => $overwritten[0],
106 Contributor => $identical[0]);
108 if (@p == 2 && @identical == 2) {
109 my @bytime = nsort_by {
110 my ($ph,$pm) = get_commit $_->{CommitId};
111 $ph =~ m/^committer .* (\d+) [-+]\d+$/m or die "$_->{CommitId} ?";
114 return $classify->(qw(Pseudomerge),
115 Xtype => qw(Ambiguous),
116 Overwritten => $bytime[0],
117 Contributyor => $bytime[1]);
120 my ($type) = git_cat_file "$p^1";
121 $p->{IsOrigin} = $type eq 'missing';
123 if (!grep { !$_->{IsOrigin} } @p
124 && $m =~ m{^\[dgit import unpatched .*\]$}m) {
125 return $classify->(qw(DgitImport));
128 my ($stype, $series) = git_cat_file "$t:debian/patches/series";
129 my $haspatches = $stype ne 'missing' && $series =~ m/^\s*[^#\n\t ]/m;
131 # how to decide about l/r ordering of breakwater merges
132 # git --topo-order prefers to expand 2nd parent first
133 # easy rune to look for debian/ history so that should
137 !$p[0]{IsOrigin} && # breakwater merge never starts with an origin
138 !($p[0]{Differs} & ~D_DEB) &&
139 !($p[1]{Differs} & ~D_UPS)) {
140 return $classify->(qw(BreakwaterUpstreamMerge),
144 return $unknown->("complex merge");
147 ((git_cat_file "$t:debian/patches/series"
158 # changes on debian/patches, discard it
171 # go through commits backwards
172 # we generate two lists of commits to apply
173 my (@deb_cl, @ups_cl);
174 my $cur = git_rev_parse('HEAD');
178 if ($ARGV[0] eq 'launder') {
183 print Dumper(cfg('wombat.foo.bar'));
189 when starting must record original start (for ff)