# usages:
#
# git-debrebase [<options>] new-upstream-v0 \
-# <new-version> <orig-commitish>
-# [<extra-orig-name> <extra-orig-commitish> ...]
+# <new-version> <orig-commitish> \
+# [<extra-orig-name> <extra-orig-commitish> ...] \
# [<git-rebase options>...]
#
# git-debrebase [<options> --] [<git-rebase options...>]
# git-debrebase [<options>] analyse
# git-debrebase [<options>] launder # prints breakwater tip etc.
# git-debrebase [<options>] downstream-rebase-launder-v0 # experimental
+#
+# git-debrebase [<options>] gbp2debrebase-v0 \
+# <upstream>
# problems / outstanding questions:
#
sub get_commit ($) {
my ($objid) = @_;
- my $data = git_cat_file $objid, 'commit';
+ my $data = (git_cat_file $objid, 'commit');
$data =~ m/(?<=\n)\n/ or die "$objid ($data) ?";
return ($`,$');
}
my @cmd = (@git, qw(diff-tree -z --no-renames));
push @cmd, @$opts;
push @cmd, "$_:" foreach $x, $y;
- push @cmd, @$limits;
+ push @cmd, '--', @$limits;
my $diffs = cmdoutput @cmd;
foreach (split /\0/, $diffs) { $fn->(); }
};
if ($mode eq 'A' && !m/\.series$/s) {
$ok = 1;
} elsif ($mode eq 'M' && $_ eq 'series') {
- my $x_s = git_cat_file "$x:debian/patches/series", 'blob';
- my $y_s = git_cat_file "$y:debian/patches/series", 'blob';
+ my $x_s = (git_cat_file "$x:debian/patches/series", 'blob');
+ my $y_s = (git_cat_file "$y:debian/patches/series", 'blob');
chomp $x_s; $x_s .= "\n";
$ok = $x_s eq substr($y_s, 0, length $x_s);
} else {
return cmdoutput @cmd;
}
+our $fproblems;
+sub fproblem ($) {
+ my ($msg) = @_;
+ $fproblems++;
+ print STDERR "git-debrebase: safety catch tripped: $msg\n";
+}
+sub fproblems_maybe_bail () {
+ if ($fproblems) {
+ if ($opt_force) {
+ printf STDERR
+ "safety catch trips (%d) overriden by --force\n",
+ $fproblems;
+ } else {
+ fail sprintf
+ "safety catch trips (%d) (you could --force)",
+ $fproblems;
+ }
+ }
+}
+
# classify returns an info hash like this
# CommitId => $objid
# Hdr => # commit headers, including 1 final newline
sub update_head_checkout ($$$) {
my ($old, $new, $mrest) = @_;
- my $symref = git_get_symref();
- runcmd @git, qw(checkout), $new, qw(.);
update_head $old, $new, $mrest;
+ runcmd @git, qw(reset --hard);
}
sub update_head_postlaunder ($$$) {
my $old_upstream = parsecommit
$old_upstream_update_cl->{OrigParents}[0]{CommitId};
- my $problems = 0;
- my $problem = sub {
- my ($msg) = @_;
- $problems++;
- print STDERR "preflight check failed: $msg\n";
- };
-
$piece->('', Old => $old_upstream->{CommitId});
if ($old_upstream->{Msg} =~ m{^\[git-debrebase }m) {
if ($old_upstream->{Msg} =~
- m{^\[git-debrebase new-upstream combine \.((?: $extra_orig_namepart_re)+)\]}
+ m{^\[git-debrebase (?:\w*-)?upstream combine \.((?: $extra_orig_namepart_re)+)\]}
) {
my @oldpieces = ('', split / /, $1);
my $parentix = -1 + scalar @{ $old_upstream->{Parents} };
$piece->($n, Old => $old_upstream->{CommitId}.'^'.$parentix);
}
} else {
- $problem->("previous upstream $old_upstream->{CommitId} is from".
- " git-debrebase but not a \`new-upstream combine' commit");
+ fproblem "previous upstream $old_upstream->{CommitId} is from".
+ " git-debrebase but not an \`upstream combine' commit";
}
}
foreach my $pc (values %pieces) {
if (!$pc->{Old}) {
- $problem->("introducing upstream piece \`$pc->{Name}'");
+ fproblem "introducing upstream piece \`$pc->{Name}'";
} elsif (!$pc->{New}) {
- $problem->("dropping upstream piece \`$pc->{Name}'");
+ fproblem "dropping upstream piece \`$pc->{Name}'";
} elsif (!is_fast_fwd $pc->{Old}, $pc->{New}) {
- $problem->("not fast forward: $pc->{Name} $pc->{Old}..$pc->{New}");
+ fproblem "not fast forward: $pc->{Name} $pc->{Old}..$pc->{New}";
}
}
printdebug "%pieces = ", (dd \%pieces), "\n";
printdebug "\@newpieces = ", (dd \@newpieces), "\n";
- if ($problems) {
- if ($opt_force) {
- printf STDERR
- "preflight check failures (%d) overriden by --force\n",
- $problems;
- } else {
- fail sprintf
- "preflight check failures (%d) (you could --force)",
- $problems;
- }
- }
+ fproblems_maybe_bail();
my $new_bw;
in_workarea sub {
my @upstream_merge_parents;
- if (!$problems) {
+ if (!$fproblems) {
push @upstream_merge_parents, $old_upstream->{CommitId};
}
# now it's for the user to sort out
}
+sub cmd_gbp2debrebase () {
+ badusage "needs 1 optional argument, the upstream" unless @ARGV<=1;
+ my ($upstream_spec) = @ARGV;
+ $upstream_spec //= 'refs/heads/upstream';
+ my $upstream = git_rev_parse $upstream_spec;
+ my $old_head = get_head();
+
+ my $upsdiff = get_differs $upstream, $old_head;
+ if ($upsdiff & D_UPS) {
+ runcmd @git, qw(--no-pager diff),
+ $upstream, $old_head,
+ qw( -- :!/debian :/);
+ fail "upstream ($upstream_spec) and HEAD are not identical in upstream files";
+ }
+
+ if (!is_fast_fwd $upstream, $old_head) {
+ fproblem "upstream ($upstream) is not an ancestor of HEAD";
+ } else {
+ my $wrong = cmdoutput
+ (@git, qw(rev-list --ancestry-path), "$upstream..HEAD",
+ qw(-- :/ :!/debian));
+ if (length $wrong) {
+ fproblem "history between upstream ($upstream) and HEAD contains direct changes to upstream files - are you sure this is a gbp (patches-unapplied) branch?";
+ print STDERR "list expected changes with: git log --stat --ancestry-path $upstream_spec..HEAD -- :/ ':!/debian'\n";
+ }
+ }
+
+ if ((git_cat_file "$upstream:debian")[0] ne 'missing') {
+ fproblem "upstream ($upstream) contains debian/ directory";
+ }
+
+ fproblems_maybe_bail();
+
+ my $work;
+
+ fresh_workarea();
+ in_workarea sub {
+ runcmd @git, qw(checkout -q -b gdr-internal), $old_head;
+ # make a branch out of the patch queue - we'll want this in a mo
+ runcmd qw(gbp pq import);
+ # strip the patches out
+ runcmd @git, qw(checkout -q gdr-internal~0);
+ rm_subdir_cached 'debian/patches';
+ $work = make_commit ['HEAD'], [
+ 'git-debrebase import: drop patch queue',
+ 'Delete debian/patches, as part of converting to git-debrebase format.',
+ '[git-debrebase gbp2debrebase drop-patches]'
+ ];
+ # make the breakwater pseudomerge
+ # the tree is already exactly right
+ $work = make_commit [$work, $upstream], [
+ 'git-debrebase import: declare upstream',
+ 'First breakwater merge.',
+ '[git-debrebase declare-upstream breakwater]'
+ ];
+
+ # rebase the patch queue onto the new breakwater
+ runcmd @git, qw(reset --quiet --hard patch-queue/gdr-internal);
+ runcmd @git, qw(rebase --quiet --onto), $work, qw(gdr-internal);
+ $work = get_head();
+ };
+
+ update_head_checkout $old_head, $work, 'gbp2debrebase';
+}
+
sub cmd_downstream_rebase_launder_v0 () {
badusage "needs 1 argument, the baseline" unless @ARGV==1;
my ($base) = @ARGV;