Merge branch 'jc/add-p-unquote'
authorJunio C Hamano <gitster@pobox.com>
Thu, 5 Mar 2009 23:41:41 +0000 (15:41 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 5 Mar 2009 23:41:41 +0000 (15:41 -0800)
* jc/add-p-unquote:
git-add -i/-p: learn to unwrap C-quoted paths

1  2 
Documentation/git-add.txt
git-add--interactive.perl
index e4c711bbd2d1a95d501978673bc52f7a2957fba7,6c79a87f5ab20cda05f52bad64286c4b182b6ab8..ce71838b9e17f3b68dcd19648da3a88dfe4f35bd
@@@ -136,7 -136,7 +136,7 @@@ $ git add Documentation/\\*.tx
  ------------
  +
  Note that the asterisk `\*` is quoted from the shell in this
 -example; this lets the command to include the files from
 +example; this lets the command include the files from
  subdirectories of `Documentation/` directory.
  
  * Considers adding content from all git-*.sh scripts:
  $ git add git-*.sh
  ------------
  +
 -Because this example lets shell expand the asterisk (i.e. you are
 +Because this example lets the shell expand the asterisk (i.e. you are
  listing the files explicitly), it does not consider
  `subdir/git-foo.sh`.
  
@@@ -198,8 -198,8 +198,8 @@@ one deletion)
  
  update::
  
 -   This shows the status information and gives prompt
 -   "Update>>".  When the prompt ends with double '>>', you can
 +   This shows the status information and issues an "Update>>"
 +   prompt.  When the prompt ends with double '>>', you can
     make more than one selection, concatenated with whitespace or
     comma.  Also you can say ranges.  E.g. "2-5 7,9" to choose
     2,3,4,5,7,9 from the list.  If the second number in a range is
@@@ -238,8 -238,8 +238,8 @@@ add untracked:
  
  patch::
  
 -  This lets you choose one path out of 'status' like selection.
 -  After choosing the path, it presents diff between the index
 +  This lets you choose one path out of 'status' like selection.
 +  After choosing the path, it presents the diff between the index
    and the working tree file and asks you if you want to stage
    the change of each hunk.  You can say:
  
@@@ -263,13 -263,6 +263,6 @@@ diff:
    This lets you review what will be committed (i.e. between
    HEAD and index).
  
- Bugs
- ----
- The interactive mode does not work with files whose names contain
- characters that need C-quoting.  `core.quotepath` configuration can be
- used to work this limitation around to some degree, but backslash,
- double-quote and control characters will still have problems.
  SEE ALSO
  --------
  linkgit:git-status[1]
index f7b0761732f4a752cc91fd7ca02e3a3e07dcfc17,064d4c68d09508f17de1f579c86903b38ebf4859..def062a9e2cbc67b78522aa47151d47cd50f0f33
@@@ -3,6 -3,8 +3,8 @@@
  use strict;
  use Git;
  
+ binmode(STDOUT, ":raw");
  my $repo = Git->repository();
  
  my $menu_use_color = $repo->get_colorbool('color.interactive');
@@@ -91,6 -93,47 +93,47 @@@ if (!defined $GIT_DIR) 
  }
  chomp($GIT_DIR);
  
+ my %cquote_map = (
+  "b" => chr(8),
+  "t" => chr(9),
+  "n" => chr(10),
+  "v" => chr(11),
+  "f" => chr(12),
+  "r" => chr(13),
+  "\\" => "\\",
+  "\042" => "\042",
+ );
+ sub unquote_path {
+       local ($_) = @_;
+       my ($retval, $remainder);
+       if (!/^\042(.*)\042$/) {
+               return $_;
+       }
+       ($_, $retval) = ($1, "");
+       while (/^([^\\]*)\\(.*)$/) {
+               $remainder = $2;
+               $retval .= $1;
+               for ($remainder) {
+                       if (/^([0-3][0-7][0-7])(.*)$/) {
+                               $retval .= chr(oct($1));
+                               $_ = $2;
+                               last;
+                       }
+                       if (/^([\\\042btnvfr])(.*)$/) {
+                               $retval .= $cquote_map{$1};
+                               $_ = $2;
+                               last;
+                       }
+                       # This is malformed -- just return it as-is for now.
+                       return $_[0];
+               }
+               $_ = $remainder;
+       }
+       $retval .= $_;
+       return $retval;
+ }
  sub refresh {
        my $fh;
        open $fh, 'git update-index --refresh |'
  sub list_untracked {
        map {
                chomp $_;
-               $_;
+               unquote_path($_);
        }
        run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @ARGV);
  }
@@@ -141,7 -184,8 +184,8 @@@ sub list_modified 
  
        if (@ARGV) {
                @tracked = map {
-                       chomp $_; $_;
+                       chomp $_;
+                       unquote_path($_);
                } run_cmd_pipe(qw(git ls-files --exclude-standard --), @ARGV);
                return if (!@tracked);
        }
                if (($add, $del, $file) =
                    /^([-\d]+)  ([-\d]+)        (.*)/) {
                        my ($change, $bin);
+                       $file = unquote_path($file);
                        if ($add eq '-' && $del eq '-') {
                                $change = 'binary';
                                $bin = 1;
                }
                elsif (($adddel, $file) =
                       /^ (create|delete) mode [0-7]+ (.*)$/) {
+                       $file = unquote_path($file);
                        $data{$file}{INDEX_ADDDEL} = $adddel;
                }
        }
        for (run_cmd_pipe(qw(git diff-files --numstat --summary --), @tracked)) {
                if (($add, $del, $file) =
                    /^([-\d]+)  ([-\d]+)        (.*)/) {
+                       $file = unquote_path($file);
                        if (!exists $data{$file}) {
                                $data{$file} = +{
                                        INDEX => 'unchanged',
                }
                elsif (($adddel, $file) =
                       /^ (create|delete) mode [0-7]+ (.*)$/) {
+                       $file = unquote_path($file);
                        $data{$file}{FILE_ADDDEL} = $adddel;
                }
        }
@@@ -302,7 -350,8 +350,8 @@@ sub find_unique_prefixes 
                        }
                        %search = %{$search{$letter}};
                }
-               if ($soft_limit && $j + 1 > $soft_limit) {
+               if (ord($letters[0]) > 127 ||
+                   ($soft_limit && $j + 1 > $soft_limit)) {
                        $prefix = undef;
                        $remainder = $ret;
                }
@@@ -753,10 -802,6 +802,10 @@@ EO
                || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
        system('sh', '-c', $editor.' "$@"', $editor, $hunkfile);
  
 +      if ($? != 0) {
 +              return undef;
 +      }
 +
        open $fh, '<', $hunkfile
                or die "failed to open hunk edit file for reading: " . $!;
        my @newtext = grep { !/^#/ } <$fh>;