git-svn: fix ls-tree usage with dash-prefixed paths
authorEric Wong <normalperson@yhbt.net>
Sun, 29 Mar 2009 05:10:08 +0000 (22:10 -0700)
committerEric Wong <normalperson@yhbt.net>
Sun, 29 Mar 2009 06:00:05 +0000 (23:00 -0700)
To find the blob object name given a tree and pathname, we were
incorrectly calling "git ls-tree" with a "--" argument followed
by the pathname of the file we wanted to get.

  git ls-tree <TREE> -- --dashed/path/name.c

Unlike many command-line interfaces, the "--" alone does not
symbolize the end of non-option arguments on the command-line.

ls-tree interprets the "--" as a prefix to match against, thus
the entire contents of the --dashed/* hierarchy would be
returned because the "--" matches "--dashed" and every path
under it.

Thanks to Anton Gyllenberg for pointing me toward the
Twisted repository as a real-world example of this case.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
git-svn.perl

index 8be6be00c6cc76bcf2fc2d9b1fe331ec5e81fd2e..f21cfb462d3d6d84a4c47bca3d5882ee20266ff7 100755 (executable)
@@ -3387,15 +3387,18 @@ sub delete_entry {
        return undef if ($gpath eq '');
 
        # remove entire directories.
-       if (command('ls-tree', $self->{c}, '--', $gpath) =~ /^040000 tree/) {
+       my ($tree) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
+                        =~ /\A040000 tree ([a-f\d]{40})\t\Q$gpath\E\0/);
+       if ($tree) {
                my ($ls, $ctx) = command_output_pipe(qw/ls-tree
                                                     -r --name-only -z/,
-                                                    $self->{c}, '--', $gpath);
+                                                    $tree);
                local $/ = "\0";
                while (<$ls>) {
                        chomp;
-                       $self->{gii}->remove($_);
-                       print "\tD\t$_\n" unless $::_q;
+                       my $rmpath = "$gpath/$_";
+                       $self->{gii}->remove($rmpath);
+                       print "\tD\t$rmpath\n" unless $::_q;
                }
                print "\tD\t$gpath/\n" unless $::_q;
                command_close_pipe($ls, $ctx);
@@ -3414,8 +3417,8 @@ sub open_file {
        goto out if is_path_ignored($path);
 
        my $gpath = $self->git_path($path);
-       ($mode, $blob) = (command('ls-tree', $self->{c}, '--', $gpath)
-                            =~ /^(\d{6}) blob ([a-f\d]{40})\t/);
+       ($mode, $blob) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
+                            =~ /\A(\d{6}) blob ([a-f\d]{40})\t\Q$gpath\E\0/);
        unless (defined $mode && defined $blob) {
                die "$path was not found in commit $self->{c} (r$rev)\n";
        }