git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] git-add -i/-p: learn to unwrap C-quoted paths

From
Junio C Hamano <gitster@pobox.com>
Date
Feb 17, 2009, 07:02 UTC
Message-ID
<7v3aeda6lw.fsf_-_@gitster.siamese.dyndns.org>
In-Reply-To
<7v63jbf2v0.fsf@gitster.siamese.dyndns.org>

The underlying plumbing commands are not run with -z option, so the paths returned from them need to be unquoted as needed.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Junio C Hamano <gitster@pobox.com> writes:
 > I did not spell the specifics out because this change won't happen in any
 > near future anyway, but my thinking was to give a way for "add -p" to
 > either (1) internally run without quotepath regardless of the user's
 > settings or (2) unquote the paths correctly when it learns the set of
 > paths affected by the change.
 >
 > I think the right approach is (2), because you need to unquote pathnames
 > with some byte values that even with core.quotepath=false will not pass
 > unquoted *anyway*.
 I deliberately avoided using :utf8 because pathnames to git are always
 binary text, not necessarily utf8, and for the same reason I dropped the
 "shortcut by first character", as the pathnames are stored as raw
 sequence of bytes and using the first byte is obviously wrong.  It would
 be very much welcomed if somebody feels inclined to test and polish it.
 This hopefully makes the discussion on default value for core.quotepath
 independent of "git-add -i/-p".
 git-add--interactive.perl |   55 ++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 5f129a4..064d4c6 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -3,6 +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 @@ 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 |'
@@ -104,7 +147,7 @@ sub refresh {
 sub list_untracked {
 	map {
 		chomp $_;
-		$_;
+		unquote_path($_);
 	}
 	run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @ARGV);
 }
@@ -141,7 +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);
 	}
@@ -153,6 +197,7 @@ sub list_modified {
 		if (($add, $del, $file) =
 		    /^([-\d]+)	([-\d]+)	(.*)/) {
 			my ($change, $bin);
+			$file = unquote_path($file);
 			if ($add eq '-' && $del eq '-') {
 				$change = 'binary';
 				$bin = 1;
@@ -168,6 +213,7 @@ sub list_modified {
 		}
 		elsif (($adddel, $file) =
 		       /^ (create|delete) mode [0-7]+ (.*)$/) {
+			$file = unquote_path($file);
 			$data{$file}{INDEX_ADDDEL} = $adddel;
 		}
 	}
@@ -175,6 +221,7 @@ sub list_modified {
 	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',
@@ -196,6 +243,7 @@ sub list_modified {
 		}
 		elsif (($adddel, $file) =
 		       /^ (create|delete) mode [0-7]+ (.*)$/) {
+			$file = unquote_path($file);
 			$data{$file}{FILE_ADDDEL} = $adddel;
 		}
 	}
@@ -302,7 +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;
 		}
-- 
1.6.2.rc1.47.g30e1d8
Previous: Junio C HamanoNext: Teemu Likonen
Message 6 of 8 in “"add -p" + filenames with UTF-8 multibyte characters = "No changes"”
  1. Antonio García DomínguezFeb 15, 2009
  2. Teemu LikonenFeb 15, 2009
  3. Teemu LikonenFeb 15, 2009
  4. Jeff KingFeb 16, 2009
  5. Junio C HamanoFeb 16, 2009
  6. git-add -i/-p: learn to unwrap C-quoted pathsJunio C Hamano, Feb 17, 2009
  7. Teemu LikonenFeb 17, 2009
  8. Teemu LikonenFeb 16, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.