git: make super-prefix option

Add a super-prefix environment variable 'GIT_INTERNAL_SUPER_PREFIX' which can be used to specify a path from above a repository down to its root. When such a super-prefix is specified, the paths reported by Git are prefixed with it to make them relative to that directory "above". The paths given by the user on the command line (e.g. "git subcmd --output-file=path/to/a/file" and pathspecs) are taken relative to the directory "above" to match. The immediate use of this option is by commands which have a --recurse-submodule option in order to give context to submodules about how they were invoked. This option is currently only allowed for builtins which support a super-prefix. Signed-off-by: Brandon Williams <bmwill@google.com> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed Oct 7, 2016 at 11:18 UTC 74866d75793559e8b351a17100679f83b96972ca
4 files changed +46
Documentation/git.txt
+6
@@ -13,6 +13,7 @@ SYNOPSIS
13 [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
14 [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
15 [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
16 + [--super-prefix=<path>]
17 <command> [<args>]
18
19 DESCRIPTION
@@ -601,6 +602,11 @@ foo.bar= ...`) sets `foo.bar` to the empty string.
602 details. Equivalent to setting the `GIT_NAMESPACE` environment
603 variable.
604
605 +--super-prefix=<path>::
606 + Currently for internal use only. Set a prefix which gives a path from
607 + above a repository down to its root. One use is to give submodules
608 + context about the superproject that invoked it.
609 +
610 --bare::
611 Treat the repository as a bare repository. If GIT_DIR
612 environment is not set, it is set to the current working
cache.h
+2
@@ -408,6 +408,7 @@ static inline enum object_type object_type(unsigned int mode)
408 #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
409 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
410 #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
411 +#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
412 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
413 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
414 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -468,6 +469,7 @@ extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
469 extern int get_common_dir(struct strbuf *sb, const char *gitdir);
470 extern const char *get_git_namespace(void);
471 extern const char *strip_namespace(const char *namespaced_ref);
472 +extern const char *get_super_prefix(void);
473 extern const char *get_git_work_tree(void);
474
475 /*
environment.c
+13
@@ -100,6 +100,8 @@ static char *work_tree;
100 static const char *namespace;
101 static size_t namespace_len;
102
103 +static const char *super_prefix;
104 +
105 static const char *git_dir, *git_common_dir;
106 static char *git_object_dir, *git_index_file, *git_graft_file;
107 int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
@@ -120,6 +122,7 @@ const char * const local_repo_env[] = {
122 NO_REPLACE_OBJECTS_ENVIRONMENT,
123 GIT_REPLACE_REF_BASE_ENVIRONMENT,
124 GIT_PREFIX_ENVIRONMENT,
125 + GIT_SUPER_PREFIX_ENVIRONMENT,
126 GIT_SHALLOW_FILE_ENVIRONMENT,
127 GIT_COMMON_DIR_ENVIRONMENT,
128 NULL
@@ -222,6 +225,16 @@ const char *strip_namespace(const char *namespaced_ref)
225 return namespaced_ref + namespace_len;
226 }
227
228 +const char *get_super_prefix(void)
229 +{
230 + static int initialized;
231 + if (!initialized) {
232 + super_prefix = getenv(GIT_SUPER_PREFIX_ENVIRONMENT);
233 + initialized = 1;
234 + }
235 + return super_prefix;
236 +}
237 +
238 static int git_work_tree_initialized;
239
240 /*
git.c
+25
@@ -164,6 +164,20 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
164 setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
165 if (envchanged)
166 *envchanged = 1;
167 + } else if (!strcmp(cmd, "--super-prefix")) {
168 + if (*argc < 2) {
169 + fprintf(stderr, "No prefix given for --super-prefix.\n" );
170 + usage(git_usage_string);
171 + }
172 + setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
173 + if (envchanged)
174 + *envchanged = 1;
175 + (*argv)++;
176 + (*argc)--;
177 + } else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
178 + setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
179 + if (envchanged)
180 + *envchanged = 1;
181 } else if (!strcmp(cmd, "--bare")) {
182 char *cwd = xgetcwd();
183 is_bare_repository_cfg = 1;
@@ -310,6 +324,7 @@ static int handle_alias(int *argcp, const char ***argv)
324 * RUN_SETUP for reading from the configuration file.
325 */
326 #define NEED_WORK_TREE (1<<3)
327 +#define SUPPORT_SUPER_PREFIX (1<<4)
328
329 struct cmd_struct {
330 const char *cmd;
@@ -344,6 +359,13 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
359 }
360 commit_pager_choice();
361
362 + if (!help && get_super_prefix()) {
363 + if (!(p->option & SUPPORT_SUPER_PREFIX))
364 + die("%s doesn't support --super-prefix", p->cmd);
365 + if (prefix)
366 + die("can't use --super-prefix from a subdirectory");
367 + }
368 +
369 if (!help && p->option & NEED_WORK_TREE)
370 setup_work_tree();
371
@@ -558,6 +580,9 @@ static void execv_dashed_external(const char **argv)
580 const char *tmp;
581 int status;
582
583 + if (get_super_prefix())
584 + die("%s doesn't support --super-prefix", argv[0]);
585 +
586 if (use_pager == -1)
587 use_pager = check_pager_config(argv[0]);
588 commit_pager_choice();