git send-email: interpret unknown files as revision lists
Filter out all the arguments git-send-email doesn't like to a git format-patch command, that dumps its content to a safe directory. Barf when a file/revision conflict occurs, allow it to be overriden --[no-]format-patch. Signed-off-by: Pierre Habouzit <madcoder@debian.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pierre Habouzit committed
Nov 11, 2008 at 00:54 UTC
5df9fcf695a0ba85abfeed68efb3b1c5890068d6
3 files changed
+57
-6
Documentation/git-send-email.txt
+7
-1
@@ -8,7 +8,7 @@ git-send-email - Send a collection of patches as emails
8
9
SYNOPSIS
10
--------
11
-'git send-email' [options] <file|directory> [... file|directory]
11
+'git send-email' [options] <file|directory|rev-list options>...
12
13
14
DESCRIPTION
@@ -183,6 +183,12 @@ Administering
183
--[no-]validate::
184
Perform sanity checks on patches.
185
Currently, validation means the following:
186
+
187
+--[no-]format-patch::
188
+ When an argument may be understood either as a reference or as a file name,
189
+ choose to understand it as a format-patch argument ('--format-patch')
190
+ or as a file name ('--no-format-patch'). By default, when such a conflict
191
+ occurs, git send-email will fail.
192
+
193
--
194
* Warn of patches that contain lines longer than 998 characters; this
git-send-email.perl
+42
-5
@@ -22,8 +22,12 @@ use Term::ReadLine;
22
use Getopt::Long;
23
use Data::Dumper;
24
use Term::ANSIColor;
25
+use File::Temp qw/ tempdir /;
26
+use Error qw(:try);
27
use Git;
28
29
+Getopt::Long::Configure qw/ pass_through /;
30
+
31
package FakeTerm;
32
sub new {
33
my ($class, $reason) = @_;
@@ -38,7 +42,7 @@ package main;
42
43
sub usage {
44
print <<EOT;
41
-git send-email [options] <file | directory>...
45
+git send-email [options] <file | directory | rev-list options >
46
47
Composing:
48
--from <str> * Email From:
@@ -73,6 +77,8 @@ git send-email [options] <file | directory>...
77
--quiet * Output one line of info per email.
78
--dry-run * Don't actually send the emails.
79
--[no-]validate * Perform patch sanity checks. Default on.
80
+ --[no-]format-patch * understand any non optional arguments as
81
+ `git format-patch` ones.
82
83
EOT
84
exit(1);
@@ -146,6 +152,7 @@ if ($@) {
152
153
# Behavior modification variables
154
my ($quiet, $dry_run) = (0, 0);
155
+my $format_patch;
156
my $compose_filename = $repo->repo_path() . "/.gitsendemail.msg.$$";
157
158
# Variables with corresponding config settings
@@ -229,6 +236,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
236
"envelope-sender=s" => \$envelope_sender,
237
"thread!" => \$thread,
238
"validate!" => \$validate,
239
+ "format-patch!" => \$format_patch,
240
);
241
242
unless ($rc) {
@@ -363,23 +371,52 @@ if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
371
372
($sender) = expand_aliases($sender) if defined $sender;
373
374
+# returns 1 if the conflict must be solved using it as a format-patch argument
375
+sub check_file_rev_conflict($) {
376
+ my $f = shift;
377
+ try {
378
+ $repo->command('rev-parse', '--verify', '--quiet', $f);
379
+ if (defined($format_patch)) {
380
+ print "foo\n";
381
+ return $format_patch;
382
+ }
383
+ die(<<EOF);
384
+File '$f' exists but it could also be the range of commits
385
+to produce patches for. Please disambiguate by...
386
+
387
+ * Saying "./$f" if you mean a file; or
388
+ * Giving --format-patch option if you mean a range.
389
+EOF
390
+ } catch Git::Error::Command with {
391
+ return 0;
392
+ }
393
+}
394
+
395
# Now that all the defaults are set, process the rest of the command line
396
# arguments and collect up the files that need to be processed.
368
-for my $f (@ARGV) {
369
- if (-d $f) {
397
+my @rev_list_opts;
398
+while (my $f = pop @ARGV) {
399
+ if ($f eq "--") {
400
+ push @rev_list_opts, "--", @ARGV;
401
+ @ARGV = ();
402
+ } elsif (-d $f and !check_file_rev_conflict($f)) {
403
opendir(DH,$f)
404
or die "Failed to opendir $f: $!";
405
406
push @files, grep { -f $_ } map { +$f . "/" . $_ }
407
sort readdir(DH);
408
closedir(DH);
376
- } elsif (-f $f or -p $f) {
409
+ } elsif ((-f $f or -p $f) and !check_file_rev_conflict($f)) {
410
push @files, $f;
411
} else {
379
- print STDERR "Skipping $f - not found.\n";
412
+ push @rev_list_opts, $f;
413
}
414
}
415
416
+if (@rev_list_opts) {
417
+ push @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts);
418
+}
419
+
420
if ($validate) {
421
foreach my $f (@files) {
422
unless (-p $f) {
t/t9001-send-email.sh
+8
@@ -292,4 +292,12 @@ test_expect_success '--compose adds MIME for utf8 subject' '
292
grep "^Subject: =?utf-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
293
'
294
295
+test_expect_success 'detects ambiguous reference/file conflict' '
296
+ echo master > master &&
297
+ git add master &&
298
+ git commit -m"add master" &&
299
+ test_must_fail git send-email --dry-run master 2>errors &&
300
+ grep disambiguate errors
301
+'
302
+
303
test_done