зеркало из https://github.com/microsoft/git.git
Merge branch 'dp/clean-fix'
* dp/clean-fix: git-clean: add tests for relative path git-clean: correct printing relative path Make private quote_path() in wt-status.c available as quote_path_relative() Revert part ofd089eba
(setup: sanitize absolute and funny paths in get_pathspec()) Revert part of1abf095
(git-add: adjust to the get_pathspec() changes) Revert part of744dacd
(builtin-mv: minimum fix to avoid losing files) get_pathspec(): die when an out-of-tree path is given
This commit is contained in:
Коммит
175f559551
|
@ -228,18 +228,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
|||
goto finish;
|
||||
}
|
||||
|
||||
if (*argv) {
|
||||
/* Was there an invalid path? */
|
||||
if (pathspec) {
|
||||
int num;
|
||||
for (num = 0; pathspec[num]; num++)
|
||||
; /* just counting */
|
||||
if (argc != num)
|
||||
exit(1); /* error message already given */
|
||||
} else
|
||||
exit(1); /* error message already given */
|
||||
}
|
||||
|
||||
fill_directory(&dir, pathspec, ignored_too);
|
||||
|
||||
if (show_only) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "cache.h"
|
||||
#include "dir.h"
|
||||
#include "parse-options.h"
|
||||
#include "quote.h"
|
||||
|
||||
static int force = -1; /* unset */
|
||||
|
||||
|
@ -34,7 +35,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
|||
struct dir_struct dir;
|
||||
const char *path, *base;
|
||||
static const char **pathspec;
|
||||
int prefix_offset = 0;
|
||||
struct strbuf buf;
|
||||
const char *qname;
|
||||
char *seen = NULL;
|
||||
struct option options[] = {
|
||||
OPT__QUIET(&quiet),
|
||||
|
@ -56,6 +58,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
|||
|
||||
argc = parse_options(argc, argv, options, builtin_clean_usage, 0);
|
||||
|
||||
strbuf_init(&buf, 0);
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
if (ignored_only)
|
||||
dir.show_ignored = 1;
|
||||
|
@ -72,8 +75,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
|||
if (!ignored)
|
||||
setup_standard_excludes(&dir);
|
||||
|
||||
if (prefix)
|
||||
prefix_offset = strlen(prefix);
|
||||
pathspec = get_pathspec(prefix, argv);
|
||||
read_cache();
|
||||
|
||||
|
@ -134,39 +135,34 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
|||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
strbuf_addstr(&directory, ent->name);
|
||||
qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
|
||||
if (show_only && (remove_directories || matches)) {
|
||||
printf("Would remove %s\n",
|
||||
directory.buf + prefix_offset);
|
||||
printf("Would remove %s\n", qname);
|
||||
} else if (remove_directories || matches) {
|
||||
if (!quiet)
|
||||
printf("Removing %s\n",
|
||||
directory.buf + prefix_offset);
|
||||
printf("Removing %s\n", qname);
|
||||
if (remove_dir_recursively(&directory, 0) != 0) {
|
||||
warning("failed to remove '%s'",
|
||||
directory.buf + prefix_offset);
|
||||
warning("failed to remove '%s'", qname);
|
||||
errors++;
|
||||
}
|
||||
} else if (show_only) {
|
||||
printf("Would not remove %s\n",
|
||||
directory.buf + prefix_offset);
|
||||
printf("Would not remove %s\n", qname);
|
||||
} else {
|
||||
printf("Not removing %s\n",
|
||||
directory.buf + prefix_offset);
|
||||
printf("Not removing %s\n", qname);
|
||||
}
|
||||
strbuf_reset(&directory);
|
||||
} else {
|
||||
if (pathspec && !matches)
|
||||
continue;
|
||||
qname = quote_path_relative(ent->name, -1, &buf, prefix);
|
||||
if (show_only) {
|
||||
printf("Would remove %s\n",
|
||||
ent->name + prefix_offset);
|
||||
printf("Would remove %s\n", qname);
|
||||
continue;
|
||||
} else if (!quiet) {
|
||||
printf("Removing %s\n",
|
||||
ent->name + prefix_offset);
|
||||
printf("Removing %s\n", qname);
|
||||
}
|
||||
if (unlink(ent->name) != 0) {
|
||||
warning("failed to remove '%s'", ent->name);
|
||||
warning("failed to remove '%s'", qname);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -574,17 +574,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
|||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
/* Verify that the pathspec matches the prefix */
|
||||
if (pathspec) {
|
||||
if (argc != i) {
|
||||
int cnt;
|
||||
for (cnt = 0; pathspec[cnt]; cnt++)
|
||||
;
|
||||
if (cnt != (argc - i))
|
||||
exit(1); /* error message already given */
|
||||
}
|
||||
if (pathspec)
|
||||
prefix = verify_pathspec(prefix);
|
||||
} else if (argc != i)
|
||||
exit(1); /* error message already given */
|
||||
|
||||
/* Treat unmatching pathspec elements as errors */
|
||||
if (pathspec && error_unmatch) {
|
||||
|
|
|
@ -19,7 +19,6 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
|
|||
int count, int base_name)
|
||||
{
|
||||
int i;
|
||||
int len = prefix ? strlen(prefix) : 0;
|
||||
const char **result = xmalloc((count + 1) * sizeof(const char *));
|
||||
memcpy(result, pathspec, count * sizeof(const char *));
|
||||
result[count] = NULL;
|
||||
|
@ -33,11 +32,8 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
|
|||
if (last_slash)
|
||||
result[i] = last_slash + 1;
|
||||
}
|
||||
result[i] = prefix_path(prefix, len, result[i]);
|
||||
if (!result[i])
|
||||
exit(1); /* error already given */
|
||||
}
|
||||
return result;
|
||||
return get_pathspec(prefix, result);
|
||||
}
|
||||
|
||||
static void show_list(const char *label, struct path_list *list)
|
||||
|
|
42
quote.c
42
quote.c
|
@ -260,6 +260,48 @@ extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
|
|||
fputc(terminator, fp);
|
||||
}
|
||||
|
||||
/* quote path as relative to the given prefix */
|
||||
char *quote_path_relative(const char *in, int len,
|
||||
struct strbuf *out, const char *prefix)
|
||||
{
|
||||
int needquote;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen(in);
|
||||
|
||||
/* "../" prefix itself does not need quoting, but "in" might. */
|
||||
needquote = next_quote_pos(in, len) < len;
|
||||
strbuf_setlen(out, 0);
|
||||
strbuf_grow(out, len);
|
||||
|
||||
if (needquote)
|
||||
strbuf_addch(out, '"');
|
||||
if (prefix) {
|
||||
int off = 0;
|
||||
while (prefix[off] && off < len && prefix[off] == in[off])
|
||||
if (prefix[off] == '/') {
|
||||
prefix += off + 1;
|
||||
in += off + 1;
|
||||
len -= off + 1;
|
||||
off = 0;
|
||||
} else
|
||||
off++;
|
||||
|
||||
for (; *prefix; prefix++)
|
||||
if (*prefix == '/')
|
||||
strbuf_addstr(out, "../");
|
||||
}
|
||||
|
||||
quote_c_style_counted (in, len, out, NULL, 1);
|
||||
|
||||
if (needquote)
|
||||
strbuf_addch(out, '"');
|
||||
if (!out->len)
|
||||
strbuf_addstr(out, "./");
|
||||
|
||||
return out->buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* C-style name unquoting.
|
||||
*
|
||||
|
|
4
quote.h
4
quote.h
|
@ -47,6 +47,10 @@ extern void write_name_quoted(const char *name, FILE *, int terminator);
|
|||
extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
|
||||
const char *name, FILE *, int terminator);
|
||||
|
||||
/* quote path as relative to the given prefix */
|
||||
char *quote_path_relative(const char *in, int len,
|
||||
struct strbuf *out, const char *prefix);
|
||||
|
||||
/* quoting as a string literal for other languages */
|
||||
extern void perl_quote_print(FILE *stream, const char *src);
|
||||
extern void python_quote_print(FILE *stream, const char *src);
|
||||
|
|
2
setup.c
2
setup.c
|
@ -202,6 +202,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
|
|||
const char *p = prefix_path(prefix, prefixlen, *src);
|
||||
if (p)
|
||||
*(dst++) = p;
|
||||
else
|
||||
exit(128); /* error message already given */
|
||||
src++;
|
||||
}
|
||||
*dst = NULL;
|
||||
|
|
|
@ -120,7 +120,7 @@ EOF
|
|||
# having 1.txt and path3
|
||||
test_expect_success \
|
||||
'ls-tree filter odd names' \
|
||||
'git ls-tree $tree 1.txt /1.txt //1.txt path3/1.txt /path3/1.txt //path3//1.txt path3 /path3/ path3// >current &&
|
||||
'git ls-tree $tree 1.txt ./1.txt .//1.txt path3/1.txt path3/./1.txt path3 path3// >current &&
|
||||
cat >expected <<\EOF &&
|
||||
100644 blob X 1.txt
|
||||
100644 blob X path3/1.txt
|
||||
|
|
|
@ -142,15 +142,16 @@ test_expect_success 'setup deeper work tree' '
|
|||
test_expect_success 'add a directory outside the work tree' '(
|
||||
cd tester &&
|
||||
d1="$(cd .. ; pwd)" &&
|
||||
git add "$d1"
|
||||
test_must_fail git add "$d1"
|
||||
)'
|
||||
|
||||
|
||||
test_expect_success 'add a file outside the work tree, nasty case 1' '(
|
||||
cd tester &&
|
||||
f="$(pwd)x" &&
|
||||
echo "$f" &&
|
||||
touch "$f" &&
|
||||
git add "$f"
|
||||
test_must_fail git add "$f"
|
||||
)'
|
||||
|
||||
test_expect_success 'add a file outside the work tree, nasty case 2' '(
|
||||
|
@ -158,7 +159,7 @@ test_expect_success 'add a file outside the work tree, nasty case 2' '(
|
|||
f="$(pwd | sed "s/.$//")x" &&
|
||||
echo "$f" &&
|
||||
touch "$f" &&
|
||||
git add "$f"
|
||||
test_must_fail git add "$f"
|
||||
)'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -89,6 +89,58 @@ test_expect_success 'git-clean with prefix' '
|
|||
test -f build/lib.so
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean with relative prefix' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||
would_clean=$(
|
||||
cd docs &&
|
||||
git clean -n ../src |
|
||||
sed -n -e "s|^Would remove ||p"
|
||||
) &&
|
||||
test "$would_clean" = ../src/part3.c || {
|
||||
echo "OOps <$would_clean>"
|
||||
false
|
||||
}
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean with absolute path' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||
would_clean=$(
|
||||
cd docs &&
|
||||
git clean -n $(pwd)/../src |
|
||||
sed -n -e "s|^Would remove ||p"
|
||||
) &&
|
||||
test "$would_clean" = ../src/part3.c || {
|
||||
echo "OOps <$would_clean>"
|
||||
false
|
||||
}
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean with out of work tree relative path' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||
(
|
||||
cd docs &&
|
||||
test_must_fail git clean -n ../..
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean with out of work tree absolute path' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||
dd=$(cd .. && pwd) &&
|
||||
(
|
||||
cd docs &&
|
||||
test_must_fail git clean -n $dd
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean -d with prefix and path' '
|
||||
|
||||
mkdir -p build docs src/feature &&
|
||||
|
|
47
wt-status.c
47
wt-status.c
|
@ -7,6 +7,7 @@
|
|||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "diffcore.h"
|
||||
#include "quote.h"
|
||||
|
||||
int wt_status_relative_paths = 1;
|
||||
int wt_status_use_color = -1;
|
||||
|
@ -82,51 +83,7 @@ static void wt_status_print_trailer(struct wt_status *s)
|
|||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
|
||||
}
|
||||
|
||||
static char *quote_path(const char *in, int len,
|
||||
struct strbuf *out, const char *prefix)
|
||||
{
|
||||
if (len < 0)
|
||||
len = strlen(in);
|
||||
|
||||
strbuf_grow(out, len);
|
||||
strbuf_setlen(out, 0);
|
||||
if (prefix) {
|
||||
int off = 0;
|
||||
while (prefix[off] && off < len && prefix[off] == in[off])
|
||||
if (prefix[off] == '/') {
|
||||
prefix += off + 1;
|
||||
in += off + 1;
|
||||
len -= off + 1;
|
||||
off = 0;
|
||||
} else
|
||||
off++;
|
||||
|
||||
for (; *prefix; prefix++)
|
||||
if (*prefix == '/')
|
||||
strbuf_addstr(out, "../");
|
||||
}
|
||||
|
||||
for ( ; len > 0; in++, len--) {
|
||||
int ch = *in;
|
||||
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
strbuf_addstr(out, "\\n");
|
||||
break;
|
||||
case '\r':
|
||||
strbuf_addstr(out, "\\r");
|
||||
break;
|
||||
default:
|
||||
strbuf_addch(out, ch);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!out->len)
|
||||
strbuf_addstr(out, "./");
|
||||
|
||||
return out->buf;
|
||||
}
|
||||
#define quote_path quote_path_relative
|
||||
|
||||
static void wt_status_print_filepair(struct wt_status *s,
|
||||
int t, struct diff_filepair *p)
|
||||
|
|
Загрузка…
Ссылка в новой задаче