From: Junio C Hamano Date: Thu, 30 Jun 2011 00:09:27 +0000 (-0700) Subject: Merge branch 'da/git-prefix-everywhere' into next X-Git-Tag: v1.7.7-rc0~114 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/4ed54610e5ca8fdc34dcf8729f6416599d1bc39e?ds=inline;hp=-c Merge branch 'da/git-prefix-everywhere' into next * da/git-prefix-everywhere: t/t7503-pre-commit-hook.sh: Add GIT_PREFIX tests git-mergetool--lib: Make vimdiff retain the current directory git: Remove handling for GIT_PREFIX setup: Provide GIT_PREFIX to built-ins --- 4ed54610e5ca8fdc34dcf8729f6416599d1bc39e diff --combined git-mergetool--lib.sh index 4db9212331,f5a100a567..91f90acfba --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@@ -86,6 -86,11 +86,11 @@@ get_merge_tool_cmd () } run_merge_tool () { + # If GIT_PREFIX is empty then we cannot use it in tools + # that expect to be able to chdir() to its value. + GIT_PREFIX=${GIT_PREFIX:-.} + export GIT_PREFIX + merge_tool_path="$(get_merge_tool_path "$1")" || exit base_present="$2" status=0 @@@ -188,6 -193,7 +193,7 @@@ check_unchanged else "$merge_tool_path" -R -f -d -c "wincmd l" \ + -c 'cd $GIT_PREFIX' \ "$LOCAL" "$REMOTE" fi ;; @@@ -199,6 -205,7 +205,7 @@@ check_unchanged else "$merge_tool_path" -R -f -d -c "wincmd l" \ + -c 'cd $GIT_PREFIX' \ "$LOCAL" "$REMOTE" fi ;; @@@ -258,9 -265,12 +265,9 @@@ ;; p4merge) if merge_mode; then - touch "$BACKUP" - if $base_present; then - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" - else - "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" - fi + touch "$BACKUP" + $base_present || >"$BASE" + "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" check_unchanged else "$merge_tool_path" "$LOCAL" "$REMOTE" diff --combined git.c index 89721d420a,ef598c3e70..8828c18d6c --- a/git.c +++ b/git.c @@@ -6,7 -6,7 +6,7 @@@ #include "run-command.h" const char git_usage_string[] = - "git [--version] [--exec-path[=]] [--html-path]\n" + "git [--version] [--exec-path[=]] [--html-path] [--man-path] [--info-path]\n" " [-p|--paginate|--no-pager] [--no-replace-objects]\n" " [--bare] [--git-dir=] [--work-tree=]\n" " [-c name=value] [--help]\n" @@@ -66,7 -66,7 +66,7 @@@ static void commit_pager_choice(void) static int handle_options(const char ***argv, int *argc, int *envchanged) { - int handled = 0; + const char **orig_argv = *argv; while (*argc > 0) { const char *cmd = (*argv)[0]; @@@ -95,12 -95,6 +95,12 @@@ } else if (!strcmp(cmd, "--html-path")) { puts(system_path(GIT_HTML_PATH)); exit(0); + } else if (!strcmp(cmd, "--man-path")) { + puts(system_path(GIT_MAN_PATH)); + exit(0); + } else if (!strcmp(cmd, "--info-path")) { + puts(system_path(GIT_INFO_PATH)); + exit(0); } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) { use_pager = 1; } else if (!strcmp(cmd, "--no-pager")) { @@@ -122,6 -116,7 +122,6 @@@ *envchanged = 1; (*argv)++; (*argc)--; - handled++; } else if (!prefixcmp(cmd, "--git-dir=")) { setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); if (envchanged) @@@ -161,8 -156,9 +161,8 @@@ (*argv)++; (*argc)--; - handled++; } - return handled; + return (*argv) - orig_argv; } static int handle_alias(int *argcp, const char ***argv) @@@ -183,8 -179,6 +183,6 @@@ if (alias_string[0] == '!') { const char **alias_argv; int argc = *argcp, i; - struct strbuf sb = STRBUF_INIT; - const char *env[2]; commit_pager_choice(); @@@ -195,13 -189,7 +193,7 @@@ alias_argv[i] = (*argv)[i]; alias_argv[argc] = NULL; - strbuf_addstr(&sb, "GIT_PREFIX="); - if (subdir) - strbuf_addstr(&sb, subdir); - env[0] = sb.buf; - env[1] = NULL; - ret = run_command_v_opt_cd_env(alias_argv, RUN_USING_SHELL, NULL, env); - strbuf_release(&sb); + ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); if (ret >= 0) /* normal exit */ exit(ret); diff --combined setup.c index ce87900ce3,63f5368d90..5ea5502e48 --- a/setup.c +++ b/setup.c @@@ -85,17 -85,8 +85,17 @@@ static void NORETURN die_verify_filenam { unsigned char sha1[20]; unsigned mode; - /* try a detailed diagnostic ... */ - get_sha1_with_mode_1(arg, sha1, &mode, 0, prefix); + + /* + * Saying "'(icase)foo' does not exist in the index" when the + * user gave us ":(icase)foo" is just stupid. A magic pathspec + * begins with a colon and is followed by a non-alnum; do not + * let get_sha1_with_mode_1(only_to_die=1) to even trigger. + */ + if (!(arg[0] == ':' && !isalnum(arg[1]))) + /* try a detailed diagnostic ... */ + get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix); + /* ... or fall back the most general message. */ die("ambiguous argument '%s': unknown revision or path not in the working tree.\n" "Use '--' to separate paths from revisions", arg); @@@ -135,105 -126,6 +135,105 @@@ void verify_non_filename(const char *pr "Use '--' to separate filenames from revisions", arg); } +/* + * Magic pathspec + * + * NEEDSWORK: These need to be moved to dir.h or even to a new + * pathspec.h when we restructure get_pathspec() users to use the + * "struct pathspec" interface. + * + * Possible future magic semantics include stuff like: + * + * { PATHSPEC_NOGLOB, '!', "noglob" }, + * { PATHSPEC_ICASE, '\0', "icase" }, + * { PATHSPEC_RECURSIVE, '*', "recursive" }, + * { PATHSPEC_REGEXP, '\0', "regexp" }, + * + */ +#define PATHSPEC_FROMTOP (1<<0) + +static struct pathspec_magic { + unsigned bit; + char mnemonic; /* this cannot be ':'! */ + const char *name; +} pathspec_magic[] = { + { PATHSPEC_FROMTOP, '/', "top" }, +}; + +/* + * Take an element of a pathspec and check for magic signatures. + * Append the result to the prefix. + * + * For now, we only parse the syntax and throw out anything other than + * "top" magic. + * + * NEEDSWORK: This needs to be rewritten when we start migrating + * get_pathspec() users to use the "struct pathspec" interface. For + * example, a pathspec element may be marked as case-insensitive, but + * the prefix part must always match literally, and a single stupid + * string cannot express such a case. + */ +static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt) +{ + unsigned magic = 0; + const char *copyfrom = elt; + int i; + + if (elt[0] != ':') { + ; /* nothing to do */ + } else if (elt[1] == '(') { + /* longhand */ + const char *nextat; + for (copyfrom = elt + 2; + *copyfrom && *copyfrom != ')'; + copyfrom = nextat) { + size_t len = strcspn(copyfrom, ",)"); + if (copyfrom[len] == ')') + nextat = copyfrom + len; + else + nextat = copyfrom + len + 1; + if (!len) + continue; + for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) + if (strlen(pathspec_magic[i].name) == len && + !strncmp(pathspec_magic[i].name, copyfrom, len)) { + magic |= pathspec_magic[i].bit; + break; + } + if (ARRAY_SIZE(pathspec_magic) <= i) + die("Invalid pathspec magic '%.*s' in '%s'", + (int) len, copyfrom, elt); + } + if (*copyfrom == ')') + copyfrom++; + } else { + /* shorthand */ + for (copyfrom = elt + 1; + *copyfrom && *copyfrom != ':'; + copyfrom++) { + char ch = *copyfrom; + + if (!is_pathspec_magic(ch)) + break; + for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) + if (pathspec_magic[i].mnemonic == ch) { + magic |= pathspec_magic[i].bit; + break; + } + if (ARRAY_SIZE(pathspec_magic) <= i) + die("Unimplemented pathspec magic '%c' in '%s'", + ch, elt); + } + if (*copyfrom == ':') + copyfrom++; + } + + if (magic & PATHSPEC_FROMTOP) + return xstrdup(copyfrom); + else + return prefix_path(prefix, prefixlen, copyfrom); +} + const char **get_pathspec(const char *prefix, const char **pathspec) { const char *entry = *pathspec; @@@ -255,7 -147,8 +255,7 @@@ dst = pathspec; prefixlen = prefix ? strlen(prefix) : 0; while (*src) { - const char *p = prefix_path(prefix, prefixlen, *src); - *(dst++) = p; + *(dst++) = prefix_pathspec(prefix, prefixlen, *src); src++; } *dst = NULL; @@@ -382,7 -275,7 +382,7 @@@ const char *read_gitfile_gently(const c const char *slash; struct stat st; int fd; - size_t len; + ssize_t len; if (stat(path, &st)) return NULL; @@@ -432,7 -325,6 +432,7 @@@ static const char *setup_explicit_git_d const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); const char *worktree; char *gitfile; + int offset; if (PATH_MAX - 40 < strlen(gitdirenv)) die("'$%s' too big", GIT_DIR_ENVIRONMENT); @@@ -498,15 -390,15 +498,15 @@@ return NULL; } - if (!prefixcmp(cwd, worktree) && - cwd[strlen(worktree)] == '/') { /* cwd inside worktree */ + offset = dir_inside_of(cwd, worktree); + if (offset >= 0) { /* cwd inside worktree? */ set_git_dir(real_path(gitdirenv)); if (chdir(worktree)) die_errno("Could not chdir to '%s'", worktree); cwd[len++] = '/'; cwd[len] = '\0'; free(gitfile); - return cwd + strlen(worktree) + 1; + return cwd + offset; } /* cwd outside worktree */ @@@ -710,6 -602,11 +710,11 @@@ const char *setup_git_directory_gently( const char *prefix; prefix = setup_git_directory_gently_1(nongit_ok); + if (prefix) + setenv("GIT_PREFIX", prefix, 1); + else + setenv("GIT_PREFIX", "", 1); + if (startup_info) { startup_info->have_repository = !nongit_ok || !*nongit_ok; startup_info->prefix = prefix; diff --combined t/t1020-subdirectory.sh index f6a44c9ee0,3c7448026d..865b8ed26d --- a/t/t1020-subdirectory.sh +++ b/t/t1020-subdirectory.sh @@@ -7,7 -7,6 +7,7 @@@ test_description='Try various core-leve ' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-read-tree.sh test_expect_success setup ' long="a b c d e f g h i j k l m n o p q r s t u v w x y z" && @@@ -99,13 -98,13 +99,13 @@@ test_expect_success 'checkout-index' test_expect_success 'read-tree' ' rm -f one dir/two && tree=`git write-tree` && - git read-tree --reset -u "$tree" && + read_tree_u_must_succeed --reset -u "$tree" && cmp one original.one && cmp dir/two original.two && ( cd dir && rm -f two && - git read-tree --reset -u "$tree" && + read_tree_u_must_succeed --reset -u "$tree" && cmp two ../original.two && cmp ../one ../original.one ) @@@ -140,6 -139,22 +140,22 @@@ test_expect_success 'GIT_PREFIX for !al test_cmp expect actual ' + test_expect_success 'GIT_PREFIX for built-ins' ' + # Use GIT_EXTERNAL_DIFF to test that the "diff" built-in + # receives the GIT_PREFIX variable. + printf "dir/" >expect && + printf "#!/bin/sh\n" >diff && + printf "printf \"\$GIT_PREFIX\"" >>diff && + chmod +x diff && + ( + cd dir && + printf "change" >two && + env GIT_EXTERNAL_DIFF=./diff git diff >../actual + git checkout -- two + ) && + test_cmp expect actual + ' + test_expect_success 'no file/rev ambiguity check inside .git' ' git commit -a -m 1 && (