chiark / gitweb /
git-debrebase: docs updates
[dgit.git] / git-debrebase
index df5d27e627b6c8093076b61e34dff6b58b834c30..85cf331835002b313fc761f13acc537aee93e56a 100755 (executable)
@@ -3,7 +3,7 @@
 # Script helping make fast-forwarding histories while still rebasing
 # upstream deltas when working on Debian packaging
 #
-# Copyright (C)2017 Ian Jackson
+# Copyright (C)2017,2018 Ian Jackson
 #
 # 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
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-#    git-debrebase new-upstreams-v0 \
-#             NEW-VERSION ORIG-COMMITISH
-#            [EXTRA-ORIG-NAME EXTRA-ORIG-COMMITISH ...]
 
 # usages:
-#    git-debrebase status
-#    git-debrebase start       # like ffqrebase start + debrebase launder
-#    git-debrebase new-upstream [stuff]  # see below
-#    git-debrebase <git-rebase options>  # does debrebase start if necessary
 #
-#    git-debrebase analyse
-#    git-debrebase launder     # prints breakwater tip
-#    git-debrebase create-new-upstream-breakwater [-f] <upstreaminfo>...
+#    git-debrebase [<options>] new-upstream-v0 \
+#             <new-version> <orig-commitish>
+#            [<extra-orig-name> <extra-orig-commitish> ...]
+#            [<git-rebase options>...]
 #
-# <upstreaminfo> is
-#    [,][<subdir>:][+]<commitid>[,...]
+#    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
+
+# problems / outstanding questions:
+#
+#  *  dgit push with a `3.0 (quilt)' package means doing quilt
+#     fixup.  Usually this involves recommitting the whole patch
+#     series, one at a time, with dpkg-source --commit.  This is
+#     terribly terribly slow.  (Maybe this should be fixed in dgit.)
+#
+#  * dgit push usually needs to (re)make a pseudomerge.  The "first"
+#    git-debrebase stripped out the previous pseudomerge and could
+#    have remembeed the HEAD.  But it's not quite clear what history
+#    ought to be preserved and what should be discarded.  For now
+#    the user will have to tell dgit --overwrite.
+#
+#    To fix this, do we need a new push hook for dgit ?
+#
+#  * Workflow is currently clumsy.  Lots of spurious runes to type.
+#    There's not even a guide.
 #
-# if initial comma is supplied, entries are not positional.  Unspecified
-# <subdir> means root (and there may be only one).
-# xxx want auto branch names
-# xxx too complicated
-# how about for now
-#    [+]<commit> [<subdir/> [+]<commit>...]
-# ?  plus options
-#     --new-upstream-different-subtrees
+#  * There are no tests.
 #
-#  automatic case
-#       git-debrebase new-upstream
-#             - previous breakwater merge must be gdr-generated
-#             - orig set is the same as before
-#             - implicitly uses upstream branches according to orig set
-#             - not all upstream branches need be updated
-#             - insists on fast-forward of each branch, unless
-#                  --force (or --force=<subdir>[/])
-#  branch set adjustments
-#       git-debrebase new-upstream --add <subdir>/
-#       git-debrebase new-upstream --rm <subdir>/
-#       git-debrebase new-upstream / [<subdir>/ ...]
-#             - orig set is adjusted
-#             - otherwise like auto (--add is not checked for ffness, obv)
-#             - multiple --add and --rm may be specified
-#             - --add makes new upstream the last contributor
-#  explicit
-#       git-debrebase / [<rootcommitid>] [<subdir>/ [<commitid>] ...]
-#             - orig set is precisely as specified now
-#             - previous breakwater merge is irrelevant
-#             - no fast forward checks
-#  for now only explicit with commitids
-
-#         implicitly uses `upstream'
-#                                     # (or multiple other branches)
-#       git-debrebase new-upstream \
-#             [<subdir>/]=<commitid>
-
-#    UPSTREAM[,[[SUBDIR:]SUBUPSTREAM]
-#    default for SUBDIR: is from previous upstream merge[xxx terminology]
-#    
+#  * new-upstream-v0 has a terrible UI.  You end up with giant
+#    runic command lines.
 #
-#xxx
-# when starting must record original start (for ff)
-# and new rebase basis
+#    One consequence of the lack of richness it can need --force in
+#    fairly sensible situations and there is no way to tell it what
+#    you are really trying to do, other than just --force.  There
+#    should be an interface with some default branch names.
 #
-#    git-ffqrebase start [BASE]
-#                # records previous HEAD so it can be overwritten
-#                # records base for future git-ffqrebase
-#    git-ffqrebase set-base BASE
-#    git-ffqrebase <git-rebase options>
-#    git-ffqrebase finish
-#    git-ffqrebase status [BRANCH]
+#  * There should be a standard convention for the version number,
+#    and unfinalised or not changelog, after new-upstream.
 #
-#  refs/ffqrebase-prev/BRANCH    BRANCH may be refs/...; if not it means
-#  refs/ffqrebase-base/BRANCH      refs/heads/BRANCH
-#                               zero, one, or both of these may exist
+#  * Handing of multi-orig dgit new-upstream .dsc imports is known to
+#    be broken.  They may be not recognised, improperly converted, or
+#    their conversion may be unrecognised.
 #
-# git-debrebase without start, if already started, is willing
-# to strip pseudomerges provided that they overwrite exactly
-# the previous HEAD
-#  xxxx is this right ?  what matters is have we pushed
-#    I think in fact the right answer is:
-#       git-debrebase always strips out pseudomerges from its branch
-#       a pseudomerge is put in at the time we want to push
-#       at that time, we make a pseudomerge of the remote tracking
-#           branch (if raw git) or the dgit view (if dgit)
-#       for raw git git-ffqrebase, do want preciseley to record
-#           value of remote tracking branch or our branch, on start, so we
-#           overwrite only things we intend to
-#  the previous pseudomerge    check for tags and remote branches ?
+#  * Docs need writing and updating.  Even README.git-debrebase
+#    describes a design but may not reflect the implementation.
+#
+#  * We need to develop a plausible model that works for derivatives,
+#    who probably want to maintain their stack on top of Debian's.
+#    downstream-rebase-launder-v0 may be a starting point?
 
 use strict;
 
@@ -785,18 +752,33 @@ sub update_head_checkout ($$$) {
     update_head $old, $new, $mrest;
 }
 
+sub update_head_postlaunder ($$$) {
+    my ($old, $tip, $reflogmsg) = @_;
+    return if $tip eq $old;
+    print "git-debrebase: laundered (head was $old)\n";
+    update_head $old, $tip, $reflogmsg;
+    # no tree changes except debian/patches
+    runcmd @git, qw(rm --quiet --ignore-unmatch -rf debian/patches);
+}
+
 sub cmd_launder () {
     badusage "no arguments to launder allowed" if @ARGV;
     my $old = get_head();
     my ($tip,$breakwater,$last_upstream_merge) = walk $old;
-    update_head $old, $tip, 'launder';
-    # no tree changes except debian/patches
-    runcmd @git, qw(rm --quiet --ignore-unmatch -rf debian/patches);
+    update_head_postlaunder $old, $tip, 'launder';
     printf "# breakwater tip\n%s\n", $breakwater;
     printf "# working tip\n%s\n", $tip;
     printf "# last upstream merge\n%s\n", $last_upstream_merge;
 }
 
+sub defaultcmd_rebase () {
+    my $old = get_head();
+    my ($tip,$breakwater) = walk $old;
+    update_head_postlaunder $old, $tip, 'launder for rebase';
+    @ARGV = qw(-i) unless @ARGV; # make configurable
+    runcmd @git, qw(rebase), @ARGV, $breakwater;
+}
+
 sub cmd_analyse () {
     die if ($ARGV[0]//'') =~ m/^-/;
     badusage "too many arguments to analyse" if @ARGV>1;
@@ -811,16 +793,14 @@ sub cmd_analyse () {
 }
 
 sub cmd_new_upstream_v0 () {
-    # xxx would like to support more git-rebase options
-    badusage
- "need NEW-VERSION UPS-COMMITISH [EXTRA-UPS-NAME EXTRA-UPS-COMMITISH...]"
-       unless @ARGV % 2 == 0 and @ARGV >= 2;
     # tree should be clean and this is not checked
     # automatically and unconditionally launders before rebasing
     # if rebase --abort is used, laundering has still been done
 
     my %pieces;
 
+    badusage "need NEW-VERSION UPS-COMMITTISH" unless @ARGV >= 2;
+
     # parse args - low commitment
     my $new_version = (new Dpkg::Version scalar(shift @ARGV), check => 1);
     my $new_upstream_version = $new_version->version();
@@ -848,8 +828,12 @@ sub cmd_new_upstream_v0 () {
         OldIx => 0,
         New => $new_upstream,
     );
-    while (@ARGV) {
+    while (@ARGV && $ARGV[0] !~ m{^-}) {
        my $n = shift @ARGV;
+
+        badusage "for each EXTRA-UPS-NAME need EXTRA-UPS-COMMITISH"
+            unless @ARGV && $ARGV[0] !~ m{^-};
+
        my $c = git_rev_parse shift @ARGV;
        die unless $n =~ m/^$extra_orig_namepart_re$/;
        $newpiece->($n, New => $c);
@@ -939,15 +923,12 @@ sub cmd_new_upstream_v0 () {
 
        if (@newpieces > 1) {
            # need to make the upstream subtree merge commit
-           my $us_tree = cmdoutput @git, qw(write-tree);
-           my @cmd = (@git, qw(commit-tree), $us_tree);
-           push @cmd, qw(-p), $_ foreach @upstream_merge_parents;
-           push @cmd, qw(-m), "Combine upstreams for $new_upstream_version";
-           push @cmd, qw(-m),
-               "[git-debrebase new-upstream combine . ".
-               (join " ", map { $_->{Name} } @newpieces[1..$#newpieces]).
-                "]";
-           $new_upstream = cmdoutput @cmd;
+            $new_upstream = make_commit \@upstream_merge_parents,
+                [ "Combine upstreams for $new_upstream_version",
+                  ("[git-debrebase new-upstream combine . ".
+                   (join " ", map { $_->{Name} } @newpieces[1..$#newpieces]).
+                   "]"),
+                ];
        }
 
        # $new_upstream is either the single upstream commit, or the
@@ -964,10 +945,10 @@ sub cmd_new_upstream_v0 () {
 
        # Now we have to add a changelog stanza so the Debian version
        # is right.
-
        die if unlink "debian";
-       die $! unless $!==ENOTEMPTY;
-       unlink "debian/changelog" or die $!;
+       die $! unless $!==ENOENT or $!==ENOTEMPTY;
+       unlink "debian/changelog" or $!==ENOENT or die $!;
+        mkdir "debian" or die $!;
        open CN, ">", "debian/changelog" or die $!;
        my $oldclog = git_cat_file ":debian/changelog";
        $oldclog =~ m/^($package_re) \(\S+\) / or
@@ -995,9 +976,10 @@ END
     # the laundering output, because git-rebase can't easily be made
     # to make a replay list which is based on some other branch
 
-    update_head $old_head, $old_laundered_tip, 'launder for new upstream';
+    update_head_postlaunder $old_head, $old_laundered_tip,
+        'launder for new upstream';
 
-    my @cmd = (@git, qw(rebase --onto), $new_bw, $old_bw);
+    my @cmd = (@git, qw(rebase --onto), $new_bw, $old_bw, @ARGV);
     runcmd @cmd;
     # now it's for the user to sort out
 }
@@ -1061,10 +1043,14 @@ chdir $toplevel or die "chdir $toplevel: $!";
 
 $rd = fresh_playground "$playprefix/misc";
 
-my $cmd = shift @ARGV;
-my $cmdfn = $cmd;
-$cmdfn =~ y/-/_/;
-$cmdfn = ${*::}{"cmd_$cmdfn"};
+if (!@ARGV || $ARGV[0] =~ m{^-}) {
+    defaultcmd_rebase();
+} else {
+    my $cmd = shift @ARGV;
+    my $cmdfn = $cmd;
+    $cmdfn =~ y/-/_/;
+    $cmdfn = ${*::}{"cmd_$cmdfn"};
 
-$cmdfn or badusage "unknown git-debrebase sub-operation $cmd";
-$cmdfn->();
+    $cmdfn or badusage "unknown git-debrebase sub-operation $cmd";
+    $cmdfn->();
+}