#
# git-debrebase [<options> --] [<git-rebase options...>]
# git-debrebase [<options>] analyse
+# git-debrebase [<options>] breakwater # prints breakwater tip only
# git-debrebase [<options>] launder # prints breakwater tip etc.
+# git-debrebase [<options>] stitch [--prose=<for commit message>]
# git-debrebase [<options>] downstream-rebase-launder-v0 # experimental
#
-# git-debrebase [<options>] gbp2debrebase-v0 \
-# <upstream>
+# git-debrebase [<options>] convert-from-gbp <upstream-git-rev>
# problems / outstanding questions:
#
sub cfg ($;$) {
my ($k, $optional) = @_;
- $/ = "\0";
+ local $/ = "\0";
my @cmd = qw(git config -z);
push @cmd, qw(--get-all) if wantarray;
push @cmd, $k;
# Upstream
# AddPatches
# Mixed
-# Unknown
#
# Pseudomerge
# has additional entres in classification result
# BreakwaterUpstreamMerge
# has additional entry in classification result
# OrigParents = [ subset of Parents ] # singleton list
+#
+# Unknown
+# has additional entry in classification result
+# Why => "prose"
sub parsecommit ($;$) {
my ($objid, $p_ref) = @_;
};
my $unknown = sub {
my ($why) = @_;
- $r = { %$r, Type => qw(Unknown) };
+ $r = { %$r, Type => qw(Unknown), Why => $why };
printdebug " ** Unknown\n";
return $r;
};
my @overwritten = grep { $_->{Differs} } @p;
confess "internal error $objid ?" unless @overwritten==1;
return $classify->(qw(Pseudomerge),
- Overwritten => $overwritten[0],
+ Overwritten => [ $overwritten[0] ],
Contributor => $identical[0]);
}
if (@p == 2 && @identical == 2) {
} @p;
return $classify->(qw(Pseudomerge),
SubType => qw(Ambiguous),
- Overwritten => $bytime[0],
+ Overwritten => [ $bytime[0] ],
Contributor => $bytime[1]);
}
foreach my $p (@p) {
return $unknown->("complex merge");
}
+sub breakwater_of ($) {
+ my ($head) = @_; # must be laundered
+ my $breakwater;
+ my $unclean = sub {
+ my ($why) = @_;
+ fail "branch needs laundering (run git-debrebase): $why";
+ };
+ for (;;) {
+ my $cl = classify $head;
+ my $ty = $cl->{Type};
+ if ($ty eq 'Packaging' or
+ $ty eq 'Changelog') {
+ $breakwater //= $head;
+ } elsif ($ty eq 'BreakwaterUpstreamMerge' or
+ $ty eq 'BreakwaterStart') {
+ $breakwater //= $head;
+ last;
+ } elsif ($ty eq 'Upstream') {
+ $unclean->("packaging change ($breakwater)".
+ " follows upstream change (eg $head)")
+ if defined $breakwater;
+ } elsif ($ty eq 'Mixed') {
+ $unclean->('found mixed upstream/packaging commit ($head)');
+ } elsif ($ty eq 'Pseudomerge' or
+ $ty eq 'AddPatches') {
+ $unclean->("found interchange conversion commit ($ty, $head)");
+ } elsif ($ty eq 'DgitImportUnpatched') {
+ $unclean->("found dgit dsc import ($head)");
+ } else {
+ fail "found unprocessable commit, cannot cope: $head; $cl->{Why}";
+ }
+ $head = $cl->{Parents}[0]{CommitId};
+ }
+ return $breakwater;
+}
+
sub walk ($;$$);
sub walk ($;$$) {
my ($input,
# suite intended by the non-dgit NMUer, and later
# pseudomerges may represent in-archive copies.
my $ovwrs = $pm->{Overwritten};
- printf $report " PM=%s \@Overwr:%d", $pm, (scalar @$ovwrs)
+ printf $report " PM=%s \@Overwr:%d",
+ $pm->{CommitId}, (scalar @$ovwrs)
if $report;
if (@$ovwrs != 1) {
printdebug "*** WALK BOMB DgitImportUnpatched\n";
%$cl,
SpecialMethod => 'DgitImportDebianUpdate',
$xmsg->("convert dgit import: debian changes")
+ }, {
+ %$cl,
+ SpecialMethod => 'DgitImportUpstreamUpdate',
+ $xmsg->("convert dgit import: upstream update",
+ " breakwater")
};
- my $differs = (get_differs $ovwr, $cl->{Tree});
- printf $report " Differs=%#x", $differs if $report;
- if ($differs & D_UPS) {
- printf $report " D_UPS" if $report;
- # This will also trigger if a non-dgit git-based NMU
- # deleted .gitignore (which is a thing that some of
- # the existing git tools do if the user doesn't
- # somehow tell them not to). Ah well.
- push @brw_cl, {
- %$cl,
- SpecialMethod => 'DgitImportUpstreamUpdate',
- $xmsg->("convert dgit import: upstream changes",
- " breakwater")
- };
- }
$prline->(" Import");
$rewrite_from_here->();
$upp_limit //= $#upp_cl; # further, deeper, patches discarded
- die 'BUG $upp_limit is not used anywhere?';
$cur = $ovwr;
next;
} else {
runcmd @git, qw(read-tree), $treeish;
$read_tree_debian->($build);
};
+
+ $#upp_cl = $upp_limit if defined $upp_limit;
my $committer_authline = calculate_committer_authline();
next;
} elsif ($method eq 'DgitImportDebianUpdate') {
$read_tree_debian->($cltree);
- rm_subdir_cached qw(debian/patches);
} elsif ($method eq 'DgitImportUpstreamUpdate') {
+ confess unless $rewriting;
+ my $differs = (get_differs $build, $cltree);
+ next unless $differs & D_UPS;
$read_tree_upstream->($cltree);
push @parents, map { $_->{CommitId} } @{ $cl->{OrigParents} };
} else {
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{^parent .*\n}{}mg;
$ch =~ s{(?=^author)}{
join '', map { "parent $_\n" } @parents
}me or confess "$ch ?";
sub defaultcmd_rebase () {
my $old = get_head();
+ my ($status, $message) = record_ffq_prev();
+ if ($status eq 'written' || $status eq 'exists') {
+ } else {
+ fproblem $status, "could not record ffq-prev: $message";
+ fproblems_maybe_bail();
+ }
my ($tip,$breakwater) = walk $old;
update_head_postlaunder $old, $tip, 'launder for rebase';
runcmd @git, qw(rebase), @ARGV, $breakwater;
STDOUT->error and die $!;
}
+sub ffq_prev_branchinfo () {
+ # => ('status', "message", [$current, $ffq_prev])
+ # 'status' may be
+ # branch message is undef
+ # weird-symref } no $current,
+ # notbranch } no $ffq_prev
+ my $current = git_get_symref();
+ return ('detached', 'detached HEAD') unless defined $current;
+ return ('weird-symref', 'HEAD symref is not to refs/')
+ unless $current =~ m{^refs/};
+ my $ffq_prev = "refs/$ffq_refprefix/$'";
+ return ('branch', undef, $current, $ffq_prev);
+}
+
sub record_ffq_prev () {
# => ('status', "message")
# 'status' may be
# if not ff from some branch we should be ff from, is an fproblem
# if "written", will have printed something about that to stdout,
# and also some messages about ff checks
- my $current = git_get_symref();
- return ('detached', 'detached HEAD') unless defined $current;
- return ('weird-symref', 'HEAD symref is not to refs/')
- unless $current =~ m{^refs/};
- my $ffq_prev = "refs/$ffq_refprefix/$'";
+ my ($status, $message, $current, $ffq_prev) = ffq_prev_branchinfo();
+ return ($status, $message) unless $status eq 'branch';
my $currentval = get_head();
}
}
-sub cmd_gbp2debrebase () {
- badusage "needs 1 optional argument, the upstream" unless @ARGV<=1;
+sub cmd_breakwater () {
+ badusage "no arguments allowed" if @ARGV;
+ my $bw = breakwater_of git_rev_parse 'HEAD';
+ print "$bw\n" or die $!;
+}
+
+sub cmd_stitch () {
+ my $prose = '';
+ GetOptions('prose=s', \$prose) or die badusage("bad options to stitch");
+ badusage "no arguments allowed" if @ARGV;
+ my ($status, $message, $current, $ffq_prev) = ffq_prev_branchinfo();
+ if ($status ne 'branch') {
+ fproblem $status, "could not check ffq-prev: $message";
+ fproblems_maybe_bail();
+ }
+ my $prev = $ffq_prev && git_get_ref $ffq_prev;
+ if (!$prev) {
+ fail "No ffq-prev to stitch." unless $opt_noop_ok;
+ }
+ fresh_workarea();
+ my $old_head = get_head();
+ my $new_head = make_commit [ $old_head, $ffq_prev ], [
+ 'Declare fast forward / record previous work',
+ "[git-debrebase pseudomerge: stitch$prose]",
+ ];
+ my @upd_cmd = (@git, qw(update-ref --stdin));
+ debugcmd '>|', @upd_cmd;
+ open U, "|-", @upd_cmd or die $!;
+ my $u = <<END;
+update HEAD $new_head $old_head
+delete $ffq_prev $prev
+END
+ printdebug ">= ", $_, "\n" foreach split /\n/, $u;
+ print U $u;
+ printdebug ">\$\n";
+ close U or failedcmd @upd_cmd;
+}
+
+sub cmd_convert_from_gbp () {
+ badusage "needs 1 optional argument, the upstream git rev"
+ unless @ARGV<=1;
my ($upstream_spec) = @ARGV;
$upstream_spec //= 'refs/heads/upstream';
my $upstream = git_rev_parse $upstream_spec;
runcmd @git, qw(checkout -q gdr-internal~0);
rm_subdir_cached 'debian/patches';
$work = make_commit ['HEAD'], [
- 'git-debrebase import: drop patch queue',
+ 'git-debrebase convert-from-gbp: drop patches from tree',
'Delete debian/patches, as part of converting to git-debrebase format.',
- '[git-debrebase: gbp2debrebase, drop patches]'
+ '[git-debrebase convert-from-gbp: drop patches from tree]'
];
# make the breakwater pseudomerge
# the tree is already exactly right
$work = git_rev_parse 'HEAD';
};
- update_head_checkout $old_head, $work, 'gbp2debrebase';
+ update_head_checkout $old_head, $work, 'convert-from-gbp';
}
sub cmd_downstream_rebase_launder_v0 () {