From 4fb1c6aad82212051d95b2d0b1f4c877d076bf5d Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 17 Mar 2017 10:22:53 -0700 Subject: grep: fix help text typo Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano diff --git a/builtin/grep.c b/builtin/grep.c index 2c727ef..4b7b2da 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -978,7 +978,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_SET_INT(0, "exclude-standard", &opt_exclude, N_("ignore files specified via '.gitignore'"), 1), OPT_BOOL(0, "recurse-submodules", &recurse_submodules, - N_("recursivley search in each submodule")), + N_("recursively search in each submodule")), OPT_STRING(0, "parent-basename", &parent_basename, N_("basename"), N_("prepend parent project's basename to output")), -- cgit v0.10.2-6-g49f6 From b58a68c1c1874ff155699d82947c9f026f431cb3 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 17 Mar 2017 10:22:54 -0700 Subject: setup: allow for prefix to be passed to git commands In a future patch child processes which act on submodules need a little more context about the original command that was invoked. This patch teaches git to use the prefix stored in `GIT_INTERNAL_TOPLEVEL_PREFIX` instead of the prefix that was potentally found during the git directory setup process. Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano diff --git a/cache.h b/cache.h index 61fc86e..c7aa6f4 100644 --- a/cache.h +++ b/cache.h @@ -410,6 +410,7 @@ static inline enum object_type object_type(unsigned int mode) #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE" #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX" #define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX" +#define GIT_TOPLEVEL_PREFIX_ENVIRONMENT "GIT_INTERNAL_TOPLEVEL_PREFIX" #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY" #define INDEX_ENVIRONMENT "GIT_INDEX_FILE" diff --git a/git.c b/git.c index c887272..51bad41 100644 --- a/git.c +++ b/git.c @@ -361,8 +361,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) if (!help && get_super_prefix()) { if (!(p->option & SUPPORT_SUPER_PREFIX)) die("%s doesn't support --super-prefix", p->cmd); - if (prefix) - die("can't use --super-prefix from a subdirectory"); } if (!help && p->option & NEED_WORK_TREE) diff --git a/setup.c b/setup.c index 967f289..56cd68b 100644 --- a/setup.c +++ b/setup.c @@ -939,9 +939,14 @@ static const char *setup_git_directory_gently_1(int *nongit_ok) const char *setup_git_directory_gently(int *nongit_ok) { - const char *prefix; + const char *prefix, *env_prefix; prefix = setup_git_directory_gently_1(nongit_ok); + env_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT); + + if (env_prefix) + prefix = env_prefix; + if (prefix) setenv(GIT_PREFIX_ENVIRONMENT, prefix, 1); else -- cgit v0.10.2-6-g49f6 From be80a2392f5d10395bf934a066faeefdb6bb380a Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 17 Mar 2017 10:22:55 -0700 Subject: grep: fix bug when recursing with relative pathspec When using the --recurse-submodules flag with a relative pathspec which includes "..", an error is produced inside the child process spawned for a submodule. When creating the pathspec struct in the child, the ".." is interpreted to mean "go up a directory" which causes an error stating that the path ".." is outside of the repository. While it is true that ".." is outside the scope of the submodule, it is confusing to a user who originally invoked the command where ".." was indeed still inside the scope of the superproject. Since the child process launched for the submodule has some context that it is operating underneath a superproject, this error could be avoided. This patch fixes the bug by passing the 'prefix' to the child process. Now each child process that works on a submodule has two points of reference to the superproject: (1) the 'super_prefix' which is the path from the root of the superproject down to root of the submodule and (2) the 'prefix' which is the path from the root of the superproject down to the directory where the user invoked the git command. With these two pieces of information a child process can correctly interpret the pathspecs provided by the user as well as being able to properly format its output relative to the directory the user invoked the original command from. Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano diff --git a/builtin/grep.c b/builtin/grep.c index 4b7b2da..4a279ca 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -310,10 +310,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, { struct strbuf pathbuf = STRBUF_INIT; - if (opt->relative && opt->prefix_length) { - quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf); - strbuf_insert(&pathbuf, 0, filename, tree_name_len); - } else if (super_prefix) { + if (super_prefix) { strbuf_add(&pathbuf, filename, tree_name_len); strbuf_addstr(&pathbuf, super_prefix); strbuf_addstr(&pathbuf, filename + tree_name_len); @@ -321,6 +318,13 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, strbuf_addstr(&pathbuf, filename); } + if (opt->relative && opt->prefix_length) { + char *name = strbuf_detach(&pathbuf, NULL); + quote_path_relative(name + tree_name_len, opt->prefix, &pathbuf); + strbuf_insert(&pathbuf, 0, name, tree_name_len); + free(name); + } + #ifndef NO_PTHREADS if (num_threads) { add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1); @@ -345,12 +349,14 @@ static int grep_file(struct grep_opt *opt, const char *filename) { struct strbuf buf = STRBUF_INIT; + if (super_prefix) + strbuf_addstr(&buf, super_prefix); + strbuf_addstr(&buf, filename); + if (opt->relative && opt->prefix_length) { - quote_path_relative(filename, opt->prefix, &buf); - } else { - if (super_prefix) - strbuf_addstr(&buf, super_prefix); - strbuf_addstr(&buf, filename); + char *name = strbuf_detach(&buf, NULL); + quote_path_relative(name, opt->prefix, &buf); + free(name); } #ifndef NO_PTHREADS @@ -399,13 +405,12 @@ static void run_pager(struct grep_opt *opt, const char *prefix) } static void compile_submodule_options(const struct grep_opt *opt, - const struct pathspec *pathspec, + const char **argv, int cached, int untracked, int opt_exclude, int use_index, int pattern_type_arg) { struct grep_pat *pattern; - int i; if (recurse_submodules) argv_array_push(&submodule_options, "--recurse-submodules"); @@ -523,9 +528,8 @@ static void compile_submodule_options(const struct grep_opt *opt, /* Add Pathspecs */ argv_array_push(&submodule_options, "--"); - for (i = 0; i < pathspec->nr; i++) - argv_array_push(&submodule_options, - pathspec->items[i].original); + for (; *argv; argv++) + argv_array_push(&submodule_options, *argv); } /* @@ -549,6 +553,11 @@ static int grep_submodule_launch(struct grep_opt *opt, prepare_submodule_repo_env(&cp.env_array); argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT); + if (opt->relative && opt->prefix_length) + argv_array_pushf(&cp.env_array, "%s=%s", + GIT_TOPLEVEL_PREFIX_ENVIRONMENT, + opt->prefix); + /* Add super prefix */ argv_array_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ? super_prefix : "", @@ -1206,7 +1215,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (recurse_submodules) { gitmodules_config(); - compile_submodule_options(&opt, &pathspec, cached, untracked, + compile_submodule_options(&opt, argv + i, cached, untracked, opt_exclude, use_index, pattern_type_arg); } diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh index 67247a0..5b6eb3a 100755 --- a/t/t7814-grep-recurse-submodules.sh +++ b/t/t7814-grep-recurse-submodules.sh @@ -227,6 +227,81 @@ test_expect_success 'grep history with moved submoules' ' test_cmp expect actual ' +test_expect_success 'grep using relative path' ' + test_when_finished "rm -rf parent sub" && + git init sub && + echo "foobar" >sub/file && + git -C sub add file && + git -C sub commit -m "add file" && + + git init parent && + echo "foobar" >parent/file && + git -C parent add file && + mkdir parent/src && + echo "foobar" >parent/src/file2 && + git -C parent add src/file2 && + git -C parent submodule add ../sub && + git -C parent commit -m "add files and submodule" && + + # From top works + cat >expect <<-\EOF && + file:foobar + src/file2:foobar + sub/file:foobar + EOF + git -C parent grep --recurse-submodules -e "foobar" >actual && + test_cmp expect actual && + + # Relative path to top + cat >expect <<-\EOF && + ../file:foobar + file2:foobar + ../sub/file:foobar + EOF + git -C parent/src grep --recurse-submodules -e "foobar" -- .. >actual && + test_cmp expect actual && + + # Relative path to submodule + cat >expect <<-\EOF && + ../sub/file:foobar + EOF + git -C parent/src grep --recurse-submodules -e "foobar" -- ../sub >actual && + test_cmp expect actual +' + +test_expect_success 'grep from a subdir' ' + test_when_finished "rm -rf parent sub" && + git init sub && + echo "foobar" >sub/file && + git -C sub add file && + git -C sub commit -m "add file" && + + git init parent && + mkdir parent/src && + echo "foobar" >parent/src/file && + git -C parent add src/file && + git -C parent submodule add ../sub src/sub && + git -C parent submodule add ../sub sub && + git -C parent commit -m "add files and submodules" && + + # Verify grep from root works + cat >expect <<-\EOF && + src/file:foobar + src/sub/file:foobar + sub/file:foobar + EOF + git -C parent grep --recurse-submodules -e "foobar" >actual && + test_cmp expect actual && + + # Verify grep from a subdir works + cat >expect <<-\EOF && + file:foobar + sub/file:foobar + EOF + git -C parent/src grep --recurse-submodules -e "foobar" >actual && + test_cmp expect actual +' + test_incompatible_with_recurse_submodules () { test_expect_success "--recurse-submodules and $1 are incompatible" " -- cgit v0.10.2-6-g49f6 From e4770f67d16c1970fa175bddfd4ca40258e57f22 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 17 Mar 2017 10:22:56 -0700 Subject: ls-files: fix typo in variable name Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 1c0f057..ca5b48d 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -30,7 +30,7 @@ static int line_terminator = '\n'; static int debug_mode; static int show_eol; static int recurse_submodules; -static struct argv_array submodules_options = ARGV_ARRAY_INIT; +static struct argv_array submodule_options = ARGV_ARRAY_INIT; static const char *prefix; static const char *super_prefix; @@ -175,17 +175,17 @@ static void show_killed_files(struct dir_struct *dir) static void compile_submodule_options(const struct dir_struct *dir, int show_tag) { if (line_terminator == '\0') - argv_array_push(&submodules_options, "-z"); + argv_array_push(&submodule_options, "-z"); if (show_tag) - argv_array_push(&submodules_options, "-t"); + argv_array_push(&submodule_options, "-t"); if (show_valid_bit) - argv_array_push(&submodules_options, "-v"); + argv_array_push(&submodule_options, "-v"); if (show_cached) - argv_array_push(&submodules_options, "--cached"); + argv_array_push(&submodule_options, "--cached"); if (show_eol) - argv_array_push(&submodules_options, "--eol"); + argv_array_push(&submodule_options, "--eol"); if (debug_mode) - argv_array_push(&submodules_options, "--debug"); + argv_array_push(&submodule_options, "--debug"); } /** @@ -204,7 +204,7 @@ static void show_gitlink(const struct cache_entry *ce) argv_array_push(&cp.args, "--recurse-submodules"); /* add supported options */ - argv_array_pushv(&cp.args, submodules_options.argv); + argv_array_pushv(&cp.args, submodule_options.argv); /* * Pass in the original pathspec args. The submodule will be -- cgit v0.10.2-6-g49f6 From b2dfeb7c005b83145e9f61305658f5dac745482a Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 17 Mar 2017 10:22:57 -0700 Subject: ls-files: fix bug when recursing with relative pathspec When using the --recurse-submodules flag with a relative pathspec which includes "..", an error is produced inside the child process spawned for a submodule. When creating the pathspec struct in the child, the ".." is interpreted to mean "go up a directory" which causes an error stating that the path ".." is outside of the repository. While it is true that ".." is outside the scope of the submodule, it is confusing to a user who originally invoked the command where ".." was indeed still inside the scope of the superproject. Since the child process launched for the submodule has some context that it is operating underneath a superproject, this error could be avoided. This patch fixes the bug by passing the 'prefix' to the child process. Now each child process that works on a submodule has two points of reference to the superproject: (1) the 'super_prefix' which is the path from the root of the superproject down to root of the submodule and (2) the 'prefix' which is the path from the root of the superproject down to the directory where the user invoked the git command. With these two pieces of information a child process can correctly interpret the pathspecs provided by the user as well as being able to properly format its output relative to the directory the user invoked the original command from. Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano diff --git a/builtin/ls-files.c b/builtin/ls-files.c index ca5b48d..d449e46 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -172,7 +172,9 @@ static void show_killed_files(struct dir_struct *dir) /* * Compile an argv_array with all of the options supported by --recurse_submodules */ -static void compile_submodule_options(const struct dir_struct *dir, int show_tag) +static void compile_submodule_options(const char **argv, + const struct dir_struct *dir, + int show_tag) { if (line_terminator == '\0') argv_array_push(&submodule_options, "-z"); @@ -186,6 +188,11 @@ static void compile_submodule_options(const struct dir_struct *dir, int show_tag argv_array_push(&submodule_options, "--eol"); if (debug_mode) argv_array_push(&submodule_options, "--debug"); + + /* Add Pathspecs */ + argv_array_push(&submodule_options, "--"); + for (; *argv; argv++) + argv_array_push(&submodule_options, *argv); } /** @@ -195,8 +202,11 @@ static void show_gitlink(const struct cache_entry *ce) { struct child_process cp = CHILD_PROCESS_INIT; int status; - int i; + if (prefix_len) + argv_array_pushf(&cp.env_array, "%s=%s", + GIT_TOPLEVEL_PREFIX_ENVIRONMENT, + prefix); argv_array_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ? super_prefix : "", ce->name); @@ -206,15 +216,6 @@ static void show_gitlink(const struct cache_entry *ce) /* add supported options */ argv_array_pushv(&cp.args, submodule_options.argv); - /* - * Pass in the original pathspec args. The submodule will be - * responsible for prepending the 'submodule_prefix' prior to comparing - * against the pathspec for matches. - */ - argv_array_push(&cp.args, "--"); - for (i = 0; i < pathspec.nr; i++) - argv_array_push(&cp.args, pathspec.items[i].original); - cp.git_cmd = 1; cp.dir = ce->name; status = run_command(&cp); @@ -604,7 +605,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) setup_work_tree(); if (recurse_submodules) - compile_submodule_options(&dir, show_tag); + compile_submodule_options(argv, &dir, show_tag); if (recurse_submodules && (show_stage || show_deleted || show_others || show_unmerged || diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh index a542617..4cf6ccf 100755 --- a/t/t3007-ls-files-recurse-submodules.sh +++ b/t/t3007-ls-files-recurse-submodules.sh @@ -188,6 +188,45 @@ test_expect_success '--recurse-submodules and pathspecs' ' test_cmp expect actual ' +test_expect_success '--recurse-submodules and relative paths' ' + # From subdir + cat >expect <<-\EOF && + b + EOF + git -C b ls-files --recurse-submodules >actual && + test_cmp expect actual && + + # Relative path to top + cat >expect <<-\EOF && + ../.gitmodules + ../a + b + ../h.txt + ../sib/file + ../sub/file + ../submodule/.gitmodules + ../submodule/c + ../submodule/f.TXT + ../submodule/g.txt + ../submodule/subsub/d + ../submodule/subsub/e.txt + EOF + git -C b ls-files --recurse-submodules -- .. >actual && + test_cmp expect actual && + + # Relative path to submodule + cat >expect <<-\EOF && + ../submodule/.gitmodules + ../submodule/c + ../submodule/f.TXT + ../submodule/g.txt + ../submodule/subsub/d + ../submodule/subsub/e.txt + EOF + git -C b ls-files --recurse-submodules -- ../submodule >actual && + test_cmp expect actual +' + test_expect_success '--recurse-submodules does not support --error-unmatch' ' test_must_fail git ls-files --recurse-submodules --error-unmatch 2>actual && test_i18ngrep "does not support --error-unmatch" actual -- cgit v0.10.2-6-g49f6