chiark / gitweb /
git-debrebase: classify: tolerate backwards breakwater merges
[dgit.git] / git-debrebase
index c4fabe3e2302a75c59faea289e7353e72136cf3c..8f2e922355e440f7227a1f7afa3fd8bd8aa61753 100755 (executable)
@@ -110,7 +110,7 @@ use POSIX;
 use Data::Dumper;
 use Getopt::Long qw(:config posix_default gnu_compat bundling);
 
-use Debian::Dgit qw(:DEFAULT $wa);
+use Debian::Dgit qw(:DEFAULT :playground);
 
 sub badusage ($) {
     my ($m) = @_;
@@ -131,9 +131,8 @@ memoize('cfg');
 
 sub get_commit ($) {
     my ($objid) = @_;
-    my ($type,$data) = git_cat_file $objid;
-    die unless $type eq 'commit';
-    $data =~ m/(?<=\n)\n/;
+    my $data = git_cat_file $objid, 'commit';
+    $data =~ m/(?<=\n)\n/ or die "$objid ($data) ?";
     return ($`,$');
 }
 
@@ -142,10 +141,25 @@ sub D_UPS ()     { return 0x2; } # upstream files
 sub D_PAT_ADD () { return 0x4; } # debian/patches/ extra patches at end
 sub D_PAT_OTH () { return 0x8; } # debian/patches other changes
 
-our $rd = ".git/git-debrebase";
-our $ud = "$rd/work";
+
+our $playprefix = 'debrebase';
+our $rd;
+our $workarea;
+
 our @git = qw(git);
 
+sub in_workarea ($) {
+    my ($sub) = @_;
+    changedir $workarea;
+    my $r = eval { $sub->(); };
+    changedir $maindir;
+}
+
+sub fresh_workarea () {
+    $workarea = fresh_playground "$playprefix/work";
+    in_workarea sub { playtree_setup };
+}
+
 sub get_differs ($$) {
     my ($x,$y) = @_;
     # This resembles quiltify_trees_differ, in dgit, a bit.
@@ -359,7 +373,7 @@ sub classify ($) {
                           Contributor => $bytime[1]);
     }
     foreach my $p (@p) {
-       my ($p_h, $p_m) = get_commit $p;
+       my ($p_h, $p_m) = get_commit $p->{CommitId};
        $p->{IsOrigin} = $p_h !~ m/^parent \w+$/m;
        ($p->{IsDgitImport},) = $p_m =~ m/^\[dgit import ([0-9a-z]+) .*\]$/m;
     }
@@ -382,15 +396,26 @@ sub classify ($) {
     # debian/) so debian breakwater branch should be 1st parent; that
     # way also there's also an easy rune to look for the upstream
     # patches (--topo-order).
-    if (@p == 2 &&
-       !$haspatches &&
-       !$p[0]{IsOrigin} && # breakwater merge never starts with an origin
-       !($p[0]{Differs} & ~D_DEB) &&
-       !($p[1]{Differs} & ~D_UPS)) {
-       return $classify->(qw(BreakwaterUpstreamMerge),
-                          OrigParents => [ $p[1] ]);
+
+    # The above tells us which way *we* will generate them.  But we
+    # might encounter ad-hoc breakwater merges generated manually,
+    # which might be the other way around.  In principle, in some odd
+    # situations, a breakwater merge might have two identical parents.
+    # In that case we guess which way round it is (ie, which parent
+    # has the upstream history).  The order of the 2-iteration loop
+    # controls which guess we make.
+
+    foreach my $prevbrw (qw(0 1)) {
+       if (@p == 2 &&
+           !$haspatches &&
+           !$p[$prevbrw]{IsOrigin} && # breakwater never starts with an origin
+           !($p[$prevbrw]{Differs} & ~D_DEB) &&
+           !($p[!$prevbrw]{Differs} & ~D_UPS)) {
+           return $classify->(qw(BreakwaterUpstreamMerge),
+                              OrigParents => [ $p[!$prevbrw] ]);
+       }
+       # xxx multi-.orig upstreams
     }
-    # xxx multi-.orig upstreams
 
     return $unknown->("complex merge");
 }
@@ -569,13 +594,13 @@ sub walk ($;$$) {
 
     # Now we build it back up again
 
-    workarea_fresh();
+    fresh_workarea();
 
     my $rewriting = 0;
 
     my $rm_tree_cached = sub {
        my ($subdir) = @_;
-       runcmd @git, qw(rm --quiet -rf --cached), $subdir;
+       runcmd @git, qw(rm --quiet -rf --cached --ignore-unmatch), $subdir;
     };
     my $read_tree_debian = sub {
        my ($treeish) = @_;
@@ -660,7 +685,7 @@ sub update_head ($$$) {
 }
 
 sub cmd_launder () {
-    badusage "no arguments to launder allowed";
+    badusage "no arguments to launder allowed" if @ARGV;
     my $old = get_head();
     my ($tip,$breakwater) = walk $old;
     update_head $old, $tip, 'launder';
@@ -689,6 +714,8 @@ enabledebug if $debuglevel;
 my $toplevel = cmdoutput @git, qw(rev-parse --show-toplevel);
 chdir $toplevel or die "chdir $toplevel: $!";
 
+$rd = fresh_playground "$playprefix/misc";
+
 my $cmd = shift @ARGV;
 my $cmdfn = $cmd;
 $cmdfn =~ y/-/_/;