# Script helping make fast-forwarding histories while still rebasing
# upstream deltas when working on Debian packaging
#
-# Copyright (C)2017,2018 Ian Jackson
+# Copyright (C)2017-2019 Ian Jackson
+# Copyright (C)2019 Niko Tyni
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
git-debrebase [<options>] prepush [--prose=...]
git-debrebase [<options>] quick|conclude
git-debrebase [<options>] new-upstream <new-version> [<details ...>]
- git-debrebase [<options>] convert-from-gbp [<upstream-commitish>]
+ git-debrebase [<options>] convert-from-* ...
...
See git-debrebase(1), git-debrebase(5), dgit-maint-debrebase(7) (in dgit).
END
our $rd;
our $workarea;
-our @git = qw(git);
our @dgit = qw(dgit);
sub in_workarea ($) {
my @upd_cmd = (git_update_ref_cmd "debrebase: $mrest", qw(--stdin));
debugcmd '>|', @upd_cmd;
- open U, "|-", @upd_cmd or confess $!;
+ open U, "|-", @upd_cmd or confess "$!";
foreach (@$updates) {
printdebug ">= ", $_, "\n";
- print U $_, "\n" or confess $!;
+ print U $_, "\n" or confess "$!";
}
printdebug ">\$\n";
close U or failedcmd @upd_cmd;
return $&;
}
-sub rm_subdir_cached ($) {
- my ($subdir) = @_;
- runcmd @git, qw(rm --quiet -rf --cached --ignore-unmatch), $subdir;
-}
-
-sub read_tree_subdir ($$) {
- my ($subdir, $new_tree_object) = @_;
- rm_subdir_cached $subdir;
- runcmd @git, qw(read-tree), "--prefix=$subdir/", $new_tree_object;
-}
-
-sub read_tree_debian ($) {
- my ($treeish) = @_;
- read_tree_subdir 'debian', "$treeish:debian";
- rm_subdir_cached 'debian/patches';
-}
-
-sub read_tree_upstream ($;$$) {
- my ($treeish, $keep_patches, $tree_with_debian) = @_;
- # if $tree_with_debian is supplied, will use that for debian/
- # otherwise will save and restore it.
- my $debian =
- $tree_with_debian ? "$tree_with_debian:debian"
- : cmdoutput @git, qw(write-tree --prefix=debian/);
- runcmd @git, qw(read-tree), $treeish;
- read_tree_subdir 'debian', $debian;
- rm_subdir_cached 'debian/patches' unless $keep_patches;
-};
-
-sub make_commit ($$) {
- my ($parents, $message_paras) = @_;
- my $tree = cmdoutput @git, qw(write-tree);
- my @cmd = (@git, qw(commit-tree), $tree);
- push @cmd, qw(-p), $_ foreach @$parents;
- push @cmd, qw(-m), $_ foreach @$message_paras;
- return cmdoutput @cmd;
-}
-
our @snag_force_opts;
sub snag ($$;@) {
my ($tag,$msg) = @_; # ignores extra args, for benefit of keycommits
if ($any) {
open S, $seriesfile or confess "$seriesfile $!";
while (my $patch = <S>) {
- chomp $patch or confess $!;
+ chomp $patch or confess "$!";
$prereq{$patch} //= {};
foreach my $earlier (@earlier) {
$prereq{$patch}{$earlier}{$s}++ and confess;
};
};
- open NS, '>', $seriesfile or confess $!;
+ open NS, '>', $seriesfile or confess "$!";
while (keys %prereq) {
my $best;
$best = $try;
}
printdebug "merge_series series next $best\n";
- print NS "$best\n" or confess $!;
+ print NS "$best\n" or confess "$!";
delete $prereq{$best};
foreach my $gp (values %prereq) {
delete $gp->{$best};
my $tree = cmdoutput @git, qw(write-tree);
$commit =~ s{^parent (\S+)$}{parent $build}m or confess;
$commit =~ s{^tree (\S+)$}{tree $tree}m or confess;
- open C, ">", "../mcommit" or confess $!;
- print C $commit or confess $!;
- close C or confess $!;
- $build = cmdoutput @git, qw(hash-object -w -t commit ../mcommit);
+ open C, ">", "../mcommit" or confess "$!";
+ print C $commit or confess "$!";
+ close C or confess "$!";
+ $build = hash_commit '../mcommit';
}
$result = $build;
mwrecknote($wrecknotes, 'merged-result', $result);
confess __ "internal error" unless $build eq (pop @processed)->{CommitId};
in_workarea sub {
- mkdir $rd or $!==EEXIST or confess $!;
+ mkdir $rd or $!==EEXIST or confess "$!";
my $current_method;
my $want_debian = $build;
my $want_upstream = $build;
or confess "$ch ?";
}
my $cf = "$rd/m$rewriting";
- open CD, ">", $cf or confess $!;
- print CD $ch, "\n", $cl->{Msg} or confess $!;
- close CD or confess $!;
+ open CD, ">", $cf or confess "$!";
+ print CD $ch, "\n", $cl->{Msg} or confess "$!";
+ close CD or confess "$!";
my @cmd = (@git, qw(hash-object));
push @cmd, qw(-w) if $rewriting;
push @cmd, qw(-t commit), $cf;
$old = git_rev_parse 'HEAD';
}
my ($dummy,$breakwater) = walk $old, 1,*STDOUT;
- STDOUT->error and confess $!;
+ STDOUT->error and confess "$!";
}
sub ffq_check ($;$$) {
# normally $currentval should be HEAD
my ($currentval, $ff, $notff) =@_;
- $ff //= sub { print $_[0] or confess $!; };
+ $ff //= sub { print $_[0] or confess "$!"; };
$notff //= \&snag;
my ($status, $message, $current, $ffq_prev, $gdrlast)
stitch($dangling_head, $ffq_prev, $gdrlast, $ffq_prev_commitish, $prose);
}
-sub upstream_commitish_search ($$) {
- my ($upstream_version, $tried) = @_;
- # todo: at some point maybe use git-deborig to do this
- foreach my $tagpfx ('', 'v', 'upstream/') {
- my $tag = $tagpfx.(dep14_version_mangle $upstream_version);
- my $new_upstream = git_get_ref "refs/tags/$tag";
- push @$tried, $tag;
- return $new_upstream if length $new_upstream;
- }
-}
-
-sub resolve_upstream_version ($$) {
- my ($new_upstream, $upstream_version) = @_;
-
- if (!defined $new_upstream) {
- my @tried;
- $new_upstream = upstream_commitish_search $upstream_version, \@tried;
- if (!length $new_upstream) {
- fail f_
- "Could not determine appropriate upstream commitish.\n".
- " (Tried these tags: %s)\n".
- " Check version, and specify upstream commitish explicitly.",
- "@tried";
- }
- }
- $new_upstream = git_rev_parse $new_upstream;
-
- return $new_upstream;
-}
-
sub cmd_new_upstream () {
# automatically and unconditionally launders before rebasing
# if rebase --abort is used, laundering has still been done
$new_version = (new Dpkg::Version "$spec_version-1", check => 1);
}
- my $new_upstream = shift @ARGV;
+ my $new_upstream = (@ARGV && $ARGV[0] !~ m{^-}) ? shift @ARGV : undef;
my $new_upstream_version = upstreamversion $new_version;
- $new_upstream =
+ my $new_upstream_used;
+ ($new_upstream, $new_upstream_used) =
resolve_upstream_version $new_upstream, $new_upstream_version;
record_ffq_auto();
badusage "no arguments allowed" if @ARGV;
my ($status, $msg) = record_ffq_prev_deferred();
if ($status eq 'exists' && $opt_noop_ok) {
- print __ "Previous head already recorded\n" or confess $!;
+ print __ "Previous head already recorded\n" or confess "$!";
} elsif ($status eq 'deferred') {
run_deferred_updates 'record-ffq-prev';
} else {
sub cmd_anchor () {
badusage __ "no arguments allowed" if @ARGV;
my ($anchor, $bw) = keycommits +(git_rev_parse 'HEAD'), 0,0;
- print "$anchor\n" or confess $!;
+ print "$anchor\n" or confess "$!";
}
sub cmd_breakwater () {
badusage __ "no arguments allowed" if @ARGV;
my ($anchor, $bw) = keycommits +(git_rev_parse 'HEAD'), 0,0;
- print "$bw\n" or confess $!;
+ print "$bw\n" or confess "$!";
}
sub cmd_status () {
my $prcommitinfo = sub {
my ($cid) = @_;
- flush STDOUT or confess $!;
+ flush STDOUT or confess "$!";
runcmd @git, qw(--no-pager log -n1),
'--pretty=format: %h %s%n',
$cid;
update_head_checkout $old_head, $new_head, $mrest;
}
+sub cmd_convert_from_unapplied () { cmd_convert_from_gbp(); }
sub cmd_convert_from_gbp () {
badusage __ "want only 1 optional argument, the upstream git commitish"
unless @ARGV<=1;
my ($upstream_spec) = @ARGV;
my $upstream_version = upstreamversion $version;
- my $upstream =
+ my ($upstream, $upstream_used) =
resolve_upstream_version($upstream_spec, $upstream_version);
my ($old_head, $gdrlastinfo) = begin_convert_from();
runcmd @git, qw(--no-pager diff --stat),
$upstream, $old_head,
qw( -- :!/debian :/);
- fail f_ <<END, $upstream_spec, $upstream_spec;
+ fail f_ <<END, $upstream_used, $upstream;
upstream (%s) and HEAD are not
identical in upstream files. See diffstat above, or run
git diff %s HEAD -- :!/debian :/
if (length $wrong) {
snag 'unexpected-upstream-changes', f_
"history between upstream (%s) and HEAD contains direct changes to upstream files - are you sure this is a gbp (patches-unapplied) branch?",
- $upstream;
+ $upstream_used;
print STDERR f_ "list expected changes with: %s\n",
- "git log --stat --ancestry-path $upstream_spec..HEAD -- :/ ':!/debian'";
+ "git log --stat --ancestry-path $upstream..HEAD -- :/ ':!/debian'";
}
}
};
complete_convert_from $old_head, $work, $gdrlastinfo, 'convert-from-gbp';
- print f_ <<END, $us or confess $!;
+ print f_ <<END, $us or confess "$!";
%s: converted from patched-unapplied (gbp) branch format, OK
END
}
}
snags_maybe_bail();
update_head_checkout $head, $out, "convert to gbp (v0)";
- print f_ <<END, $us,$us,$us or confess $!;
+ print f_ <<END, $us,$us,$us or confess "$!";
%s: converted to git-buildpackage branch format
%s: WARNING: do not now run "git-debrebase" any more
%s: WARNING: doing so would drop all upstream patches!
my $spec = shift @ARGV;
my $commit = git_rev_parse "$spec^{commit}";
push @upstreams, { Commit => $commit,
- Source => (f_ "%s, from command line", $ARGV[0]),
+ Source => (f_ "%s, from command line", $spec),
Only => 1,
};
}
if (!@upstreams) {
if ($do_tags) {
my @tried;
- my $ups_tag = upstream_commitish_search $version, \@tried;
- if ($ups_tag) {
- my $this = f_ "git tag %s", $tried[-1];
- push @upstreams, { Commit => $ups_tag,
+ my ($ups_tag, $ups_rev) =
+ upstream_commitish_search $version, \@tried;
+ if ($ups_rev) {
+ my $this = f_ "git tag %s", $ups_tag;
+ push @upstreams, { Commit => $ups_rev,
Source => $this,
};
} else {
END
}
- printf STDERR "Yes, will base new branch on %s\n", $result->{Source};
+ print STDERR f_ "Yes, will base new branch on %s\n", $result->{Source};
complete_convert_from $head, $result->{Result}, $gdrlastinfo,
'convert-from-dgit-view';
}
sub cmd_forget_was_ever_debrebase () {
- badusage "forget-was-ever-debrebase takes no further arguments" if @ARGV;
+ badusage __ "forget-was-ever-debrebase takes no further arguments"
+ if @ARGV;
my ($ffqstatus, $ffq_msg, $current, $ffq_prev, $gdrlast) =
ffq_prev_branchinfo();
- fail "Not suitable for recording git-debrebaseness anyway: $ffq_msg"
+ fail f_ "Not suitable for recording git-debrebaseness anyway: %s",
+ $ffq_msg
if defined $ffq_msg;
push @deferred_updates, "delete $ffq_prev";
push @deferred_updates, "delete $gdrlast";
textdomain("git-debrebase");
getoptions_main
- ("bad options\n",
+ (__ "bad options\n",
"D+" => \$debuglevel,
'noop-ok', => \$opt_noop_ok,
'f=s' => \@snag_force_opts,
'experimental-merge-resolution!', \$opt_merges,
'-i:s' => sub {
my ($opt,$val) = @_;
- badusage f_ "%s: no cuddling to -i for git-rebase", $us
+ badusage f_ "%s: with git-debrebase, get-rebase -i option may only be followed by more options (as separate arguments)", $us
if length $val;
confess if $opt_defaultcmd_interactive; # should not happen
$opt_defaultcmd_interactive = [ qw(-i) ];
push @$opt_defaultcmd_interactive, @ARGV;
@ARGV=();
},
- 'help' => sub { print __ $usage_message or confess $!; finish 0; },
+ 'help' => sub { print __ $usage_message or confess "$!"; finish 0; },
);
initdebug('git-debrebase ');
enabledebug if $debuglevel;
-my $toplevel = cmdoutput @git, qw(rev-parse --show-toplevel);
-chdir $toplevel or fail "chdir toplevel $toplevel: $!\n";
+changedir_git_toplevel();
$rd = fresh_playground "$playprefix/misc";