See git-debrebase(1), git-debrebase(5), dgit-maint-debrebase(7) (in dgit).
END
-our ($opt_force, $opt_careful, $opt_noop_ok, @opt_anchors);
+our ($opt_force, $opt_noop_ok, $opt_merges, @opt_anchors);
our ($opt_defaultcmd_interactive);
-$opt_careful = 0;
-
our $us = qw(git-debrebase);
our $wrecknoteprefix = 'refs/debrebase/wreckage';
@deferred_update_messages = ();
}
-sub get_tree ($) {
+sub get_tree ($;$$) {
# tree object name => ([ $name, $info ], ...)
# where $name is the sort key, ie has / at end for subtrees
# $info is the LHS from git-ls-tree (<mode> <type> <hash>)
- # will crash if $x does not exist, so don't do that;
+ # without $precheck, will crash if $x does not exist, so don't do that;
# instead pass '' to get ().
- my ($x) = @_;
+ my ($x, $precheck, $recurse) = @_;
return () if !length $x;
+ if ($precheck) {
+ my ($type, $dummy) = git_cat_file $x, [qw(tree missing)];
+ return () if $type eq 'missing';
+ }
+
+ confess "get_tree needs object not $x ?" unless $x =~ m{^[0-9a-f]+\:};
+
our (@get_tree_memo, %get_tree_memo);
my $memo = $get_tree_memo{$x};
return @$memo if $memo;
local $Debian::Dgit::debugcmd_when_debuglevel = 3;
my @l;
- my @cmd = (qw(git ls-tree -z --full-tree --), $x);
+ my @cmd = (qw(git ls-tree -z --full-tree));
+ push @cmd, qw(-r) if $recurse;
+ push @cmd, qw(--), $x;
my $o = cmdoutput @cmd;
$o =~ s/\0$//s;
my $last = '';
return $snags_forced || $snags_tripped;
}
+sub record_gdrlast ($$) {
+ my ($gdrlast, $newvalue) = @_;
+ push @deferred_updates, "update $gdrlast $newvalue $git_null_obj";
+}
+
sub gbp_pq_export ($$$) {
my ($bname, $base, $tip) = @_;
# must be run in a workarea. $bname and patch-queue/$bname
}
-# xxx allow merge resolution separately from laundering, before git merge
-#
-# xxx general gdr docs highlight forbidden things
-# xxx general gdr docs list allowable things ?
-# xxx general gdr docs explicitly forbid some rebase
+# MERGE-TODO allow merge resolution separately from laundering, before git merge
# later/rework?
# use git-format-patch?
runcmd @git, qw(checkout -q -b mergec), $merged_pq;
merge_attempt_cmd($wrecknotes, qw(gbp pq import));
+ # MERGE-TODO consider git-format-patch etc. instead,
+ # since gbp pq doesn't always round-trip :-/
# OK now we are on patch-queue/merge, and we need to rebase
# onto the intended parent and drop the patches from each one
if (@p == 2 and
$r->{Msg} =~ m{^\[git-debrebase merged-breakwater.*\]$}m) {
- # xxx ^ metadata tag needs adding to (5)
return $classify->("MergedBreakwaters");
}
if ($r->{Msg} =~ m{^\[(git-debrebase|dgit)[: ].*\]$}m) {
return $unknown->("octopus merge");
}
- if (!$ENV{GIT_DEBREBASE_EXPERIMENTAL_MERGE}) {
+ if (!$opt_merges) {
return $unknown->("general two-parent merge");
}
# which was reachable via ffq-prev is no longer findable.
# This is suboptimal, but if it all works we'll have done
# the right thing.
- # xxx we should warn the user in the docs about this
+ # MERGE-TODO we should warn the user in the docs about this
my $ok=1;
my $best_anchor;
printdebug "WALK REWRITING NOW cl=$cl procd=$procd\n";
}
}
- if ($rewriting || $opt_careful) {
+ if ($rewriting) {
read_tree_upstream $want_upstream, 0, $want_debian;
my $newtree = cmdoutput @git, qw(write-tree);
sub update_head_postlaunder ($$$) {
my ($old, $tip, $reflogmsg) = @_;
- return if $tip eq $old;
+ return if $tip eq $old && !@deferred_updates;
print "git-debrebase: laundered (head was $old)\n";
update_head $old, $tip, $reflogmsg;
# no tree changes except debian/patches
# ffq-prev is ahead of us, and the only tree changes it has
# are possibly addition of things in debian/patches/.
# Just wind forwards rather than making a pointless pseudomerge.
- push @deferred_updates,
- "update $gdrlast $ffq_prev_commitish $git_null_obj";
+ record_gdrlast $gdrlast, $ffq_prev_commitish;
update_head_checkout $old_head, $ffq_prev_commitish,
"stitch (fast forward)";
return;
'Declare fast forward / record previous work',
"[git-debrebase pseudomerge: $prose]",
];
- push @deferred_updates, "update $gdrlast $new_head $git_null_obj";
+ record_gdrlast $gdrlast, $new_head;
update_head $old_head, $new_head, "stitch: $prose";
}
}
}
+sub check_series_has_all_patches ($) {
+ my ($head) = @_;
+ my $seriesfn = 'debian/patches/series';
+ my ($dummy, $series) = git_cat_file "$head:$seriesfn",
+ [qw(blob missing)];
+ $series //= '';
+ my %series;
+ foreach my $f (grep /\S/, grep {!m/^\s\#/} split /\n/, $series) {
+ fail "patch $f repeated in $seriesfn !" if $series{$f}++;
+ }
+ foreach my $patchfile (get_tree "$head:debian/patches", 1,1) {
+ my ($f,$i) = @$patchfile;
+ next if $series{$f};
+ next if $f eq 'series';
+ snag 'unused-patches', "Unused patch file $f will be discarded";
+ }
+}
+
sub cmd_convert_from_gbp () {
badusage "want only 1 optional argument, the upstream git commitish"
unless @ARGV<=1;
"upstream ($upstream) contains debian/ directory";
}
+ check_series_has_all_patches $old_head;
+
my $previous_dgit_view = eval {
my @clogcmd = qw(dpkg-parsechangelog --format rfc822 -n2);
my ($lvsn, $suite);
my $mtag = cmdoutput @git, qw(describe --always --abbrev=0 --match),
$mtag_pat;
die "could not find suitable maintainer view tag $mtag_pat\n"
- unless $mtag_pat =~ m{/};
+ unless $mtag =~ m{/};
is_fast_fwd $mtag, 'HEAD' or
die "HEAD is not FF from maintainer tag $mtag!";
my $dtag = "archive/$mtag";
+ git_get_ref "refs/tags/$dtag" or
+ die "dgit view tag $dtag not found\n";
is_fast_fwd $mtag, $dtag or
- die "dgit view tag $dtag is not FF from maintainer tag $mtag";
+ die "dgit view tag $dtag is not FF from maintainer tag $mtag\n";
print "will stitch in dgit view, $dtag\n";
git_rev_parse $dtag;
};
if (!$previous_dgit_view) {
$@ =~ s/^\n+//;
chomp $@;
- print STDERR "cannot stitch in dgit view: $@\n";
+ print STDERR <<END;
+Cannot confirm dgit view: $@
+Failed to stitch in dgit view (see messages above).
+dgit --overwrite will be needed on the first dgit push after conversion.
+END
}
snags_maybe_bail_early();
ffq_check $work;
snags_maybe_bail();
update_head_checkout $old_head, $work, 'convert-from-gbp';
+ print <<END or die $!;
+git-debrebase: converted from patched-unapplied (gbp) branch format, OK
+END
}
sub cmd_convert_to_gbp () {
}
}
+ check_series_has_all_patches $head;
+
snags_maybe_bail_early();
my $version = upstreamversion $clogp->{Version};
sub cmd_record_resolved_merge () {
badusage "record-resolved-merge takes no further arguments" if @ARGV;
- # xxx needs documentation
+ # MERGE-TODO needs documentation
my $new = get_head();
my $method;
'anchor=s' => \@opt_anchors,
'--dgit=s' => \($dgit[0]),
'force!',
+ 'experimental-merge-resolution!', \$opt_merges,
'-i:s' => sub {
my ($opt,$val) = @_;
badusage "git-debrebase: no cuddling to -i for git-rebase"