+sub quiltify_trees_differ ($$;$$$) {
+ my ($x,$y,$finegrained,$ignorenamesr,$unrepres) = @_;
+ # returns true iff the two tree objects differ other than in debian/
+ # with $finegrained,
+ # returns bitmask 01 - differ in upstream files except .gitignore
+ # 02 - differ in .gitignore
+ # if $ignorenamesr is defined, $ingorenamesr->{$fn}
+ # is set for each modified .gitignore filename $fn
+ # if $unrepres is defined, array ref to which is appeneded
+ # a list of unrepresentable changes (removals of upstream files
+ # (as messages)
+ local $/=undef;
+ my @cmd = (@git, qw(diff-tree -z));
+ push @cmd, qw(--name-only) unless $unrepres;
+ push @cmd, qw(-r) if $finegrained || $unrepres;
+ push @cmd, $x, $y;
+ my $diffs= cmdoutput @cmd;
+ my $r = 0;
+ my @lmodes;
+ foreach my $f (split /\0/, $diffs) {
+ if ($unrepres && !@lmodes) {
+ @lmodes = $f =~ m/^\:(\w+) (\w+) \w+ \w+ / or die "$_ ?";
+ next;
+ }
+ my ($oldmode,$newmode) = @lmodes;
+ @lmodes = ();
+
+ next if $f =~ m#^debian(?:/.*)?$#s;
+
+ if ($unrepres) {
+ eval {
+ die "deleted\n" unless $newmode =~ m/[^0]/;
+ die "not a plain file\n" unless $newmode =~ m/^10\d{4}$/;
+ if ($oldmode =~ m/[^0]/) {
+ die "mode changed\n" if $oldmode ne $newmode;
+ } else {
+ die "non-default mode\n" unless $newmode =~ m/^100644$/;
+ }
+ };
+ if ($@) {
+ local $/="\n"; chomp $@;
+ push @$unrepres, [ $f, $@ ];
+ }
+ }
+
+ my $isignore = $f =~ m#^(?:.*/)?.gitignore$#s;
+ $r |= $isignore ? 02 : 01;
+ $ignorenamesr->{$f}=1 if $ignorenamesr && $isignore;
+ }
+ printdebug "quiltify_trees_differ $x $y => $r\n";
+ return $r;
+}
+
+sub quiltify_tree_sentinelfiles ($) {
+ # lists the `sentinel' files present in the tree
+ my ($x) = @_;
+ my $r = cmdoutput @git, qw(ls-tree --name-only), $x,
+ qw(-- debian/rules debian/control);
+ $r =~ s/\n/,/g;
+ return $r;
+}
+
+sub quiltify_splitbrain_needed () {
+ if (!$split_brain) {
+ progress "dgit view: changes are required...";
+ runcmd @git, qw(checkout -q -b dgit-view);
+ $split_brain = 1;
+ }
+}
+
+sub quiltify_splitbrain ($$$$$$) {
+ my ($clogp, $unapplied, $headref, $diffbits,
+ $editedignores, $cachekey) = @_;
+ if ($quilt_mode !~ m/gbp|dpm/) {
+ # treat .gitignore just like any other upstream file
+ $diffbits = { %$diffbits };
+ $_ = !!$_ foreach values %$diffbits;
+ }
+ # We would like any commits we generate to be reproducible
+ my @authline = clogp_authline($clogp);
+ local $ENV{GIT_COMMITTER_NAME} = $authline[0];
+ local $ENV{GIT_COMMITTER_EMAIL} = $authline[1];
+ local $ENV{GIT_COMMITTER_DATE} = $authline[2];
+ local $ENV{GIT_AUTHOR_NAME} = $authline[0];
+ local $ENV{GIT_AUTHOR_EMAIL} = $authline[1];
+ local $ENV{GIT_AUTHOR_DATE} = $authline[2];
+
+ if ($quilt_mode =~ m/gbp|unapplied/ &&
+ ($diffbits->{O2H} & 01)) {
+ my $msg =
+ "--quilt=$quilt_mode specified, implying patches-unapplied git tree\n".
+ " but git tree differs from orig in upstream files.";
+ if (!stat_exists "debian/patches") {
+ $msg .=
+ "\n ... debian/patches is missing; perhaps this is a patch queue branch?";
+ }
+ fail $msg;
+ }
+ if ($quilt_mode =~ m/dpm/ &&
+ ($diffbits->{H2A} & 01)) {
+ fail <<END;
+--quilt=$quilt_mode specified, implying patches-applied git tree
+ but git tree differs from result of applying debian/patches to upstream
+END
+ }
+ if ($quilt_mode =~ m/gbp|unapplied/ &&
+ ($diffbits->{O2A} & 01)) { # some patches
+ quiltify_splitbrain_needed();
+ progress "dgit view: creating patches-applied version using gbp pq";
+ runcmd shell_cmd 'exec >/dev/null', gbp_pq, qw(import);
+ # gbp pq import creates a fresh branch; push back to dgit-view
+ runcmd @git, qw(update-ref refs/heads/dgit-view HEAD);
+ runcmd @git, qw(checkout -q dgit-view);
+ }
+ if ($quilt_mode =~ m/gbp|dpm/ &&
+ ($diffbits->{O2A} & 02)) {
+ fail <<END
+--quilt=$quilt_mode specified, implying that HEAD is for use with a
+ tool which does not create patches for changes to upstream
+ .gitignores: but, such patches exist in debian/patches.
+END
+ }
+ if (($diffbits->{O2H} & 02) && # user has modified .gitignore
+ !($diffbits->{O2A} & 02)) { # patches do not change .gitignore
+ quiltify_splitbrain_needed();
+ progress "dgit view: creating patch to represent .gitignore changes";
+ ensuredir "debian/patches";
+ my $gipatch = "debian/patches/auto-gitignore";
+ open GIPATCH, ">>", "$gipatch" or die "$gipatch: $!";
+ stat GIPATCH or die "$gipatch: $!";
+ fail "$gipatch already exists; but want to create it".
+ " to record .gitignore changes" if (stat _)[7];
+ print GIPATCH <<END or die "$gipatch: $!";
+Subject: Update .gitignore from Debian packaging branch
+
+The Debian packaging git branch contains these updates to the upstream
+.gitignore file(s). This patch is autogenerated, to provide these
+updates to users of the official Debian archive view of the package.
+
+[dgit ($our_version) update-gitignore]
+---
+END
+ close GIPATCH or die "$gipatch: $!";
+ runcmd shell_cmd "exec >>$gipatch", @git, qw(diff),
+ $unapplied, $headref, "--", sort keys %$editedignores;
+ open SERIES, "+>>", "debian/patches/series" or die $!;
+ defined seek SERIES, -1, 2 or $!==EINVAL or die $!;
+ my $newline;
+ defined read SERIES, $newline, 1 or die $!;
+ print SERIES "\n" or die $! unless $newline eq "\n";
+ print SERIES "auto-gitignore\n" or die $!;
+ close SERIES or die $!;
+ runcmd @git, qw(add -- debian/patches/series), $gipatch;
+ commit_admin <<END
+Commit patch to update .gitignore
+
+[dgit ($our_version) update-gitignore-quilt-fixup]
+END
+ }
+
+ my $dgitview = git_rev_parse 'HEAD';
+
+ changedir '../../../..';
+ # When we no longer need to support squeeze, use --create-reflog
+ # instead of this:
+ ensuredir ".git/logs/refs/dgit-intern";
+ my $makelogfh = new IO::File ".git/logs/refs/$splitbraincache", '>>'
+ or die $!;
+
+ my $oldcache = git_get_ref "refs/$splitbraincache";
+ if ($oldcache eq $dgitview) {
+ my $tree = cmdoutput qw(git rev-parse), "$dgitview:";
+ # git update-ref doesn't always update, in this case. *sigh*
+ my $dummy = make_commit_text <<END;
+tree $tree
+parent $dgitview
+author Dgit <dgit\@example.com> 1000000000 +0000
+committer Dgit <dgit\@example.com> 1000000000 +0000
+
+Dummy commit - do not use
+END
+ runcmd @git, qw(update-ref -m), "dgit $our_version - dummy",
+ "refs/$splitbraincache", $dummy;