5 mdcommit - commit changes to man-db
9 B<mdcommit> [B<--release>] [B<--message=>I<text>] [B<--noact>] [B<--confirm>] [B<--changelog=>I<path>] [B<--all> | I<files to commit>]
13 B<mdcommit> generates a commit message based on new text in B<docs/ChangeLog>,
14 and commits the change to man-db's repository. It must be run in a working
15 copy for the package. Supported version control systems are:
22 =item B<-c> B<--changelog> I<path>
24 Specify an alternate location for the changelog. By default docs/ChangeLog is
27 =item B<-r> B<--release>
29 Commit a release of the package. The version number is determined from
30 docs/ChangeLog, and is used to tag the package in the repository.
32 Note that svn/svk tagging conventions vary, so mdcommit uses
33 L<svnpath(1)> to determine where the tag should be placed in the
36 =item B<-m> I<text> B<--message> I<text>
38 Specify a commit message to use. Useful if the program cannot determine
39 a commit message on its own based on docs/ChangeLog, or if you want to
40 override the default message.
42 =item B<-n> B<--noact>
44 Do not actually do anything, but do print the commands that would be run.
46 =item B<-C> B<--confirm>
48 Display the generated commit message and ask for confirmation before committing
53 Commit all files. This is the default operation when using a VCS other
56 =item I<files to commit>
58 Specify which files to commit (docs/ChangeLog is added to the list
61 =item B<-s> B<--strip-message>, B<--no-strip-message>
63 If this option is set and the commit message has been derived from the
64 changelog, the characters "* " will be stripped from the beginning of
67 This option is ignored if more than one line of the message
70 =item B<--sign-tags>, B<--no-sign-tags>
72 If this option is set, then tags that mdcommit creates will be signed
73 using gnupg. Currently this is only supported by git.
79 =head1 CONFIGURATION VARIABLES
81 The two configuration files F</etc/devscripts.conf> and
82 F<~/.devscripts> are sourced by a shell in that order to set
83 configuration variables. Command line options can be used to override
84 configuration file settings. Environment variable settings are
85 ignored for this purpose. The currently recognised variables are:
89 =item B<DEBCOMMIT_STRIP_MESSAGE>
91 If this is set to I<yes>, then it is the same as the --strip-message
92 command line parameter being used. The default is I<no>.
94 =item B<DEBCOMMIT_SIGN_TAGS>
96 If this is set to I<yes>, then it is the same as the --sign-tags command
97 line parameter being used. The default is I<no>.
99 =item B<DEBSIGN_KEYID>
101 This is the key id used for signing tags. If not set, a default will be
102 chosen by the revision control system.
111 my $progname = basename($0);
113 my $modified_conf_msg;
117 Usage: $progname [options] [files to commit]
121 Generates a commit message based on new text in docs/ChangeLog,
122 and commit the change to a package\'s repository.
125 -c --changelog=path Specify the location of the changelog
126 -r --release Commit a release of the package and create a tag
127 -m --message=text Specify a commit message
128 -n --noact Dry run, no actual commits
129 -C --confirm Ask for confirmation of the message before commit
130 -a --all Commit all files (default except for git)
131 -s --strip-message Strip the leading '* ' from the commit message
132 --no-strip-message Do not strip a leading '* ' (default)
133 --sign-tags Enable signing of tags (git only)
134 --no-sign-tags Do not sign tags (default)
135 -h --help This message
136 -v --version Version information
139 Don\'t read devscripts config files;
140 must be the first option given
142 Default settings modified by devscripts configuration files:
150 This is $progname, from the Debian devscripts package, version 2.10.11
151 This code is copyright by Joey Hess <joeyh\@debian.org>, all rights reserved.
152 This program comes with ABSOLUTELY NO WARRANTY.
153 You are free to redistribute this code under the terms of the
154 GNU General Public License, version 2 or later.
165 my $changelog="docs/ChangeLog";
168 # Now start by reading configuration files and then command line
169 # The next stuff is boilerplate
171 if (@ARGV and $ARGV[0] =~ /^--no-?conf$/) {
172 $modified_conf_msg = " (no configuration files read)";
175 my @config_files = ('/etc/devscripts.conf', '~/.devscripts');
177 'DEBCOMMIT_STRIP_MESSAGE' => 'no',
178 'DEBCOMMIT_SIGN_TAGS' => 'no',
179 'DEBSIGN_KEYID' => '',
181 my %config_default = %config_vars;
185 foreach my $var (keys %config_vars) {
186 $shell_cmd .= qq[$var="$config_vars{$var}";\n];
188 $shell_cmd .= 'for file in ' . join(" ",@config_files) . "; do\n";
189 $shell_cmd .= '[ -f $file ] && . $file; done;' . "\n";
191 foreach my $var (keys %config_vars) { $shell_cmd .= "echo \$$var;\n" }
192 my $shell_out = `/bin/bash -c '$shell_cmd'`;
193 @config_vars{keys %config_vars} = split /\n/, $shell_out, -1;
196 $config_vars{'DEBCOMMIT_STRIP_MESSAGE'} =~ /^(yes|no)$/
197 or $config_vars{'DEBCOMMIT_STRIP_MESSAGE'}='no';
198 $config_vars{'DEBCOMMIT_SIGN_TAGS'} =~ /^(yes|no)$/
199 or $config_vars{'DEBCOMMIT_SIGN_TAGS'}='no';
201 foreach my $var (sort keys %config_vars) {
202 if ($config_vars{$var} ne $config_default{$var}) {
203 $modified_conf_msg .= " $var=$config_vars{$var}\n";
206 $modified_conf_msg ||= " (none)\n";
207 chomp $modified_conf_msg;
209 $stripmessage = $config_vars{'DEBCOMMIT_STRIP_MESSAGE'} eq 'no' ? 0 : 1;
210 $signtags = $config_vars{'DEBCOMMIT_SIGN_TAGS'} eq 'no' ? 0 : 1;
211 if (exists $config_vars{'DEBSIGN_KEYID'} &&
212 length $config_vars{'DEBSIGN_KEYID'}) {
213 $keyid=$config_vars{'DEBSIGN_KEYID'};
217 # Now read the command line arguments
219 Getopt::Long::Configure("bundling");
221 "r|release" => \$release,
222 "m|message=s" => \$message,
223 "n|noact" => \$noact,
224 "C|confirm" => \$confirm,
226 "c|changelog=s" => \$changelog,
227 "s|strip-message!" => \$stripmessage,
228 "sign-tags!" => \$signtags,
229 "h|help" => sub { usage(); exit 0; },
230 "v|version" => sub { version(); exit 0; },
232 die "Usage: mdcommit [--release] [--message=text] [--noact] [--confirm] [--changelog=path] [--all | files to commit]\n";
235 my @files_to_commit = @ARGV;
236 if (@files_to_commit && !grep(/$changelog/,@files_to_commit)) {
237 push @files_to_commit, $changelog;
241 if (! -e $changelog) {
242 die "mdcommit: cannot find $changelog\n";
246 open (C, "<$changelog" ) || die "mdcommit: cannot read $changelog: $!";
249 if ($firstline!~/Version: ([0-9][a-z0-9.-]*)/) {
250 die "mdcommit: no Version: changelog entry found\n";
257 #$message="releasing version $version" if ! defined $message;
258 $message=getmessage() if ! defined $message;
263 $message=getmessage() if ! defined $message;
264 commit($message) if not $confirm or confirm($message);
275 # I don't think we can tell just from the working copy
276 # whether to use tla or baz, so try baz if it's available,
277 # otherwise fall back to tla.
278 if (system ("baz --version >/dev/null 2>&1") == 0) {
294 # Test for this file to avoid interactive prompting from svk.
295 if (-d "$ENV{HOME}/.svk/local") {
296 # svk has no useful directories so try to run it.
297 my $svkpath=`svk info . 2>/dev/null| grep -i '^Depot Path:' | cut -d ' ' -f 3`;
298 if (length $svkpath) {
303 # .git may be in a parent directory, rather than the current
304 # directory, if multiple packages are kept in one git repository.
306 while ($dir=~s/[^\/]*\/?$// && length $dir) {
307 if (-d "$dir/.git") {
312 die "mdcommit: not in a cvs, subversion, baz, bzr, git, hg, or svk working copy\n";
318 join(" ", map { if (/[^-A-Za-z0-9]/) { s/'/'\\''/g; "'$_'" } else { $_ } } @_), "\n";
320 return (system($prog, @_) != 0) ? 0 : 1;
326 die "mdcommit: can't specify a list of files to commit when using --all\n"
327 if (@files_to_commit and $all);
329 if ($prog =~ /^(cvs|svn|svk|bzr|hg)$/) {
330 my $author = getauthor();
332 if (defined $author) {
333 @author = ('--author', $author);
335 if (! action($prog, "commit", @author, "-m", $message, @files_to_commit)) {
336 die "mdcommit: commit failed\n";
339 elsif ($prog eq 'git') {
340 if (! @files_to_commit && $all) {
341 # check to see if the WC is clean. git-commit would exit
342 # nonzero, so don't run it.
343 my $status=`LANG=C git status`;
344 if ($status=~/nothing to commit \(working directory clean\)/) {
350 @files_to_commit=("-a")
352 if (! action($prog, "commit", "-m", $message, @files_to_commit)) {
353 die "mdcommit: commit failed\n";
356 elsif ($prog eq 'tla' || $prog eq 'baz') {
357 my $summary=$message;
358 $summary=~s/^((?:\* )?[^\n]{1,72})(?:(?:\s|\n).*|$)/$1/ms;
360 if ($summary eq $message) {
362 @args=("-s", $summary);
365 @args=("-s", "$summary ...", "-L", $message);
369 (($prog eq 'tla') ? '--' : ()),
371 ) if @files_to_commit;
373 if (! action($prog, "commit", @args)) {
374 die "mdcommit: commit failed\n";
378 die "mdcommit: unknown program $prog";
385 if ($prog eq 'svn' || $prog eq 'svk') {
386 my $svnpath=`svnpath`;
388 my $tagpath=`svnpath tags`;
391 if (! action($prog, "copy", $svnpath, "$tagpath/$tag",
392 "-m", "tagging version $tag")) {
393 if (! action($prog, "mkdir", $tagpath,
394 "-m", "create tag directory") ||
395 ! action($prog, "copy", $svnpath, "$tagpath/$tag",
396 "-m", "tagging version $tag")) {
397 die "mdcommit: failed tagging with $tag\n";
401 elsif ($prog eq 'cvs') {
402 $tag=~s/^[0-9]+://; # strip epoch
403 $tag=~tr/./_/; # mangle for cvs
404 $tag="debian_version_$tag";
405 if (! action("cvs", "tag", "-f", $tag)) {
406 die "mdcommit: failed tagging with $tag\n";
409 elsif ($prog eq 'tla' || $prog eq 'baz') {
410 my $archpath=`archpath`;
412 my $tagpath=`archpath releases--\Q$tag\E`;
415 if ($prog eq 'baz') {
416 $subcommand="branch";
421 if (! action($prog, $subcommand, $archpath, $tagpath)) {
422 die "mdcommit: failed tagging with $tag\n";
425 elsif ($prog eq 'bzr') {
426 if (action("$prog tags >/dev/null 2>&1")) {
427 if (! action($prog, "tag", $tag)) {
428 die "mdcommit: failed tagging with $tag\n";
431 die "mdcommit: bazaar or branch version too old to support tags\n";
434 elsif ($prog eq 'git') {
435 $tag=~s/^[0-9]+://; # strip epoch
437 # not a native package, so tag as a debian release
442 if (defined $keyid) {
443 if (! action($prog, "tag", "-u", $keyid, "-m",
444 "tagging version $tag", $tag)) {
445 die "mdcommit: failed tagging with $tag\n";
449 if (! action($prog, "tag", "-s", "-m",
450 "tagging version $tag", $tag)) {
451 die "mdcommit: failed tagging with $tag\n";
455 elsif (! action($prog, "tag", $tag)) {
456 die "mdcommit: failed tagging with $tag\n";
459 elsif ($prog eq 'hg') {
461 if (! action($prog, "tag", "-m", "tagging version $tag", $tag)) {
462 die "mdcommit: failed tagging with $tag\n";
466 die "mdcommit: unknown program $prog";
471 open CHLOG, '-|', ('bzr', 'diff'), $changelog
472 or die "mdcommit: cannot run bzr: $!\n";
474 next unless /^\+[A-Z]/;
479 if (/^Colin Watson /) {
493 if ($prog =~ /^(cvs|svn|svk|tla|baz|bzr|git|hg)$/) {
497 if ($prog eq 'tla' || $prog eq 'baz') {
498 @diffcmd = ($prog, 'file-diff');
499 } elsif ($prog eq 'git') {
501 @diffcmd = ('git-diff');
503 @diffcmd = ('git-diff', '--cached');
506 @diffcmd = ($prog, 'diff');
509 open CHLOG, '-|', @diffcmd, $changelog
510 or die "mdcommit: cannot run $diffcmd[0]: $!\n";
512 # TODO should keep intermediate whitespace in message
521 if ($prog eq 'git') {
522 $info = ' (do you mean "mdcommit -a" or did you forget to run "git add"?)';
524 die "mdcommit: unable to determine commit message using $prog$info\nTry using the -m flag.\n";
527 my $count = () = $ret =~ /^\* /mg;
535 die "mdcommit: unknown program $prog";
544 print $message, "\n--\n";
546 print "OK to commit? [Y/n] ";
549 return 1 if /^(y|$)/i;
555 This code is copyright by Joey Hess <joeyh@debian.org>, all rights reserved.
556 This program comes with ABSOLUTELY NO WARRANTY.
557 You are free to redistribute this code under the terms of the
558 GNU General Public License, version 2 or later.
562 Joey Hess <joeyh@debian.org>