Browse Source

[PATCH] Improve handling of "." and ".." in git-diff-*

This fixes up usage of ".." (without an ending slash) and "." (with or
without the ending slash) in the git diff family.

It also fixes pathspec matching for the case of an empty pathspec, since a
"." in the top-level directory (or enough ".." under subdirectories) will
result in an empty pathspec. We used to not match it against anything, but
it should in fact match everything.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
maint
Linus Torvalds 20 years ago committed by Junio C Hamano
parent
commit
f332726eaa
  1. 2
      diffcore-pathspec.c
  2. 2
      read-cache.c
  3. 93
      setup.c

2
diffcore-pathspec.c

@ -29,6 +29,8 @@ static int matches_pathspec(const char *name, struct path_spec *s, int cnt) @@ -29,6 +29,8 @@ static int matches_pathspec(const char *name, struct path_spec *s, int cnt)
name[len] == 0 ||
name[len] == '/')
return 1;
if (!len)
return 1;
}
return 0;
}

2
read-cache.c

@ -191,6 +191,8 @@ int ce_path_match(const struct cache_entry *ce, const char **pathspec) @@ -191,6 +191,8 @@ int ce_path_match(const struct cache_entry *ce, const char **pathspec)
return 1;
if (name[matchlen] == '/' || !name[matchlen])
return 1;
if (!matchlen)
return 1;
}
return 0;
}

93
setup.c

@ -1,23 +1,60 @@ @@ -1,23 +1,60 @@
#include "cache.h"

static char *prefix_path(const char *prefix, int len, char *path)
{
char *orig = path;
for (;;) {
char c;
if (*path != '.')
break;
c = path[1];
/* "." */
if (!c) {
path++;
break;
}
/* "./" */
if (c == '/') {
path += 2;
continue;
}
if (c != '.')
break;
c = path[2];
if (!c)
path += 2;
else if (c == '/')
path += 3;
else
break;
/* ".." and "../" */
/* Remove last component of the prefix */
do {
if (!len)
die("'%s' is outside repository", orig);
len--;
} while (len && prefix[len-1] != '/');
continue;
}
if (len) {
int speclen = strlen(path);
char *n = xmalloc(speclen + len + 1);
memcpy(n, prefix, len);
memcpy(n + len, path, speclen+1);
path = n;
}
return path;
}

const char **get_pathspec(const char *prefix, char **pathspec)
{
char *entry = *pathspec;
char **p;
int prefixlen;

if (!prefix) {
char **p;
if (!entry)
return NULL;
p = pathspec;
do {
if (*entry != '.')
continue;
/* fixup ? */
} while ((entry = *++p) != NULL);
return (const char **) pathspec;
}
if (!prefix && !entry)
return NULL;

if (!entry) {
static const char *spec[2];
@ -27,38 +64,10 @@ const char **get_pathspec(const char *prefix, char **pathspec) @@ -27,38 +64,10 @@ const char **get_pathspec(const char *prefix, char **pathspec)
}

/* Otherwise we have to re-write the entries.. */
prefixlen = strlen(prefix);
p = pathspec;
prefixlen = prefix ? strlen(prefix) : 0;
do {
int speclen, len = prefixlen;
char *n;

for (;;) {
if (!strcmp(entry, ".")) {
entry++;
break;
}
if (!strncmp(entry, "./", 2)) {
entry += 2;
continue;
}
if (!strncmp(entry, "../", 3)) {
do {
if (!len)
die("'%s' is outside repository", *p);
len--;
} while (len && prefix[len-1] != '/');
entry += 3;
continue;
}
break;
}
speclen = strlen(entry);
n = xmalloc(speclen + len + 1);
memcpy(n, prefix, len);
memcpy(n + len, entry, speclen+1);
*p = n;
*p = prefix_path(prefix, prefixlen, entry);
} while ((entry = *++p) != NULL);
return (const char **) pathspec;
}

Loading…
Cancel
Save