Skip to content

Commit 6c3b3e1

Browse files
committed
Merge branch 'jc/maint-add-p-unquote' into maint
* jc/maint-add-p-unquote: git-add -i/-p: learn to unwrap C-quoted paths
2 parents 5f7b338 + 8851f48 commit 6c3b3e1

File tree

2 files changed

+52
-10
lines changed

2 files changed

+52
-10
lines changed

Documentation/git-add.txt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,6 @@ diff::
263263
This lets you review what will be committed (i.e. between
264264
HEAD and index).
265265

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-
273266
SEE ALSO
274267
--------
275268
linkgit:git-status[1]

git-add--interactive.perl

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
use strict;
44
use Git;
55

6+
binmode(STDOUT, ":raw");
7+
68
my $repo = Git->repository();
79

810
my $menu_use_color = $repo->get_colorbool('color.interactive');
@@ -91,6 +93,47 @@ sub run_cmd_pipe {
9193
}
9294
chomp($GIT_DIR);
9395

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+
94137
sub refresh {
95138
my $fh;
96139
open $fh, 'git update-index --refresh |'
@@ -104,7 +147,7 @@ sub refresh {
104147
sub list_untracked {
105148
map {
106149
chomp $_;
107-
$_;
150+
unquote_path($_);
108151
}
109152
run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @ARGV);
110153
}
@@ -141,7 +184,8 @@ sub list_modified {
141184

142185
if (@ARGV) {
143186
@tracked = map {
144-
chomp $_; $_;
187+
chomp $_;
188+
unquote_path($_);
145189
} run_cmd_pipe(qw(git ls-files --exclude-standard --), @ARGV);
146190
return if (!@tracked);
147191
}
@@ -153,6 +197,7 @@ sub list_modified {
153197
if (($add, $del, $file) =
154198
/^([-\d]+) ([-\d]+) (.*)/) {
155199
my ($change, $bin);
200+
$file = unquote_path($file);
156201
if ($add eq '-' && $del eq '-') {
157202
$change = 'binary';
158203
$bin = 1;
@@ -168,13 +213,15 @@ sub list_modified {
168213
}
169214
elsif (($adddel, $file) =
170215
/^ (create|delete) mode [0-7]+ (.*)$/) {
216+
$file = unquote_path($file);
171217
$data{$file}{INDEX_ADDDEL} = $adddel;
172218
}
173219
}
174220

175221
for (run_cmd_pipe(qw(git diff-files --numstat --summary --), @tracked)) {
176222
if (($add, $del, $file) =
177223
/^([-\d]+) ([-\d]+) (.*)/) {
224+
$file = unquote_path($file);
178225
if (!exists $data{$file}) {
179226
$data{$file} = +{
180227
INDEX => 'unchanged',
@@ -196,6 +243,7 @@ sub list_modified {
196243
}
197244
elsif (($adddel, $file) =
198245
/^ (create|delete) mode [0-7]+ (.*)$/) {
246+
$file = unquote_path($file);
199247
$data{$file}{FILE_ADDDEL} = $adddel;
200248
}
201249
}
@@ -302,7 +350,8 @@ sub find_unique_prefixes {
302350
}
303351
%search = %{$search{$letter}};
304352
}
305-
if ($soft_limit && $j + 1 > $soft_limit) {
353+
if (ord($letters[0]) > 127 ||
354+
($soft_limit && $j + 1 > $soft_limit)) {
306355
$prefix = undef;
307356
$remainder = $ret;
308357
}

0 commit comments

Comments
 (0)