From: Junio C Hamano Date: Mon, 19 Jun 2017 19:38:42 +0000 (-0700) Subject: Merge branch 'jk/pathspec-magic-disambiguation' X-Git-Tag: v2.14.0-rc0~89 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/32e0da583f70fe1406268217befd61e3f515505f?ds=inline;hp=-c Merge branch 'jk/pathspec-magic-disambiguation' The convention for a command line is to follow "git cmdname --options" with revisions followed by an optional "--" disambiguator and then finally pathspecs. When "--" is not there, we make sure early ones are all interpretable as revs (and do not look like paths) and later ones are the other way around. A pathspec with "magic" (e.g. ":/p/a/t/h" that matches p/a/t/h from the top-level of the working tree, no matter what subdirectory you are working from) are conservatively judged as "not a path", which required disambiguation more often. The command line parser learned to say "it's a pathspec" a bit more often when the syntax looks like so. * jk/pathspec-magic-disambiguation: verify_filename(): flip order of checks verify_filename(): treat ":(magic)" as a pathspec check_filename(): handle ":^" path magic check_filename(): use skip_prefix check_filename(): refactor ":/" handling t4208: add check for ":/" without matching file --- 32e0da583f70fe1406268217befd61e3f515505f diff --combined setup.c index ba6e855178,1de87ed842..751d02b9be --- a/setup.c +++ b/setup.c @@@ -134,23 -134,27 +134,27 @@@ int path_inside_repo(const char *prefix int check_filename(const char *prefix, const char *arg) { - const char *name; char *to_free = NULL; struct stat st; - if (starts_with(arg, ":/")) { - if (arg[2] == '\0') /* ":/" is root dir, always exists */ + if (skip_prefix(arg, ":/", &arg)) { + if (!*arg) /* ":/" is root dir, always exists */ return 1; - name = arg + 2; - } else if (prefix) - name = to_free = prefix_filename(prefix, arg); - else - name = arg; - if (!lstat(name, &st)) { + prefix = NULL; + } else if (skip_prefix(arg, ":!", &arg) || + skip_prefix(arg, ":^", &arg)) { + if (!*arg) /* excluding everything is silly, but allowed */ + return 1; + } + + if (prefix) + arg = to_free = prefix_filename(prefix, arg); + + if (!lstat(arg, &st)) { free(to_free); return 1; /* file exists */ } - if (errno == ENOENT || errno == ENOTDIR) { + if (is_missing_file_error(errno)) { free(to_free); return 0; /* file does not exist */ } @@@ -181,6 -185,24 +185,24 @@@ static void NORETURN die_verify_filenam } + /* + * Check for arguments that don't resolve as actual files, + * but which look sufficiently like pathspecs that we'll consider + * them such for the purposes of rev/pathspec DWIM parsing. + */ + static int looks_like_pathspec(const char *arg) + { + /* anything with a wildcard character */ + if (!no_wildcard(arg)) + return 1; + + /* long-form pathspec magic */ + if (starts_with(arg, ":(")) + return 1; + + return 0; + } + /* * Verify a filename that we got as an argument for a pathspec * entry. Note that a filename that begins with "-" never verifies @@@ -207,7 -229,7 +229,7 @@@ void verify_filename(const char *prefix { if (*arg == '-') die("bad flag '%s' used after filename", arg); - if (check_filename(prefix, arg) || !no_wildcard(arg)) + if (looks_like_pathspec(arg) || check_filename(prefix, arg)) return; die_verify_filename(prefix, arg, diagnose_misspelt_rev); } @@@ -703,16 -725,11 +725,16 @@@ static const char *setup_discovered_git /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { + char *to_free = NULL; + const char *ret; + if (offset != cwd->len && !is_absolute_path(gitdir)) - gitdir = real_pathdup(gitdir, 1); + gitdir = to_free = real_pathdup(gitdir, 1); if (chdir(cwd->buf)) die_errno("Could not come back to cwd"); - return setup_explicit_git_dir(gitdir, cwd, nongit_ok); + ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok); + free(to_free); + return ret; } /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */ @@@ -753,7 -770,7 +775,7 @@@ static const char *setup_bare_git_dir(s /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { - const char *gitdir; + static const char *gitdir; gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset); if (chdir(cwd->buf))