From 46c3cd44d7a1e8a33ad66c017ac9e3575cc88c00 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Mar 2016 17:10:27 -0500 Subject: setup: make startup_info available everywhere Commit a60645f (setup: remember whether repository was found, 2010-08-05) introduced the startup_info structure, which records some parts of the setup_git_directory() process (notably, whether we actually found a repository or not). One of the uses of this data is for functions to behave appropriately based on whether we are in a repo. But the startup_info struct is just a pointer to storage provided by the main program, and the only program that sets it up is the git.c wrapper. Thus builtins have access to startup_info, but externally linked programs do not. Worse, library code which is accessible from both has to be careful about accessing startup_info. This can be used to trigger a die("BUG") via get_sha1(): $ git fast-import <<-\EOF tag foo from HEAD:./whatever EOF fatal: BUG: startup_info struct is not initialized. Obviously that's fairly nonsensical input to feed to fast-import, but we should never hit a die("BUG"). And there may be other ways to trigger it if other non-builtins resolve sha1s. So let's point the storage for startup_info to a static variable in setup.c, making it available to all users of the library code. We _could_ turn startup_info into a regular extern struct, but doing so would mean tweaking all of the existing use sites. So let's leave the pointer indirection in place. We can, however, drop any checks for NULL, as they will always be false (and likewise, we can drop the test covering this case, which was a rather artificial situation using one of the test-* programs). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/cache.h b/cache.h index b829410..9f09540 100644 --- a/cache.h +++ b/cache.h @@ -1771,7 +1771,7 @@ int split_cmdline(char *cmdline, const char ***argv); /* Takes a negative value returned by split_cmdline */ const char *split_cmdline_strerror(int cmdline_errno); -/* git.c */ +/* setup.c */ struct startup_info { int have_repository; const char *prefix; diff --git a/environment.c b/environment.c index 6dec9d0..6cc0a77 100644 --- a/environment.c +++ b/environment.c @@ -64,7 +64,6 @@ int grafts_replace_parents = 1; int core_apply_sparse_checkout; int merge_log_config = -1; int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ -struct startup_info *startup_info; unsigned long pack_size_limit_cfg; #ifndef PROTECT_HFS_DEFAULT diff --git a/git.c b/git.c index 6cc0c07..968a8a4 100644 --- a/git.c +++ b/git.c @@ -15,7 +15,6 @@ const char git_more_info_string[] = "concept guides. See 'git help ' or 'git help '\n" "to read about a specific subcommand or concept."); -static struct startup_info git_startup_info; static int use_pager = -1; static char *orig_cwd; static const char *env_names[] = { @@ -637,8 +636,6 @@ int main(int argc, char **av) const char *cmd; int done_help = 0; - startup_info = &git_startup_info; - cmd = git_extract_argv0_path(argv[0]); if (!cmd) cmd = "git-help"; diff --git a/setup.c b/setup.c index de1a2a7..fa7a306 100644 --- a/setup.c +++ b/setup.c @@ -7,6 +7,9 @@ static int inside_work_tree = -1; static int work_tree_config_is_bogus; static struct string_list unknown_extensions = STRING_LIST_INIT_DUP; +static struct startup_info the_startup_info; +struct startup_info *startup_info = &the_startup_info; + /* * The input parameter must contain an absolute path, and it must already be * normalized. @@ -905,10 +908,9 @@ const char *setup_git_directory_gently(int *nongit_ok) else setenv(GIT_PREFIX_ENVIRONMENT, "", 1); - if (startup_info) { - startup_info->have_repository = !nongit_ok || !*nongit_ok; - startup_info->prefix = prefix; - } + startup_info->have_repository = !nongit_ok || !*nongit_ok; + startup_info->prefix = prefix; + return prefix; } diff --git a/sha1_name.c b/sha1_name.c index 3acf221..776101e 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -1353,9 +1353,6 @@ static char *resolve_relative_path(const char *rel) if (!starts_with(rel, "./") && !starts_with(rel, "../")) return NULL; - if (!startup_info) - die("BUG: startup_info struct is not initialized."); - if (!is_inside_work_tree()) die("relative path syntax can't be used outside working tree."); diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh index 613d9bf..86c2ff2 100755 --- a/t/t1506-rev-parse-diagnosis.sh +++ b/t/t1506-rev-parse-diagnosis.sh @@ -166,11 +166,6 @@ test_expect_success 'relative path when cwd is outside worktree' ' grep "relative path syntax can.t be used outside working tree." error ' -test_expect_success 'relative path when startup_info is NULL' ' - test_must_fail test-match-trees HEAD:./file.txt HEAD:./file.txt 2>error && - grep "BUG: startup_info struct is not initialized." error -' - test_expect_success ':file correctly diagnosed after a pathname' ' test_must_fail git rev-parse file.txt HEAD:file.txt 1>actual 2>error && test_i18ngrep ! "exists on disk" error && -- cgit v0.10.2-6-g49f6 From f1c126bd8b24ab7a78de33f4ba1f8a496e7245e2 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Mar 2016 17:11:34 -0500 Subject: setup: set startup_info->have_repository more reliably When setup_git_directory() is called, we set a flag in startup_info to indicate we have a repository. But there are a few other mechanisms by which we might set up a repo: 1. When creating a new repository via init_db(), we transition from no-repo to being in a repo. We should tweak this flag at that moment. 2. In enter_repo(), a stricter form of setup_git_directory() used by server-side programs, we check the repository format config. After doing so, we know we're in a repository, and can set the flag. With these changes, library code can now reliably tell whether we are in a repository and act accordingly. We'll leave the "prefix" field as NULL, which is what happens when setup_git_directory() finds there is no prefix. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/builtin/init-db.c b/builtin/init-db.c index 6223b7d..da531f6 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -322,6 +322,7 @@ int set_git_dir_init(const char *git_dir, const char *real_git_dir, set_git_dir(real_path(git_dir)); git_link = NULL; } + startup_info->have_repository = 1; return 0; } diff --git a/setup.c b/setup.c index fa7a306..3439ec6 100644 --- a/setup.c +++ b/setup.c @@ -986,7 +986,9 @@ int check_repository_format_version(const char *var, const char *value, void *cb int check_repository_format(void) { - return check_repository_format_gently(get_git_dir(), NULL); + check_repository_format_gently(get_git_dir(), NULL); + startup_info->have_repository = 1; + return 0; } /* -- cgit v0.10.2-6-g49f6 From f2f12d169aa607604edbd942675026174f061e3f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Mar 2016 17:11:57 -0500 Subject: remote: don't resolve HEAD in non-repository The remote-config code wants to look at HEAD to mark the current branch specially. But if we are not in a repository (e.g., running "git archive --remote"), this makes no sense; there is no HEAD to look at, and we have no current branch. This doesn't really cause any bugs in practice (if you are not in a repo, you probably don't have a .git/HEAD file), but we should be more careful about triggering the refs code at all in a non-repo. As we grow new ref backends, we would not even know which backend to use. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/remote.c b/remote.c index fc02698..28fd676 100644 --- a/remote.c +++ b/remote.c @@ -455,7 +455,6 @@ static void read_config(void) { static int loaded; struct object_id oid; - const char *head_ref; int flag; if (loaded) @@ -463,10 +462,12 @@ static void read_config(void) loaded = 1; current_branch = NULL; - head_ref = resolve_ref_unsafe("HEAD", 0, oid.hash, &flag); - if (head_ref && (flag & REF_ISSYMREF) && - skip_prefix(head_ref, "refs/heads/", &head_ref)) { - current_branch = make_branch(head_ref, 0); + if (startup_info->have_repository) { + const char *head_ref = resolve_ref_unsafe("HEAD", 0, oid.hash, &flag); + if (head_ref && (flag & REF_ISSYMREF) && + skip_prefix(head_ref, "refs/heads/", &head_ref)) { + current_branch = make_branch(head_ref, 0); + } } git_config(handle_config, NULL); alias_all_urls(); -- cgit v0.10.2-6-g49f6 From 5735dc5a0df5de12b28237ff2c41df6df5f67b81 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Mar 2016 17:13:29 -0500 Subject: mailmap: do not resolve blobs in a non-repository The mailmap code may be triggered outside of a repository by git-shortlog. There is no point in looking up a name like "HEAD:.mailmap" there; without a repository, we have no refs. This is unlikely to matter much in practice for the current code, as we would simply fail to find the ref. But as the refs code learns about new backends, this is more important; without a repository, we do not even know which backend to look at. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/mailmap.c b/mailmap.c index f4a0f1c..9726237 100644 --- a/mailmap.c +++ b/mailmap.c @@ -250,7 +250,8 @@ int read_mailmap(struct string_list *map, char **repo_abbrev) git_mailmap_blob = "HEAD:.mailmap"; err |= read_mailmap_file(map, ".mailmap", repo_abbrev); - err |= read_mailmap_blob(map, git_mailmap_blob, repo_abbrev); + if (startup_info->have_repository) + err |= read_mailmap_blob(map, git_mailmap_blob, repo_abbrev); err |= read_mailmap_file(map, git_mailmap_file, repo_abbrev); return err; } -- cgit v0.10.2-6-g49f6 From 85975c0c7f46aeb5010121959e38c339038758a7 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 7 Mar 2016 10:51:21 -0500 Subject: grep: turn off gitlink detection for --no-index If we are running "git grep --no-index" outside of a git repository, we behave roughly like "grep -r", examining all files in the current directory and its subdirectories. However, because we use fill_directory() to do the recursion, it will skip over any directories which look like sub-repositories. For a normal git operation (like "git grep" in a repository) this makes sense; we do not want to cross the boundary out of our current repository into a submodule. But for "--no-index" without a repository, we should look at all files, including embedded repositories. There is one exception, though: we probably should _not_ descend into ".git" directories. Doing so is inefficient and unlikely to turn up useful hits. This patch drops our use of dir.c's gitlink-detection, but we do still avoid ".git". That makes us more like tools such as "ack" or "ag", which also know to avoid cruft in .git. As a bonus, this also drops our usage of the ref code when we are outside of a repository, making the transition to pluggable ref backends cleaner. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/builtin/grep.c b/builtin/grep.c index aa7435f..111b6f6 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -522,12 +522,14 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, } static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec, - int exc_std) + int exc_std, int use_index) { struct dir_struct dir; int i, hit = 0; memset(&dir, 0, sizeof(dir)); + if (!use_index) + dir.flags |= DIR_NO_GITLINKS; if (exc_std) setup_standard_excludes(&dir); @@ -902,7 +904,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude; if (list.nr) die(_("--no-index or --untracked cannot be used with revs.")); - hit = grep_directory(&opt, &pathspec, use_exclude); + hit = grep_directory(&opt, &pathspec, use_exclude, use_index); } else if (0 <= opt_exclude) { die(_("--[no-]exclude-standard cannot be used for tracked contents.")); } else if (!list.nr) { diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index b540944..1e72971 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -905,6 +905,33 @@ test_expect_success 'inside git repository but with --no-index' ' ) ' +test_expect_success 'grep --no-index descends into repos, but not .git' ' + rm -fr non && + mkdir -p non/git && + ( + GIT_CEILING_DIRECTORIES="$(pwd)/non" && + export GIT_CEILING_DIRECTORIES && + cd non/git && + + echo magic >file && + git init repo && + ( + cd repo && + echo magic >file && + git add file && + git commit -m foo && + echo magic >.git/file + ) && + + cat >expect <<-\EOF && + file + repo/file + EOF + git grep -l --no-index magic >actual && + test_cmp expect actual + ) +' + test_expect_success 'setup double-dash tests' ' cat >double-dash < Date: Sat, 5 Mar 2016 17:16:50 -0500 Subject: use setup_git_directory() in test-* programs Some of the test-* programs rely on examining refs, but did not bother to make sure we are actually in a git repository. Let's have them call setup_git_directory() to do so. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/test-match-trees.c b/test-match-trees.c index 109f03e..4dad709 100644 --- a/test-match-trees.c +++ b/test-match-trees.c @@ -6,6 +6,8 @@ int main(int ac, char **av) unsigned char hash1[20], hash2[20], shifted[20]; struct tree *one, *two; + setup_git_directory(); + if (get_sha1(av[1], hash1)) die("cannot parse %s as an object name", av[1]); if (get_sha1(av[2], hash2)) diff --git a/test-revision-walking.c b/test-revision-walking.c index 285f06b..3d03133 100644 --- a/test-revision-walking.c +++ b/test-revision-walking.c @@ -50,6 +50,8 @@ int main(int argc, char **argv) if (argc < 2) return 1; + setup_git_directory(); + if (!strcmp(argv[1], "run-twice")) { printf("1st\n"); if (!run_revision_walk()) -- cgit v0.10.2-6-g49f6