git-add -i/-p: learn to unwrap C-quoted paths
The underlying plumbing commands are not run with -z option, so the paths returned from them need to be unquoted as needed. Remove the now stale BUGS section from git-add documentaiton as suggested by Teemu Likonen. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Feb 16, 2009 at 22:43 UTC
8851f4800c15fe91b6a53e9e284787b983226c41
2 files changed
+52
-10
Documentation/git-add.txt
-7
@@ -263,13 +263,6 @@ diff::
263
This lets you review what will be committed (i.e. between
264
HEAD and index).
265
266
-Bugs
267
-----
268
-The interactive mode does not work with files whose names contain
269
-characters that need C-quoting. `core.quotepath` configuration can be
270
-used to work this limitation around to some degree, but backslash,
271
-double-quote and control characters will still have problems.
272
-
266
SEE ALSO
267
--------
268
linkgit:git-status[1]
git-add--interactive.perl
+52
-3
@@ -3,6 +3,8 @@
3
use strict;
4
use Git;
5
6
+binmode(STDOUT, ":raw");
7
+
8
my $repo = Git->repository();
9
10
my $menu_use_color = $repo->get_colorbool('color.interactive');
@@ -91,6 +93,47 @@ if (!defined $GIT_DIR) {
93
}
94
chomp($GIT_DIR);
95
96
+my %cquote_map = (
97
+ "b" => chr(8),
98
+ "t" => chr(9),
99
+ "n" => chr(10),
100
+ "v" => chr(11),
101
+ "f" => chr(12),
102
+ "r" => chr(13),
103
+ "\\" => "\\",
104
+ "\042" => "\042",
105
+);
106
+
107
+sub unquote_path {
108
+ local ($_) = @_;
109
+ my ($retval, $remainder);
110
+ if (!/^\042(.*)\042$/) {
111
+ return $_;
112
+ }
113
+ ($_, $retval) = ($1, "");
114
+ while (/^([^\\]*)\\(.*)$/) {
115
+ $remainder = $2;
116
+ $retval .= $1;
117
+ for ($remainder) {
118
+ if (/^([0-3][0-7][0-7])(.*)$/) {
119
+ $retval .= chr(oct($1));
120
+ $_ = $2;
121
+ last;
122
+ }
123
+ if (/^([\\\042btnvfr])(.*)$/) {
124
+ $retval .= $cquote_map{$1};
125
+ $_ = $2;
126
+ last;
127
+ }
128
+ # This is malformed -- just return it as-is for now.
129
+ return $_[0];
130
+ }
131
+ $_ = $remainder;
132
+ }
133
+ $retval .= $_;
134
+ return $retval;
135
+}
136
+
137
sub refresh {
138
my $fh;
139
open $fh, 'git update-index --refresh |'
@@ -104,7 +147,7 @@ sub refresh {
147
sub list_untracked {
148
map {
149
chomp $_;
107
- $_;
150
+ unquote_path($_);
151
}
152
run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @ARGV);
153
}
@@ -141,7 +184,8 @@ sub list_modified {
184
185
if (@ARGV) {
186
@tracked = map {
144
- chomp $_; $_;
187
+ chomp $_;
188
+ unquote_path($_);
189
} run_cmd_pipe(qw(git ls-files --exclude-standard --), @ARGV);
190
return if (!@tracked);
191
}
@@ -153,6 +197,7 @@ sub list_modified {
197
if (($add, $del, $file) =
198
/^([-\d]+) ([-\d]+) (.*)/) {
199
my ($change, $bin);
200
+ $file = unquote_path($file);
201
if ($add eq '-' && $del eq '-') {
202
$change = 'binary';
203
$bin = 1;
@@ -168,6 +213,7 @@ sub list_modified {
213
}
214
elsif (($adddel, $file) =
215
/^ (create|delete) mode [0-7]+ (.*)$/) {
216
+ $file = unquote_path($file);
217
$data{$file}{INDEX_ADDDEL} = $adddel;
218
}
219
}
@@ -175,6 +221,7 @@ sub list_modified {
221
for (run_cmd_pipe(qw(git diff-files --numstat --summary --), @tracked)) {
222
if (($add, $del, $file) =
223
/^([-\d]+) ([-\d]+) (.*)/) {
224
+ $file = unquote_path($file);
225
if (!exists $data{$file}) {
226
$data{$file} = +{
227
INDEX => 'unchanged',
@@ -196,6 +243,7 @@ sub list_modified {
243
}
244
elsif (($adddel, $file) =
245
/^ (create|delete) mode [0-7]+ (.*)$/) {
246
+ $file = unquote_path($file);
247
$data{$file}{FILE_ADDDEL} = $adddel;
248
}
249
}
@@ -302,7 +350,8 @@ sub find_unique_prefixes {
350
}
351
%search = %{$search{$letter}};
352
}
305
- if ($soft_limit && $j + 1 > $soft_limit) {
353
+ if (ord($letters[0]) > 127 ||
354
+ ($soft_limit && $j + 1 > $soft_limit)) {
355
$prefix = undef;
356
$remainder = $ret;
357
}