summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Debian/Dgit.pm199
-rw-r--r--debian/changelog77
-rw-r--r--debian/control2
-rw-r--r--debian/tests/control12
-rwxr-xr-xdgit275
-rw-r--r--dgit-maint-gbp.7.pod7
-rw-r--r--dgit-maint-merge.7.pod113
-rw-r--r--dgit-maint-native.7.pod8
-rw-r--r--dgit-sponsorship.7.pod8
-rw-r--r--dgit-user.7.pod30
-rw-r--r--dgit.122
-rwxr-xr-xinfra/dgit-repos-server7
-rw-r--r--tests/lib15
-rwxr-xr-xtests/run-all2
-rwxr-xr-xtests/tests/dpkgsourceignores-correct53
-rwxr-xr-xtests/tests/dpkgsourceignores-docs54
-rwxr-xr-xtests/tests/gitworktree29
-rwxr-xr-xtests/tests/sbuild-gitish47
-rwxr-xr-xtests/tstunt/gpg28
-rw-r--r--tests/worktrees/example_1.0.tarbin71680 -> 81920 bytes
-rwxr-xr-xusing-these8
21 files changed, 810 insertions, 186 deletions
diff --git a/Debian/Dgit.pm b/Debian/Dgit.pm
index dcecbd1..c4a61af 100644
--- a/Debian/Dgit.pm
+++ b/Debian/Dgit.pm
@@ -29,6 +29,8 @@ use Config;
use Digest::SHA;
use Data::Dumper;
use IPC::Open2;
+use File::Path;
+use File::Basename;
BEGIN {
use Exporter ();
@@ -42,10 +44,10 @@ BEGIN {
server_branch server_ref
stat_exists link_ltarget
hashfile
- fail ensuredir executable_on_path
+ fail ensuredir must_getcwd executable_on_path
waitstatusmsg failedcmd_waitstatus
failedcmd_report_cmd failedcmd
- cmdoutput cmdoutput_errok
+ runcmd cmdoutput cmdoutput_errok
git_rev_parse git_cat_file
git_get_ref git_for_each_ref
git_for_each_tag_referring is_fast_fwd
@@ -55,10 +57,18 @@ BEGIN {
initdebug enabledebug enabledebuglevel
printdebug debugcmd
$debugprefix *debuglevel *DEBUG
- shellquote printcmd messagequote);
+ shellquote printcmd messagequote
+ $negate_harmful_gitattrs
+ changedir git_slurp_config_src
+ playtree_setup);
# implicitly uses $main::us
- %EXPORT_TAGS = ( policyflags => [qw(NOFFCHECK FRESHREPO NOCOMMITCHECK)] );
- @EXPORT_OK = @{ $EXPORT_TAGS{policyflags} };
+ %EXPORT_TAGS = ( policyflags => [qw(NOFFCHECK FRESHREPO NOCOMMITCHECK)],
+ playground => [qw(record_maindir $maindir $local_git_cfg
+ $maindir_gitdir $maindir_gitcommon
+ fresh_playground $playground
+ ensure_a_playground)]);
+ @EXPORT_OK = ( @{ $EXPORT_TAGS{policyflags} },
+ @{ $EXPORT_TAGS{playground} } );
}
our @EXPORT_OK;
@@ -82,6 +92,8 @@ sub NOCOMMITCHECK () { return 0x8; }
our $debugprefix;
our $debuglevel = 0;
+our $negate_harmful_gitattrs = "-text -eol -crlf -ident -filter";
+
our $forkcheck_mainprocess;
sub forkcheck_setup () {
@@ -216,6 +228,12 @@ sub ensuredir ($) {
die "mkdir $dir: $!";
}
+sub must_getcwd () {
+ my $d = getcwd();
+ defined $d or fail "getcwd failed: $!";
+ return $d;
+}
+
sub executable_on_path ($) {
my ($program) = @_;
return 1 if $program =~ m{/};
@@ -276,6 +294,12 @@ sub failedcmd {
fail failedcmd_waitstatus();
}
+sub runcmd {
+ debugcmd "+",@_;
+ $!=0; $?=-1;
+ failedcmd @_ if system @_;
+}
+
sub cmdoutput_errok {
confess Dumper(\@_)." ?" if grep { !defined } @_;
debugcmd "|",@_;
@@ -406,4 +430,169 @@ sub is_fast_fwd ($$) {
}
}
+sub changedir ($) {
+ my ($newdir) = @_;
+ printdebug "CD $newdir\n";
+ chdir $newdir or confess "chdir: $newdir: $!";
+}
+
+sub git_slurp_config_src ($) {
+ my ($src) = @_;
+ # returns $r such that $r->{KEY}[] = VALUE
+ my @cmd = (qw(git config -z --get-regexp), "--$src", qw(.*));
+ debugcmd "|",@cmd;
+
+ local ($debuglevel) = $debuglevel-2;
+ local $/="\0";
+
+ my $r = { };
+ open GITS, "-|", @cmd or die $!;
+ while (<GITS>) {
+ chomp or die;
+ printdebug "=> ", (messagequote $_), "\n";
+ m/\n/ or die "$_ ?";
+ push @{ $r->{$`} }, $'; #';
+ }
+ $!=0; $?=0;
+ close GITS
+ or ($!==0 && $?==256)
+ or failedcmd @cmd;
+ return $r;
+}
+
+# ========== playground handling ==========
+
+# terminology:
+#
+# $maindir user's git working tree
+# $playground area in .git/ where we can make files, unpack, etc. etc.
+# playtree git working tree sharing object store with the user's
+# inside playground, or identical to it
+#
+# other globals
+#
+# $local_git_cfg hash of arrays of values: git config from $maindir
+#
+# expected calling pattern
+#
+# firstly
+#
+# [record_maindir]
+# must be run in directory containing .git
+# assigns to $maindir if not already set
+# also calls git_slurp_config_src to record git config
+# in $local_git_cfg, unless it's already set
+#
+# fresh_playground SUBDIR_PATH_COMPONENTS
+# e.g fresh_playground 'dgit/unpack' ('.git/' is implied)
+# default SUBDIR_PATH_COMPONENTS is $playground_subdir
+# calls record_maindir
+# sets up a new playground (destroying any old one)
+# assigns to $playground and returns the same pathname
+# caller may call multiple times with different subdir paths
+# createing different playgrounds; but $playground global can
+# refer only to one, obv.
+#
+# ensure_a_playground SUBDIR_PATH_COMPONENTS
+# like fresh_playground except:
+# merely ensures the directory exists; does not delete an existing one
+# never sets global $playground
+#
+# then can use
+#
+# changedir $playground
+# changedir $maindir
+#
+# playtree_setup $local_git_cfg
+# # ^ call in some (perhaps trivial) subdir of $playground
+#
+# rmtree $playground
+
+# ----- maindir -----
+
+# these three all go together
+our $maindir;
+our $maindir_gitdir;
+our $maindir_gitcommon;
+
+our $local_git_cfg;
+
+sub record_maindir () {
+ if (!defined $maindir) {
+ $maindir = must_getcwd();
+ if (!stat "$maindir/.git") {
+ fail "cannot stat $maindir/.git: $!";
+ }
+ if (-d _) {
+ # we fall back to this in case we have a pre-worktree
+ # git, which may not know git rev-parse --git-common-dir
+ $maindir_gitdir = "$maindir/.git";
+ $maindir_gitcommon = "$maindir/.git";
+ } else {
+ $maindir_gitdir = cmdoutput qw(git rev-parse --git-dir);
+ $maindir_gitcommon = cmdoutput qw(git rev-parse --git-common-dir);
+ }
+ }
+ $local_git_cfg //= git_slurp_config_src 'local';
+}
+
+# ----- playgrounds -----
+
+our $playground;
+
+sub ensure_a_playground_parent ($) {
+ my ($spc) = @_;
+ record_maindir();
+ $spc = "$maindir_gitdir/$spc";
+ my $parent = dirname $spc;
+ mkdir $parent or $!==EEXIST
+ or fail "failed to mkdir playground parent $parent: $!";
+ return $spc;
+}
+
+sub ensure_a_playground ($) {
+ my ($spc) = @_;
+ $spc = ensure_a_playground_parent $spc;
+ mkdir $spc or $!==EEXIST or fail "failed to mkdir a playground $spc: $!";
+ return $spc;
+}
+
+sub fresh_playground ($) {
+ my ($spc) = @_;
+ $spc = ensure_a_playground_parent $spc;
+ rmtree $spc;
+ mkdir $spc or fail "failed to mkdir the playground $spc: $!";
+ return $playground = $spc;
+}
+
+# ----- playtrees -----
+
+sub playtree_setup (;$) {
+ my ($t_local_git_cfg) = @_;
+ $t_local_git_cfg //= $local_git_cfg;
+ # for use in the playtree
+ # $maindir must be set, eg by calling record_maindir or fresh_playground
+ runcmd qw(git init -q);
+ runcmd qw(git config gc.auto 0);
+ foreach my $copy (qw(user.email user.name user.useConfigOnly
+ core.sharedRepository
+ core.compression core.looseCompression
+ core.bigFileThreshold core.fsyncObjectFiles)) {
+ my $v = $t_local_git_cfg->{$copy};
+ next unless $v;
+ runcmd qw(git config), $copy, $_ foreach @$v;
+ }
+ # this is confusing: we have
+ # . playtree, not a worktree, has .git/, our cwd
+ # $maindir might be a worktree so
+ # $maindir_gitdir contains our main working "dgit", HEAD, etc.
+ # $maindir_gitcommon the shared stuff, including .objects
+ rmtree('.git/objects');
+ symlink "$maindir_gitcommon/objects",'.git/objects' or die $!;
+ ensuredir '.git/info';
+ open GA, "> .git/info/attributes" or die $!;
+ print GA "* $negate_harmful_gitattrs\n" or die $!;
+ close GA or die $!;
+}
+
1;
diff --git a/debian/changelog b/debian/changelog
index 4209e71..9fd6edd 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,34 @@
+dgit (4.2~) experimental; urgency=medium
+
+ Documentation improvements:
+ * dgit(1): Add a bit more rationale (polemic, even). Closes:#874221.
+ * Recommend mk-build-deps rather than apt-get build-dep.
+ Suggestion from Nikolaus Rath. Closes:#863361.
+ * dgit-maint-merge(7): many updates. [Sean Whitton]
+ Closes:#864873,#878433.
+ * dgit-*(7): Mention first upload trick. [Andrew Shadura,
+ Sean Whitton] Closes:#856402.
+
+ Minor fixes:
+ * When source discrepancy involves file mode changes, report them
+ specially. Closes:#886442.
+ * In split brain mode, with unexpected diffs, print dgit view
+ commitid in suggested diff rune. (HEAD is wrong.) Closes:#886443.
+ * Fix message about missing quilt cache entry to refer to
+ HEAD rather than tree, since dgit needs a commit. Closes:#884646.
+ * Fix grammar error in 4.1 changelog entry. [Sean Whitton]
+ * Remove some whitespace "errors". [Sean Whitton]
+
+ Packaging:
+ * Remove dependency alternative on realpath (package last existed in
+ Debian wheezy). Closes:#877552.
+
+ Test suite:
+ * dpkgsourceignores-docs: Correct restriction (so autopkgtest
+ won't try to run it).
+
+ --
+
dgit (3.13) unstable; urgency=high
Important bugfixes to dgit:
@@ -9,6 +40,52 @@ dgit (3.13) unstable; urgency=high
-- Ian Jackson <ijackson@chiark.greenend.org.uk> Sun, 22 Oct 2017 17:51:12 +0100
+dgit (4.1) experimental; urgency=medium
+
+ Important improvements to dgit:
+ * Support for `git worktree' worktrees. There may still be
+ bugs; the tests for this are not very comprehensive. And
+ worktrees on different filesystems may not work; that's a
+ matter for the future. Closes:#868515.
+ * Change the dpkg-source -i argument to exclude exactly the right
+ set of things. (Sadly this is not a simple rune.)
+
+ Other improvements to dgit:
+ * New print-dpkg-source-ignores option to print the big rune
+ you need to pass to dpkg-source to make it work exactly right.
+ * Properly shell-quote the --git-builder argument to gbp.
+
+ Documentation:
+ * dgit-user(7): Provide information about how to use sbuild.
+ Quite ugly due to #868527. Closes:#868526.
+ * dgit-user(7): Fixed example rune to use curl (which prints
+ to stdout, as the rune expects). [reported by Simon Tatham]
+
+ Minor improvements:
+ * Do not leave many clog-* files in .git/dgit.
+
+ Internal changes:
+ * using-these: New script to help with ad-hoc-testing.
+ * Refactoring in preparation for push-source [Sean Whitton].
+
+ Test suite:
+ * sbuild-gitish: New test case to check running sbuild from git
+ * Work around gnupg agent connection races by having our stunt
+ gpg wrapper simply try running gpg again, once, if it exits 2.
+ This does not fully suppress the bug but it does significantly reduce
+ the probability.
+ * Other tests for new features.
+ * Various refactoring.
+
+ -- Ian Jackson <ijackson@chiark.greenend.org.uk> Mon, 14 Aug 2017 09:31:03 +0100
+
+dgit (4.0) experimental; urgency=low
+
+ * dgit: --deliberately-not-fast-forward works properly in
+ split view quilt modes (suppressing the pseudomerge).
+
+ -- Ian Jackson <ijackson@chiark.greenend.org.uk> Sun, 12 Feb 2017 22:22:31 +0000
+
dgit (3.12) unstable; urgency=high
Important bugfixes to dgit:
diff --git a/debian/control b/debian/control
index 4d4c304..4405e14 100644
--- a/debian/control
+++ b/debian/control
@@ -11,7 +11,7 @@ Vcs-Browser: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git/dgit.git/
Package: dgit
Depends: perl, libwww-perl, libdpkg-perl, git-core, devscripts, dpkg-dev,
${misc:Depends}, git-buildpackage, liblist-moreutils-perl,
- coreutils (>= 8.23-1~) | realpath,
+ coreutils (>= 8.23-1~),
libdigest-sha-perl, dput, curl, apt,
libjson-perl, ca-certificates,
libtext-iconv-perl, libtext-glob-perl
diff --git a/debian/tests/control b/debian/tests/control
index 76fe9bd..7d2a486 100644
--- a/debian/tests/control
+++ b/debian/tests/control
@@ -6,6 +6,11 @@ Tests: clone-reprepro downstream-gitless
Tests-Directory: tests/tests
Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin, reprepro
+Tests: dpkgsourceignores-docs
+Tests-Directory: tests/tests
+Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin
+Restrictions: x-dgit-intree-only
+
Tests: defdistro-dsd-clone-drs dsd-clone-drs
Tests-Directory: tests/tests
Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin
@@ -24,12 +29,17 @@ Tests-Directory: tests/tests
Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin, sbuild
Restrictions: x-dgit-schroot-build
+Tests: sbuild-gitish
+Tests-Directory: tests/tests
+Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin, sbuild, man-db
+Restrictions: x-dgit-schroot-build
+
Tests: spelling
Tests-Directory: tests/tests
Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin
Restrictions: x-dgit-git-only
-Tests: absurd-gitapply badcommit-rewrite build-modes build-modes-asplit build-modes-gbp-asplit clone-clogsigpipe clone-gitnosuite clone-nogit debpolicy-dbretry debpolicy-newreject debpolicy-quilt-gbp defdistro-rpush defdistro-setup distropatches-reject drs-clone-nogit drs-push-masterupdate drs-push-rejects dsd-clone-nogit dsd-divert fetch-localgitonly fetch-somegit-notlast gbp-orig gitconfig import-dsc import-maintmangle import-native import-nonnative import-tarbomb inarchivecopy mismatches-contents mismatches-dscchanges multisuite newtag-clone-nogit oldnewtagalt oldtag-clone-nogit orig-include-exclude orig-include-exclude-chkquery overwrite-chkclog overwrite-junk overwrite-splitbrains overwrite-version protocol-compat push-buildproductsdir push-newpackage push-nextdgit quilt quilt-gbp quilt-gbp-build-modes quilt-singlepatch quilt-splitbrains quilt-useremail rpush tag-updates test-list-uptodate trustingpolicy-replay unrepresentable version-opt
+Tests: absurd-gitapply badcommit-rewrite build-modes build-modes-asplit build-modes-gbp-asplit clone-clogsigpipe clone-gitnosuite clone-nogit debpolicy-dbretry debpolicy-newreject debpolicy-quilt-gbp defdistro-rpush defdistro-setup distropatches-reject dpkgsourceignores-correct drs-clone-nogit drs-push-masterupdate drs-push-rejects dsd-clone-nogit dsd-divert fetch-localgitonly fetch-somegit-notlast gbp-orig gitconfig gitworktree import-dsc import-maintmangle import-native import-nonnative import-tarbomb inarchivecopy mismatches-contents mismatches-dscchanges multisuite newtag-clone-nogit oldnewtagalt oldtag-clone-nogit orig-include-exclude orig-include-exclude-chkquery overwrite-chkclog overwrite-junk overwrite-splitbrains overwrite-version protocol-compat push-buildproductsdir push-newpackage push-nextdgit quilt quilt-gbp quilt-gbp-build-modes quilt-singlepatch quilt-splitbrains quilt-useremail rpush tag-updates test-list-uptodate trustingpolicy-replay unrepresentable version-opt
Tests-Directory: tests/tests
Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin
diff --git a/dgit b/dgit
index afe209e..31e6bd5 100755
--- a/dgit
+++ b/dgit
@@ -19,7 +19,7 @@
use strict;
-use Debian::Dgit;
+use Debian::Dgit qw(:DEFAULT :playground);
setup_sigwarn();
use IO::Handle;
@@ -49,6 +49,8 @@ our $absurdity = undef; ###substituted###
our @rpushprotovsn_support = qw(4 3 2); # 4 is new tag format
our $protovsn;
+our $cmd;
+our $subcommand;
our $isuite;
our $idistro;
our $package;
@@ -100,6 +102,8 @@ our $git_authline_re = '^([^<>]+) \<(\S+)\> (\d+ [-+]\d+)$';
our $splitbraincache = 'dgit-intern/quilt-cache';
our $rewritemap = 'dgit-rewrite/map';
+our @dpkg_source_ignores = qw(-i(?:^|/)\.git(?:/|$) -I.git);
+
our (@git) = qw(git);
our (@dget) = qw(dget);
our (@curl) = (qw(curl --proto-redir), '-all,http,https', qw(-L));
@@ -111,8 +115,8 @@ our (@ssh) = 'ssh';
our (@dgit) = qw(dgit);
our (@aptget) = qw(apt-get);
our (@aptcache) = qw(apt-cache);
-our (@dpkgbuildpackage) = qw(dpkg-buildpackage -i\.git/ -I.git);
-our (@dpkgsource) = qw(dpkg-source -i\.git/ -I.git);
+our (@dpkgbuildpackage) = (qw(dpkg-buildpackage), @dpkg_source_ignores);
+our (@dpkgsource) = (qw(dpkg-source), @dpkg_source_ignores);
our (@dpkggenchanges) = qw(dpkg-genchanges);
our (@mergechanges) = qw(mergechanges -f);
our (@gbp_build) = ('');
@@ -251,12 +255,6 @@ sub no_such_package () {
exit 4;
}
-sub changedir ($) {
- my ($newdir) = @_;
- printdebug "CD $newdir\n";
- chdir $newdir or confess "chdir: $newdir: $!";
-}
-
sub deliberately ($) {
my ($enquiry) = @_;
return !!grep { $_ eq "--deliberately-$enquiry" } @deliberatelies;
@@ -283,6 +281,10 @@ sub gbp_pq {
return opts_opt_multi_cmd @gbp_pq;
}
+sub dgit_privdir () {
+ our $dgit_privdir_made //= ensure_a_playground 'dgit';
+}
+
#---------- remote protocol support, common ----------
# remote push initiator/responder protocol:
@@ -495,12 +497,6 @@ sub url_get {
our ($dscdata,$dscurl,$dsc,$dsc_checked,$skew_warning_vsn);
-sub runcmd {
- debugcmd "+",@_;
- $!=0; $?=-1;
- failedcmd @_ if system @_;
-}
-
sub act_local () { return $dryrun_level <= 1; }
sub act_scary () { return !$dryrun_level; }
@@ -569,7 +565,7 @@ sub nextarg {
}
sub pre_help () {
- no_local_git_cfg();
+ not_necessarily_a_tree();
}
sub cmd_help () {
print $helpmsg or die $!;
@@ -647,32 +643,17 @@ our %defcfg = ('dgit.default.distro' => 'debian',
our %gitcfgs;
our @gitcfgsources = qw(cmdline local global system);
+our $invoked_in_git_tree = 1;
sub git_slurp_config () {
- local ($debuglevel) = $debuglevel-2;
- local $/="\0";
-
# This algoritm is a bit subtle, but this is needed so that for
# options which we want to be single-valued, we allow the
# different config sources to override properly. See #835858.
foreach my $src (@gitcfgsources) {
next if $src eq 'cmdline';
# we do this ourselves since git doesn't handle it
-
- my @cmd = (@git, qw(config -z --get-regexp), "--$src", qw(.*));
- debugcmd "|",@cmd;
- open GITS, "-|", @cmd or die $!;
- while (<GITS>) {
- chomp or die;
- printdebug "=> ", (messagequote $_), "\n";
- m/\n/ or die "$_ ?";
- push @{ $gitcfgs{$src}{$`} }, $'; #';
- }
- $!=0; $?=0;
- close GITS
- or ($!==0 && $?==256)
- or failedcmd @cmd;
+ $gitcfgs{$src} = git_slurp_config_src $src;
}
}
@@ -709,9 +690,10 @@ sub cfg {
"$us: distro or suite appears not to be (properly) supported";
}
-sub no_local_git_cfg () {
+sub not_necessarily_a_tree () {
# needs to be called from pre_*
@gitcfgsources = grep { $_ ne 'local' } @gitcfgsources;
+ $invoked_in_git_tree = 0;
}
sub access_basedistro__noalias () {
@@ -1006,19 +988,13 @@ sub commit_getclogp ($) {
our %commit_getclogp_memo;
my $memo = $commit_getclogp_memo{$objid};
return $memo if $memo;
- mkpath '.git/dgit';
- my $mclog = ".git/dgit/clog-$objid";
+
+ my $mclog = dgit_privdir()."clog";
runcmd shell_cmd "exec >$mclog", @git, qw(cat-file blob),
"$objid:debian/changelog";
$commit_getclogp_memo{$objid} = parsechangelog("-l$mclog");
}
-sub must_getcwd () {
- my $d = getcwd();
- defined $d or fail "getcwd failed: $!";
- return $d;
-}
-
sub parse_dscdata () {
my $dscfh = new IO::File \$dscdata, '<' or die $!;
printdebug Dumper($dscdata) if $debuglevel>1;
@@ -1702,30 +1678,14 @@ sub create_remote_git_repo () {
our ($dsc_hash,$lastpush_mergeinput);
our ($dsc_distro, $dsc_hint_tag, $dsc_hint_url);
-our $ud = '.git/dgit/unpack';
-sub prep_ud (;$) {
- my ($d) = @_;
- $d //= $ud;
- rmtree($d);
- mkpath '.git/dgit';
- mkdir $d or die $!;
+sub prep_ud () {
+ dgit_privdir(); # ensures that $dgit_privdir_made is based on $maindir
+ fresh_playground 'dgit/unpack';
}
sub mktree_in_ud_here () {
- runcmd qw(git init -q);
- runcmd qw(git config gc.auto 0);
- foreach my $copy (qw(user.email user.name user.useConfigOnly
- core.sharedRepository
- core.compression core.looseCompression
- core.bigFileThreshold core.fsyncObjectFiles)) {
- my $v = $gitcfgs{local}{$copy};
- next unless $v;
- runcmd qw(git config), $copy, $_ foreach @$v;
- }
- rmtree('.git/objects');
- symlink '../../../../objects','.git/objects' or die $!;
- setup_gitattrs(1);
+ playtree_setup $gitcfgs{local};
}
sub git_write_tree () {
@@ -1758,8 +1718,8 @@ sub remove_stray_gits ($) {
sub mktree_in_ud_from_only_subdir ($;$) {
my ($what,$raw) = @_;
-
# changes into the subdir
+
my (@dirs) = <*/.>;
die "expected one subdir but found @dirs ?" unless @dirs==1;
$dirs[0] =~ m#^([^/]+)/\.$# or die;
@@ -2100,13 +2060,13 @@ sub generate_commits_from_dsc () {
# See big comment in fetch_from_archive, below.
# See also README.dsc-import.
prep_ud();
- changedir $ud;
+ changedir $playground;
my @dfi = dsc_files_info();
foreach my $fi (@dfi) {
my $f = $fi->{Filename};
die "$f ?" if $f =~ m#/|^\.|\.dsc$|\.tmp$#;
- my $upper_f = "../../../../$f";
+ my $upper_f = "$maindir/../$f";
printdebug "considering reusing $f: ";
@@ -2426,6 +2386,10 @@ END
my $path = $ENV{PATH} or die;
+ # we use ../../gbp-pq-output, which (given that we are in
+ # $playground/PLAYTREE, and $playground is .git/dgit/unpack,
+ # is .git/dgit.
+
foreach my $use_absurd (qw(0 1)) {
runcmd @git, qw(checkout -q unpa);
runcmd @git, qw(update-ref -d refs/heads/patch-queue/unpa);
@@ -2510,8 +2474,8 @@ END
@output = $lastpush_mergeinput;
}
}
- changedir '../../../..';
- rmtree($ud);
+ changedir $maindir;
+ rmtree $playground;
return @output;
}
@@ -3208,7 +3172,7 @@ END
my $author = clogp_authline $useclogp;
my $cversion = getfield $useclogp, 'Version';
- my $mcf = ".git/dgit/mergecommit";
+ my $mcf = dgit_privdir()."/mergecommit";
open MC, ">", $mcf or die "$mcf $!";
print MC <<END or die $!;
tree $tree
@@ -3268,7 +3232,6 @@ END
fetch_from_archive_record_1($hash);
if (defined $skew_warning_vsn) {
- mkpath '.git/dgit';
printdebug "SKEW CHECK WANT $skew_warning_vsn\n";
my $gotclogp = commit_getclogp($hash);
my $got_vsn = getfield $gotclogp, 'Version';
@@ -3307,8 +3270,9 @@ sub setup_mergechangelogs (;$) {
my $driver = 'dpkg-mergechangelogs';
my $cb = "merge.$driver";
- my $attrs = '.git/info/attributes';
- ensuredir '.git/info';
+ confess unless defined $maindir;
+ my $attrs = "$maindir_gitcommon/info/attributes";
+ ensuredir "$maindir_gitcommon/info";
open NATTRS, ">", "$attrs.new" or die "$attrs.new $!";
if (!open ATTRS, "<", $attrs) {
@@ -3353,15 +3317,16 @@ sub ensure_setup_existing_tree () {
set_local_git_config $k, 'true';
}
-sub open_gitattrs () {
- my $gai = new IO::File ".git/info/attributes"
+sub open_main_gitattrs () {
+ confess 'internal error no maindir' unless defined $maindir;
+ my $gai = new IO::File "$maindir_gitcommon/info/attributes"
or $!==ENOENT
- or die "open .git/info/attributes: $!";
+ or die "open $maindir_gitcommon/info/attributes: $!";
return $gai;
}
sub is_gitattrs_setup () {
- my $gai = open_gitattrs();
+ my $gai = open_main_gitattrs();
return 0 unless $gai;
while (<$gai>) {
return 1 if m{^\[attr\]dgit-defuse-attrs\s};
@@ -3381,15 +3346,15 @@ sub setup_gitattrs (;$) {
END
return;
}
- my $af = ".git/info/attributes";
- ensuredir '.git/info';
+ my $af = "$maindir_gitcommon/info/attributes";
+ ensuredir "$maindir_gitcommon/info";
open GAO, "> $af.new" or die $!;
print GAO <<END or die $!;
* dgit-defuse-attrs
-[attr]dgit-defuse-attrs -text -eol -crlf -ident -filter
+[attr]dgit-defuse-attrs $negate_harmful_gitattrs
# ^ see GITATTRIBUTES in dgit(7) and dgit setup-new-tree in dgit(1)
END
- my $gai = open_gitattrs();
+ my $gai = open_main_gitattrs();
if ($gai) {
while (<$gai>) {
chomp;
@@ -3625,6 +3590,7 @@ sub clone ($) {
my $multi_fetched = fork_for_multisuite(sub {
printdebug "multi clone before fetch merge\n";
changedir $dstdir;
+ record_maindir();
});
if ($multi_fetched) {
printdebug "multi clone after fetch merge\n";
@@ -3639,6 +3605,7 @@ sub clone ($) {
mkdir $dstdir or fail "create \`$dstdir': $!";
changedir $dstdir;
runcmd @git, qw(init -q);
+ record_maindir();
setup_new_tree();
clone_set_head();
my $giturl = access_giturl(1);
@@ -3778,7 +3745,7 @@ sub maybe_split_brain_save ($$$) {
my ($headref, $dgitview, $msg) = @_;
# => message fragment "$saved" describing disposition of $dgitview
return "commit id $dgitview" unless defined $split_brain_save;
- my @cmd = (shell_cmd "cd ../../../..",
+ my @cmd = (shell_cmd 'cd "$1"; shift', $maindir,
@git, qw(update-ref -m),
"dgit --dgit-view-save $msg HEAD=$headref",
$split_brain_save, $dgitview);
@@ -3879,8 +3846,7 @@ sub pseudomerge_make_commit ($$$$ $$) {
: !length $overwrite_version ? " --overwrite"
: " --overwrite=".$overwrite_version;
- mkpath '.git/dgit';
- my $pmf = ".git/dgit/pseudomerge";
+ my $pmf = dgit_privdir()."/pseudomerge";
open MC, ">", $pmf or die "$pmf $!";
print MC <<END or die $!;
tree $tree
@@ -3915,6 +3881,7 @@ sub splitbrain_pseudomerge ($$$$) {
#
return $dgitview unless defined $archive_hash;
+ return $dgitview if deliberately_not_fast_forward();
printdebug "splitbrain_pseudomerge...\n";
@@ -4187,7 +4154,7 @@ END
rpush_handle_protovsn_bothends() if $we_are_initiator;
select_tagformat();
- my $clogpfn = ".git/dgit/changelog.822.tmp";
+ my $clogpfn = dgit_privdir()."/changelog.822.tmp";
runcmd shell_cmd "exec >$clogpfn", qw(dpkg-parsechangelog);
responder_send_file('parsed-changelog', $clogpfn);
@@ -4216,20 +4183,20 @@ END
if (madformat_wantfixup($format)) {
# user might have not used dgit build, so maybe do this now:
if (quiltmode_splitbrain()) {
- changedir $ud;
+ changedir $playground;
quilt_make_fake_dsc($upstreamversion);
my $cachekey;
($dgithead, $cachekey) =
quilt_check_splitbrain_cache($actualhead, $upstreamversion);
$dgithead or fail
"--quilt=$quilt_mode but no cached dgit view:
- perhaps tree changed since dgit build[-source] ?";
+ perhaps HEAD changed since dgit build[-source] ?";
$split_brain = 1;
$dgithead = splitbrain_pseudomerge($clogp,
$actualhead, $dgithead,
$archive_hash);
$maintviewhead = $actualhead;
- changedir '../../../..';
+ changedir $maindir;
prep_ud(); # so _only_subdir() works, below
} else {
commit_quilty_patch();
@@ -4260,26 +4227,55 @@ END
}
}
- changedir $ud;
+ changedir $playground;
progress "checking that $dscfn corresponds to HEAD";
runcmd qw(dpkg-source -x --),
- $dscpath =~ m#^/# ? $dscpath : "../../../$dscpath";
+ $dscpath =~ m#^/# ? $dscpath : "$maindir/$dscpath";
my ($tree,$dir) = mktree_in_ud_from_only_subdir("source package");
check_for_vendor_patches() if madformat($dsc->{format});
- changedir '../../../..';
+ changedir $maindir;
my @diffcmd = (@git, qw(diff --quiet), $tree, $dgithead);
debugcmd "+",@diffcmd;
$!=0; $?=-1;
my $r = system @diffcmd;
if ($r) {
if ($r==256) {
+ my $referent = $split_brain ? $dgithead : 'HEAD';
my $diffs = cmdoutput @git, qw(diff --stat), $tree, $dgithead;
- fail <<END
+
+ my @mode_changes;
+ my $raw = cmdoutput @git,
+ qw(diff --no-renames -z -r --raw), $tree, $dgithead;
+ my $changed;
+ foreach (split /\0/, $raw) {
+ if (defined $changed) {
+ push @mode_changes, "$changed: $_\n" if $changed;
+ $changed = undef;
+ next;
+ } elsif (m/^:0+ 0+ /) {
+ $changed = '';
+ } elsif (m/^:(?:10*)?(\d+) (?:10*)?(\d+) /) {
+ $changed = "Mode change from $1 to $2"
+ } else {
+ die "$_ ?";
+ }
+ }
+ if (@mode_changes) {
+ fail <<END.(join '', @mode_changes).<<END;
+HEAD specifies a different tree to $dscfn:
+$diffs
+END
+There is a problem with your source tree (see dgit(7) for some hints).
+To see a full diff, run git diff $tree $referent
+END
+ }
+
+ fail <<END;
HEAD specifies a different tree to $dscfn:
$diffs
Perhaps you forgot to build. Or perhaps there is a problem with your
source tree (see dgit(7) for some hints). To see a full diff, run
- git diff $tree HEAD
+ git diff $tree $referent
END
} else {
failedcmd @diffcmd;
@@ -4338,7 +4334,7 @@ END
}
my @tagwants = push_tagwants($cversion, $dgithead, $maintviewhead,
- ".git/dgit/tag");
+ dgit_privdir()."/tag");
my @tagobjfns;
supplementary_message(<<'END');
@@ -4428,7 +4424,7 @@ END
}
sub pre_clone () {
- no_local_git_cfg();
+ not_necessarily_a_tree();
}
sub cmd_clone {
parseopts();
@@ -4531,21 +4527,18 @@ END
pull();
}
-sub cmd_push {
+sub prep_push () {
parseopts();
- badusage "-p is not allowed with dgit push" if defined $package;
+ build_or_push_prep_early();
+ pushing();
check_not_dirty();
- my $clogp = parsechangelog();
- $package = getfield $clogp, 'Source';
my $specsuite;
if (@ARGV==0) {
} elsif (@ARGV==1) {
($specsuite) = (@ARGV);
} else {
- badusage "incorrect arguments to dgit push";
+ badusage "incorrect arguments to dgit $subcommand";
}
- $isuite = getfield $clogp, 'Distribution';
- pushing();
if ($new_package) {
local ($package) = $existing_package; # this is a hack
canonicalise_suite();
@@ -4555,9 +4548,13 @@ sub cmd_push {
if (defined $specsuite &&
$specsuite ne $isuite &&
$specsuite ne $csuite) {
- fail "dgit push: changelog specifies $isuite ($csuite)".
+ fail "dgit $subcommand: changelog specifies $isuite ($csuite)".
" but command line specifies $specsuite";
}
+}
+
+sub cmd_push {
+ prep_push();
dopush();
}
@@ -4641,7 +4638,7 @@ sub i_method {
}
sub pre_rpush () {
- no_local_git_cfg();
+ not_necessarily_a_tree();
}
sub cmd_rpush {
my $host = nextarg;
@@ -4861,7 +4858,7 @@ sub quiltify_dpkg_commit ($$$;$) {
my ($patchname,$author,$msg, $xinfo) = @_;
$xinfo //= '';
- mkpath '.git/dgit';
+ mkpath '.git/dgit'; # we are in playtree
my $descfn = ".git/dgit/quilt-description.tmp";
open O, '>', $descfn or die "$descfn: $!";
$msg =~ s/\n+/\n\n/;
@@ -5054,11 +5051,11 @@ END
my $dgitview = git_rev_parse 'HEAD';
- changedir '../../../..';
+ changedir $maindir;
# 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", '>>'
+ ensuredir "$maindir_gitcommon/logs/refs/dgit-intern";
+ my $makelogfh = new IO::File "$maindir_gitcommon/logs/refs/$splitbraincache", '>>'
or die $!;
my $oldcache = git_get_ref "refs/$splitbraincache";
@@ -5079,7 +5076,7 @@ END
runcmd @git, qw(update-ref -m), $cachekey, "refs/$splitbraincache",
$dgitview;
- changedir '.git/dgit/unpack/work';
+ changedir "$playground/work";
my $saved = maybe_split_brain_save $headref, $dgitview, "converted";
progress "dgit view: created ($saved)";
@@ -5378,7 +5375,7 @@ END
my $headref = git_rev_parse('HEAD');
prep_ud();
- changedir $ud;
+ changedir $playground;
my $upstreamversion = upstreamversion $version;
@@ -5390,9 +5387,9 @@ END
die 'bug' if $split_brain && !$need_split_build_invocation;
- changedir '../../../..';
+ changedir $maindir;
runcmd_ordryrun_local
- @git, qw(pull --ff-only -q .git/dgit/unpack/work master);
+ @git, qw(pull --ff-only -q), "$playground/work", qw(master);
}
sub quilt_fixup_mkwork ($) {
@@ -5408,7 +5405,7 @@ sub quilt_fixup_linkorigs ($$) {
my ($upstreamversion, $fn) = @_;
# calls $fn->($leafname);
- foreach my $f (<../../../../*>) { #/){
+ foreach my $f (<$maindir/../*>) { #/){
my $b=$f; $b =~ s{.*/}{};
{
local ($debuglevel) = $debuglevel-1;
@@ -5487,12 +5484,12 @@ END
debian/control debian/changelog);
foreach my $maybe (qw(debian/patches debian/source/options
debian/tests/control)) {
- next unless stat_exists "../../../$maybe";
+ next unless stat_exists "$maindir/$maybe";
push @files, $maybe;
}
my $debtar= srcfn $fakeversion,'.debian.tar.gz';
- runcmd qw(env GZIP=-1n tar -zcf), "./$debtar", qw(-C ../../..), @files;
+ runcmd qw(env GZIP=-1n tar -zcf), "./$debtar", qw(-C), $maindir, @files;
$dscaddfile->($debtar);
close $fakedsc or die $!;
@@ -5501,7 +5498,7 @@ END
sub quilt_check_splitbrain_cache ($$) {
my ($headref, $upstreamversion) = @_;
# Called only if we are in (potentially) split brain mode.
- # Called in $ud.
+ # Called in playground.
# Computes the cache key and looks in the cache.
# Returns ($dgit_view_commitid, $cachekey) or (undef, $cachekey)
@@ -5535,8 +5532,8 @@ sub quilt_check_splitbrain_cache ($$) {
debugcmd "|(probably)",@cmd;
my $child = open GC, "-|"; defined $child or die $!;
if (!$child) {
- chdir '../../..' or die $!;
- if (!stat ".git/logs/refs/$splitbraincache") {
+ chdir $maindir or die $!;
+ if (!stat "$maindir_gitcommon/logs/refs/$splitbraincache") {
$! == ENOENT or die $!;
printdebug ">(no reflog)\n";
exit 0;
@@ -5857,14 +5854,18 @@ sub cmd_clean () {
maybe_unapply_patches_again();
}
-sub build_prep_early () {
- our $build_prep_early_done //= 0;
- return if $build_prep_early_done++;
- badusage "-p is not allowed when building" if defined $package;
+sub build_or_push_prep_early () {
+ our $build_or_push_prep_early_done //= 0;
+ return if $build_or_push_prep_early_done++;
+ badusage "-p is not allowed with dgit $subcommand" if defined $package;
my $clogp = parsechangelog();
$isuite = getfield $clogp, 'Distribution';
$package = getfield $clogp, 'Source';
$version = getfield $clogp, 'Version';
+}
+
+sub build_prep_early () {
+ build_or_push_prep_early();
notpushing();
check_not_dirty();
}
@@ -6102,15 +6103,17 @@ sub cmd_gbp_build {
}
my @cmd = opts_opt_multi_cmd @gbp_build;
- push @cmd, (qw(-us -uc --git-no-sign-tags), "--git-builder=@dbp");
+ push @cmd, (qw(-us -uc --git-no-sign-tags),
+ "--git-builder=".(shellquote @dbp));
if ($gbp_make_orig) {
- ensuredir '.git/dgit';
- my $ok = '.git/dgit/origs-gen-ok';
+ my $priv = dgit_privdir();
+ my $ok = "$priv/origs-gen-ok";
unlink $ok or $!==&ENOENT or die $!;
my @origs_cmd = @cmd;
push @origs_cmd, qw(--git-cleaner=true);
- push @origs_cmd, "--git-prebuild=touch $ok .git/dgit/no-such-dir/ok";
+ push @origs_cmd, "--git-prebuild=".
+ "touch ".(shellquote $ok)." ".(shellquote "$priv/no-such-dir/ok");
push @origs_cmd, @ARGV;
if (act_local()) {
debugcmd @origs_cmd;
@@ -6173,10 +6176,10 @@ sub build_source {
} else {
my @cmd = (@dpkgsource, qw(-b --));
if ($split_brain) {
- changedir $ud;
+ changedir $playground;
runcmd_ordryrun_local @cmd, "work";
my @udfiles = <${package}_*>;
- changedir "../../..";
+ changedir $maindir;
foreach my $f (@udfiles) {
printdebug "source copy, found $f\n";
next unless
@@ -6184,7 +6187,7 @@ sub build_source {
($f =~ m/\.debian\.tar(?:\.\w+)$/ &&
$f eq srcfn($version, $&));
printdebug "source copy, found $f - renaming\n";
- rename "$ud/$f", "../$f" or $!==ENOENT
+ rename "$playground/$f", "../$f" or $!==ENOENT
or fail "put in place new source file ($f): $!";
}
} else {
@@ -6414,7 +6417,7 @@ END
}
sub pre_archive_api_query () {
- no_local_git_cfg();
+ not_necessarily_a_tree();
}
sub cmd_archive_api_query {
badusage "need only 1 subpath argument" unless @ARGV==1;
@@ -6433,7 +6436,7 @@ sub repos_server_url () {
}
sub pre_clone_dgit_repos_server () {
- no_local_git_cfg();
+ not_necessarily_a_tree();
}
sub cmd_clone_dgit_repos_server {
badusage "need destination argument" unless @ARGV==1;
@@ -6445,7 +6448,7 @@ sub cmd_clone_dgit_repos_server {
}
sub pre_print_dgit_repos_server_source_url () {
- no_local_git_cfg();
+ not_necessarily_a_tree();
}
sub cmd_print_dgit_repos_server_source_url {
badusage "no arguments allowed to dgit print-dgit-repos-server-source-url"
@@ -6454,6 +6457,15 @@ sub cmd_print_dgit_repos_server_source_url {
print $url, "\n" or die $!;
}
+sub pre_print_dpkg_source_ignores {
+ not_necessarily_a_tree();
+}
+sub cmd_print_dpkg_source_ignores {
+ badusage "no arguments allowed to dgit print-dpkg-source-ignores"
+ if @ARGV;
+ print "@dpkg_source_ignores\n" or die $!;
+}
+
sub cmd_setup_mergechangelogs {
badusage "no arguments allowed to dgit setup-mergechangelogs" if @ARGV;
local $isuite = 'DGIT-SETUP-TREE';
@@ -6836,12 +6848,13 @@ if (!@ARGV) {
print STDERR $helpmsg or die $!;
exit 8;
}
-my $cmd = shift @ARGV;
+$cmd = $subcommand = shift @ARGV;
$cmd =~ y/-/_/;
my $pre_fn = ${*::}{"pre_$cmd"};
$pre_fn->() if $pre_fn;
+record_maindir if $invoked_in_git_tree;
git_slurp_config();
my $fn = ${*::}{"cmd_$cmd"};
diff --git a/dgit-maint-gbp.7.pod b/dgit-maint-gbp.7.pod
index c31dfa5..3c438ab 100644
--- a/dgit-maint-gbp.7.pod
+++ b/dgit-maint-gbp.7.pod
@@ -111,6 +111,13 @@ want to follow it up with a push to alioth.
You will need to pass I<--overwrite> if the previous upload was not
performed with dgit.
+If this is first ever dgit push of the package, consider passing
+I<--deliberately-not-fast-forward> instead of I<--overwrite>. This
+avoids introducing a new origin commit into the dgit view of your git
+history. (This origin commit would represent the most recent non-dgit
+upload of the package, but this should already be represented in your
+git history.)
+
=head1 INCORPORATING NMUS
B<dgit pull> can't yet incorporate NMUs into patches-unapplied gbp
diff --git a/dgit-maint-merge.7.pod b/dgit-maint-merge.7.pod
index 3da1b78..22be1c9 100644
--- a/dgit-maint-merge.7.pod
+++ b/dgit-maint-merge.7.pod
@@ -146,23 +146,34 @@ Now create I<debian/gbp.conf>:
pristine-tar = False
pristine-tar-commit = False
+ [import-orig]
+ merge-mode = merge
+
=back
-Then we can import the upstream version:
+gbp-import-orig(1) requires a pre-existing upstream branch:
=over 4
% git add debian/gbp.conf && git commit -m "create gbp.conf"
- % gbp import-orig ../foo_1.2.2.orig.tar.xz
+ % git checkout --orphan upstream
+ % git rm -rf .
+ % git commit --allow-empty -m "initial, empty branch for upstream source"
+ % git checkout -f master
=back
-You are now ready to proceed as above, making commits to both the
-upstream source and the I<debian/> directory.
+Then we can import the upstream version:
+
+=over 4
+
+ % gbp import-orig --merge-mode=replace ../foo_1.2.2.orig.tar.xz
-If you want to maintain a copy of your repository on
-B<alioth.debian.org>, you should push both the origin and the upstream
-branches:
+=back
+
+Our upstream branch cannot be pushed to B<dgit-repos>, but since we
+will need it whenever we import a new upstream version, we must push
+it somewhere. The usual choice is B<alioth.debian.org>:
=over 4
@@ -171,6 +182,9 @@ branches:
=back
+You are now ready to proceed as above, making commits to both the
+upstream source and the I<debian/> directory.
+
=head1 CONVERTING AN EXISTING PACKAGE
This section explains how to convert an existing Debian package to
@@ -188,7 +202,16 @@ this workflow. It should be skipped when debianising a new package.
=head2 Existing git history using another workflow
-First, dump any existing patch queue:
+First, if you don't already have the git history locally, clone it,
+and obtain the corresponding orig.tar from the archive:
+
+=over 4
+
+ % git clone git.debian.org:collab-maint/foo
+ % cd foo
+ % origtargz
+
+Now dump any existing patch queue:
=over 4
@@ -205,15 +228,25 @@ Then make new upstream tags available:
=back
+=for dgit-test dpkg-source-ignores begin
+
Now you simply need to ensure that your git HEAD is dgit-compatible,
-i.e., it is exactly what you would get if you ran B<dpkg-buildpackage
--i\.git/ -I.git -S> and then unpacked the resultant source package.
+i.e., it is exactly what you would get if you ran
+B<dpkg-buildpackage -i'(?:^|/)\.git(?:/|$)' -I.git -S>
+and then unpacked the resultant source package.
+
+=for dgit-test dpkg-source-ignores end
To achieve this, you might need to delete
I<debian/source/local-options>. One way to have dgit check your
progress is to run B<dgit build-source>.
-The first dgit push will require I<--overwrite>.
+The first dgit push will require I<--overwrite>. If this is the first
+ever dgit push of the package, consider passing
+I<--deliberately-not-fast-forward> instead of I<--overwrite>. This
+avoids introducing a new origin commit into your git history. (This
+origin commit would represent the most recent non-dgit upload of the
+package, but this should already be represented in your git history.)
=head1 SOURCE PACKAGE CONFIGURATION
@@ -290,58 +323,76 @@ to git), you can just run dpkg-buildpackage(1) or debuild(1) instead.
=head1 NEW UPSTREAM RELEASES
-=head2 When upstream tags releases in git
+=head2 Obtaining the release
-It's a good idea to preview the merge of the new upstream release.
-First, just check for any new or deleted files that may need
-accounting for in your copyright file:
+=head3 When upstream tags releases in git
=over 4
% git remote update
- % git diff --stat master..1.2.3 -- . ':!debian'
=back
-You can then review the full merge diff:
+=head3 When upstream releases only tarballs
+
+You will need the I<debian/gbp.conf> from "When upstream releases only
+tarballs", above. You will also need your upstream branch. Above, we
+pushed this to B<alioth.debian.org>. You will need to clone or fetch
+from there, instead of relying on B<dgit clone>/B<dgit fetch> alone.
+
+Then, either
=over 4
- % git merge-tree `git merge-base master 1.2.3` master 1.2.3 | $PAGER
+ % gbp import-orig --no-merge ../foo_1.2.3.orig.tar.xz
=back
-Once you're satisfied with what will be merged, update your package:
+or if you have a working watch file
=over 4
- % git merge 1.2.3
- % dch -v1.2.3-1 New upstream release.
- % git add debian/changelog && git commit -m changelog
- % git deborig
+ % gbp import-orig --no-merge --uscan
=back
-and you are ready to try a build.
+=head2 Reviewing & merging the release
-=head2 When upstream releases only tarballs
+It's a good idea to preview the merge of the new upstream release.
+First, just check for any new or deleted files that may need
+accounting for in your copyright file:
-You will need the I<debian/gbp.conf> from "When upstream releases only
-tarballs", above.
+=over 4
-Then, either
+ % git diff --stat master..1.2.3 -- . ':!debian'
+
+=back
+
+You can then review the full merge diff:
=over 4
- % gbp import-orig ../foo_1.2.2.orig.tar.xz
+ % git merge-tree `git merge-base master 1.2.3` master 1.2.3 | $PAGER
=back
-or if you have a working watch file
+Once you're satisfied with what will be merged, update your package:
=over 4
- % gbp import-orig --uscan
+ % git merge 1.2.3
+ % dch -v1.2.3-1 New upstream release.
+ % git add debian/changelog && git commit -m changelog
+
+=back
+
+If you obtained a tarball from upstream, you are ready to try a build.
+If you merged a git tag from upstream, you will first need to generate
+a tarball:
+
+=over 4
+
+ % git deborig
=back
diff --git a/dgit-maint-native.7.pod b/dgit-maint-native.7.pod
index 03aee59..34aaaff 100644
--- a/dgit-maint-native.7.pod
+++ b/dgit-maint-native.7.pod
@@ -78,6 +78,14 @@ so that your history,
which will be pushed to the dgit git server,
is fast forward from the dgit archive view.
+Alternatively,
+if this was the first ever dgit push of the package,
+you can avoid this merge commit by
+passing C<--deliberately-not-fast-forward>.
+instead of C<--overwrite>.
+This avoids introducing a new origin commit into
+your git history.
+
=head1 SUBSEQUENT PUSHES
=over 4
diff --git a/dgit-sponsorship.7.pod b/dgit-sponsorship.7.pod
index 8d5b72d..0808329 100644
--- a/dgit-sponsorship.7.pod
+++ b/dgit-sponsorship.7.pod
@@ -257,6 +257,14 @@ you may need to pass
C<--overwrite>
to dgit.
+Alternatively,
+if this was the first ever dgit push of the package,
+you can pass C<--deliberately-not-fast-forward>
+instead of C<--overwrite>.
+This avoids introducing a new origin commit
+into the dgit view of
+the sponsee's git history
+which is unnecessary and could be confusing.
=head1 SPONSORING A NON-GIT-USING SPONSEE
diff --git a/dgit-user.7.pod b/dgit-user.7.pod
index aacdf4d..c74396a 100644
--- a/dgit-user.7.pod
+++ b/dgit-user.7.pod
@@ -32,10 +32,10 @@ or L<dgit(1)> and L<dgit(7)>.
% dgit clone glibc jessie,-security
% cd glibc
- % wget 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=28250;mbox=yes;msg=89' | patch -p1 -u
+ % curl 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=28250;mbox=yes;msg=89' | patch -p1 -u
% git commit -a -m 'Fix libc lost output bug'
% gbp dch -S --since=dgit/dgit/sid --ignore-branch --commit
- % sudo apt-get build-dep glibc
+ % mk-build-deps --root-cmd=sudo --install
% dpkg-buildpackage -uc -b
% sudo dpkg -i ../libc6_*.deb
@@ -288,21 +288,37 @@ a complete treatment is beyond the scope of this tutorial.
=over 4
- % sudo apt-get build-dep glibc
+ % mk-build-deps --root-cmd=sudo --install
% dpkg-buildpackage -uc -b
=back
-apt-get build-dep installs the build dependencies according to the
-official package, not your modified one. So if you've changed the
-build dependencies you might have to install some of them by hand.
-
dpkg-buildpackage is the primary tool for building a Debian source
package.
C<-uc> means not to pgp-sign the results.
C<-b> means build all binary packages,
but not to build a source package.
+=head2 Using sbuild
+
+You can build in an schroot chroot, with sbuild, instead of in your
+main environment. (sbuild is used by the Debian build daemons.)
+
+=over 4
+
+ % git clean -xdf
+ % sbuild -c jessie -A --no-clean-source \
+ --dpkg-source-opts='-Zgzip -z1 --format=1.0 -sn'
+
+=back
+
+Note that this will seem to leave a "source package"
+(.dsc and .tar.gz)
+in the parent directory,
+but that source package should not be used.
+It is likely to be broken.
+For more information see Debian bug #868527.
+
=head1 INSTALLING
=head2 Debian Jessie or older
diff --git a/dgit.1 b/dgit.1
index e5b4bb0..1bf4a2c 100644
--- a/dgit.1
+++ b/dgit.1
@@ -30,6 +30,10 @@ dgit \- git integration with the Debian archive
.B dgit
allows you to treat the Debian archive as if it were a git
repository.
+Conversely,
+it allows Debian to publish the source of its packages
+as git branches, in a format which is directly useable
+by ordinary people.
This is the command line reference.
Please read the tutorial(s):
@@ -343,6 +347,13 @@ as actually being used on the dgit git server, as a git tree.
Prints the url used by dgit clone-dgit-repos-server.
This is hopefully suitable for use as a git remote url.
It may not be useable in a browser.
+.TP
+.BI "dgit print-dpkg-source-ignores"
+Prints the -i and -I arguments which must be passed to dpkg-souce
+to cause it to exclude exactly the .git diredcory
+and nothing else.
+The separate arguments are unquoted, separated by spaces,
+and do not contain spaces.
.SH OPTIONS
.TP
.BR --dry-run " | " -n
@@ -554,6 +565,17 @@ Declare that you are deliberately rewinding history. When pushing to
Debian, use this when you are making a renewed upload of an entirely
new source package whose previous version was not accepted for release
from NEW because of problems with copyright or redistributibility.
+
+In split view quilt modes,
+this also prevents the construction by dgit of a pseudomerge
+to make the dgit view fast forwarding.
+Normally only one of
+--overwrite (which creates a suitable pseudomerge)
+and
+--deliberately-not-fast-forward
+(which suppresses the pseudomerge and the fast forward checks)
+should be needed;
+--overwrite is usually better.
.TP
.BR --deliberately-include-questionable-history
Declare that you are deliberately including, in the git history of
diff --git a/infra/dgit-repos-server b/infra/dgit-repos-server
index ec9b2c9..a8b9400 100755
--- a/infra/dgit-repos-server
+++ b/infra/dgit-repos-server
@@ -303,13 +303,6 @@ sub reject ($) {
die "\ndgit-repos-server: reject: $why\n\n";
}
-sub runcmd {
- debugcmd '+',@_;
- $!=0; $?=0;
- my $r = system @_;
- die (shellquote @_)." $? $!" if $r;
-}
-
sub policyhook {
my ($policyallowbits, @polargs) = @_;
# => ($exitstatuspolicybitmap);
diff --git a/tests/lib b/tests/lib
index 3c04155..8fd3514 100644
--- a/tests/lib
+++ b/tests/lib
@@ -389,7 +389,7 @@ t-fscks () {
(
shopt -s nullglob
for d in $tmp/*/.git $tmp/git/*.git; do
- cd "$d"
+ cd "${d%/.git}"
t-git-fsck
done
)
@@ -407,7 +407,7 @@ t-rm-dput-dropping () {
t-dgit () {
local dgit=${DGIT_TEST-dgit}
- pwd
+ pwd >&2
: '
{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{'
$dgit --dgit=$dgit --dget:-u --dput:--config=$tmp/dput.cf \
@@ -419,6 +419,17 @@ t-dgit () {
'
}
+t-dgit-manpage () {
+ local section=$1
+ local page=$2
+ (export LC_ALL=C.UTF-8
+ if [ "$DGIT_TEST_INTREE" ]; then
+ make -C $DGIT_TEST_INTREE $page.$section.view
+ else
+ man $section $page
+ fi)
+}
+
t-diff-nogit () {
diff --exclude=.git --exclude=.pc -ruN $*
}
diff --git a/tests/run-all b/tests/run-all
index 3877c76..cfa5ce2 100755
--- a/tests/run-all
+++ b/tests/run-all
@@ -15,6 +15,8 @@ fi
mkdir -p tests/tmp
+export DGIT_GNUPG_STUNT_ERRLOG=$( tty -s ||: )
+
(
set -x
exec make $jcpus -k -f tests/Makefile "$@"
diff --git a/tests/tests/dpkgsourceignores-correct b/tests/tests/dpkgsourceignores-correct
new file mode 100755
index 0000000..33de95e
--- /dev/null
+++ b/tests/tests/dpkgsourceignores-correct
@@ -0,0 +1,53 @@
+#!/bin/bash
+set -e
+. tests/lib
+
+t-tstunt-parsechangelog
+
+t-archive example 1.0-1
+t-git-none
+
+t-dgit --no-rm-on-error clone $p
+
+cd $p
+
+bad-dpkg-source () {
+ t-expect-fail E:"dpkg-source:.*unexpected upstream changes" \
+ t-dgit --quilt=nofix -wgf build-source
+ find * -name .git -print0 | xargs -0r rm --
+}
+
+ignores=$(t-dgit print-dpkg-source-ignores)
+
+spurious-git-must-be-excluded () {
+ dpkg-source $ignores -b .
+ mkdir check
+ cd check
+ dpkg-source -x ../../${p}_${v}.dsc
+ cd ${p}-${v%-*}
+ find -name .git >../bad
+ diff /dev/null ../bad
+ cd ../..
+ find * -name .git -print0 | xargs -0r rm -rf --
+ git clean -xdff
+}
+
+mkdir docs/.git
+echo hi >docs/.git/ho
+spurious-git-must-be-excluded
+
+echo hi >docs/.git
+spurious-git-must-be-excluded
+
+mkdir not-really.git
+echo fee >not-really.git/something
+echo fi >not-really.gitfoo
+echo fo >some.git
+echo fum >some.gitfoo
+git add .
+git commit -m 'want these'
+
+t-dgit --quilt=smash -wgf build-source
+t-dgit -wgf push
+
+t-ok
diff --git a/tests/tests/dpkgsourceignores-docs b/tests/tests/dpkgsourceignores-docs
new file mode 100755
index 0000000..a71e7f9
--- /dev/null
+++ b/tests/tests/dpkgsourceignores-docs
@@ -0,0 +1,54 @@
+#!/bin/bash
+set -e
+. tests/lib
+
+t-restrict x-dgit-intree-only
+# we need the .pod source, which is not shipped
+
+cd $tmp
+
+: ----- extract args from document -----
+
+perl -ne '
+ BEGIN { print "\n=head1 dgit-test-title\n\n"; }
+ next unless
+ m/^=for dgit-test dpkg-source-ignores begin/..
+ m/^=for dgit-test dpkg-source-ignores end/;
+ next unless m/dpkg-buildpackage.*-i.*-I/;
+ s/\s*dpkg-buildpackage\s+//;
+ s/\s+-S\s*//;
+ print;
+' $root/dgit-maint-merge.7.pod >doc.pod
+
+pod2text doc.pod >doc.txt
+
+perl -ne '
+ next unless m/\S/;
+ next if m/dgit-test-title/;
+ print "for arg in ";
+ print;
+ print " do\n";
+' doc.txt >doc.sh
+
+cat >>doc.sh <<'END'
+ printf "%s\n" "$arg"
+done
+END
+
+chmod +x doc.sh
+./doc.sh >doc.args
+
+: ----- extract args from dgit -----
+
+args=$( t-dgit print-dpkg-source-ignores )
+
+>dgit.args
+for arg in $args; do
+ printf >>dgit.args "%s\n" "$arg"
+done
+
+: ----- compare -----
+
+diff -u dgit.args doc.args
+
+t-ok
diff --git a/tests/tests/gitworktree b/tests/tests/gitworktree
new file mode 100755
index 0000000..e675a0a
--- /dev/null
+++ b/tests/tests/gitworktree
@@ -0,0 +1,29 @@
+#!/bin/bash
+set -e
+. tests/lib
+
+t-archive example 1.0-1
+t-git-none
+
+t-dgit --no-rm-on-error clone $p
+
+mv $p maintree
+cd maintree
+git branch -m maintree-head
+git worktree add ../$p
+cd ../$p
+
+t-dgit fetch
+
+t-dgit setup-new-tree
+
+echo hi >>modification
+git add modification
+git commit -m 'want this'
+t-dgit -wgf quilt-fixup
+
+t-dgit -wgf --quilt=nofix build
+
+t-dgit -wgf push
+
+t-ok
diff --git a/tests/tests/sbuild-gitish b/tests/tests/sbuild-gitish
new file mode 100755
index 0000000..6e497b2
--- /dev/null
+++ b/tests/tests/sbuild-gitish
@@ -0,0 +1,47 @@
+#!/bin/bash
+set -e
+. tests/lib
+
+t-dependencies sbuild man-db
+t-restrict x-dgit-schroot-build
+
+t-tstunt-parsechangelog
+
+t-prep-newpackage example 1.1
+
+buildrune=$(
+ t-dgit-manpage 7 dgit-user | \
+ perl -ne '
+ next unless m/^ +Using sbuild$/ .. 0;
+ next unless m/^ +\%/ .. 0;
+ next if !m/\S/ .. 0;
+ s/^ +\%//;
+ $fixchr += s/(\s-c\s*)jessie(\s|$)/$1build$2/;
+ print or die $!;
+ END { $fixchr == 1 or die $fixchr; }
+ '
+)
+
+cd $p
+
+build () {
+ eval "$buildrune"
+}
+
+git checkout quilt-tip-1.1~0
+
+build
+
+git checkout gitish-only~0
+
+cat <<'END' >clean-target-hook
+#!/bin/sh
+set -ex
+test "$SCHROOT_SESSION_ID"
+END
+git add clean-target-hook
+git commit -m 'insist on schroot'
+
+build
+
+t-ok
diff --git a/tests/tstunt/gpg b/tests/tstunt/gpg
index d71aa63..a108267 100755
--- a/tests/tstunt/gpg
+++ b/tests/tstunt/gpg
@@ -1,6 +1,32 @@
#!/bin/sh
set -e
-exec \
+
+for attempt in '' exec; do
+
+set +e
+$attempt \
$DGIT_TEST_REAL_GPG \
--agent-program=$DGIT_STUNT_AGENT \
"$@"
+rc=$?
+set -e
+
+if [ $rc != 2 ]; then exit $rc; fi
+
+echo >&2 "WARNING - GNUPG FAILED $rc - STUNT GNUPG $attempt $*"
+
+sh -ec '
+ if [ "x$DGIT_GNUPG_STUNT_ERRLOG" != x ]; then
+ exec >"$DGIT_GNUPG_STUNT_ERRLOG"
+ else
+ exec 2>/dev/null
+ fi
+ exec >/dev/tty
+ printf "%s\n" "$*"
+' x "GNUPG WRAPPER - TROUBLE - $HOME $GNUPGHOME - FAILED $rc $attempt $*"
+
+sleep 10
+
+done
+
+exit 127
diff --git a/tests/worktrees/example_1.0.tar b/tests/worktrees/example_1.0.tar
index 6f66a91..fe108d1 100644
--- a/tests/worktrees/example_1.0.tar
+++ b/tests/worktrees/example_1.0.tar
Binary files differ
diff --git a/using-these b/using-these
new file mode 100755
index 0000000..0bcb4b1
--- /dev/null
+++ b/using-these
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+d="${0%/*}"
+PERLLIB=$d${PERLLIB:+:}${PERLLIB}
+export PERLLIB
+PATH=$d:$d/infra${PATH:+:}${PATH}
+export PATH
+exec "$@"