+sub cmd_record_ffq_prev () {
+ badusage "no arguments allowed" if @ARGV;
+ my ($status, $msg) = record_ffq_prev();
+ if ($status eq 'exists' && $opt_noop_ok) {
+ print "Previous head already recorded\n" or die $!;
+ } elsif ($status eq 'written') {
+ } else {
+ fail "Could not preserve: $msg";
+ }
+}
+
+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;
+ 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-not-ancestor',
+ "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 'unexpected-upstream-changes',
+ "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-has-debian',
+ "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 convert-from-gbp: drop patches from tree',
+ 'Delete debian/patches, as part of converting to git-debrebase format.',
+ '[git-debrebase convert-from-gbp: drop patches from tree]'
+ ];
+ # 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 breakwater: declare upstream]'
+ ];
+
+ # 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 = git_rev_parse 'HEAD';
+ };
+
+ update_head_checkout $old_head, $work, 'convert-from-gbp';
+}
+
+sub cmd_convert_to_gbp () {
+ badusage "no arguments allowed" if @ARGV;
+ my $head = get_head();
+ my $ffq = (ffq_prev_branchinfo())[3];
+ my $bw = breakwater_of $head;
+ fresh_workarea();
+ my $out;
+ in_workarea sub {
+ runcmd @git, qw(checkout -q -b bw), $bw;
+ runcmd @git, qw(checkout -q -b patch-queue/bw), $head;
+ runcmd qw(gbp pq export);
+ runcmd @git, qw(add debian/patches);
+ $out = make_commit ['HEAD'], [
+ 'Commit patch queue (converted from git-debrebase format)',
+ '[git-debrebase convert-to-gbp: commit patches]',
+ ];
+ };
+ if (defined $ffq) {
+ runcmd @git, qw(update-ref -m),
+ "debrebase: converting corresponding main branch to gbp format",
+ $ffq, $git_null_obj;
+ }
+ update_head_checkout $head, $out, "convert to gbp (v0)";
+ print <<END or die $!;
+git-debrebase: converted to git-buildpackage branch format
+git-debrebase: WARNING: do not now run "git-debrebase" any more
+git-debrebase: WARNING: doing so would drop all upstream patches!
+END
+}
+