From 0e94ee9415e6cf6952b755347b57319e93356210 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:23:17 -0700 Subject: hash-object: always try to set up the git repository When "hash-object" is run without "-w", we don't need to be in a git repository at all; we can just hash the object and write its sha1 to stdout. However, if we _are_ in a git repository, we would want to know that so we can follow the normal rules for respecting config, .gitattributes, etc. This happens to work at the top-level of a git repository because we blindly read ".git/config", but as the included test shows, it does not work when you are in a subdirectory. The solution is to just do a "gentle" setup in this case. We already take care to use prefix_filename() on any filename arguments we get (to handle the "-w" case), so we don't need to do anything extra to handle the side effects of repo setup. An alternative would be to specify RUN_SETUP_GENTLY for this command in git.c, and then die if "-w" is set but we are not in a repository. However, the error messages generated at the time of setup_git_directory() are more detailed, so it's better to find out which mode we are in, and then call the appropriate function. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/hash-object.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'builtin') diff --git a/builtin/hash-object.c b/builtin/hash-object.c index f7d3567dd0..9028e1fdcc 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -87,6 +87,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) int stdin_paths = 0; int no_filters = 0; int literally = 0; + int nongit = 0; unsigned flags = HASH_FORMAT_CHECK; const char *vpath = NULL; const struct option hash_object_options[] = { @@ -107,12 +108,14 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, NULL, hash_object_options, hash_object_usage, 0); - if (flags & HASH_WRITE_OBJECT) { + if (flags & HASH_WRITE_OBJECT) prefix = setup_git_directory(); - prefix_length = prefix ? strlen(prefix) : 0; - if (vpath && prefix) - vpath = prefix_filename(prefix, prefix_length, vpath); - } + else + prefix = setup_git_directory_gently(&nongit); + + prefix_length = prefix ? strlen(prefix) : 0; + if (vpath && prefix) + vpath = prefix_filename(prefix, prefix_length, vpath); git_config(git_default_config, NULL); -- cgit v1.2.3 From 475b362c2a326ddc9987ee0ff6448e795f009d5d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:23:27 -0700 Subject: diff: skip implicit no-index check when given --no-index We can invoke no-index mode in two ways: by an explicit request from the user, or implicitly by noticing that we have two paths, and at least one is outside the repository. If the user already told us --no-index, there is no need for us to do the implicit test at all. However, we currently do, and downgrade our "explicit" to DIFF_NO_INDEX_IMPLICIT. This doesn't have any user-visible behavior, though it's not immediately obvious why. We only trigger the implicit check when we have exactly two non-option arguments. And the only code that cares about implicit versus explicit is an error message that we show when we _don't_ have two non-option arguments. However, it's worth fixing anyway. Besides being slightly more efficient, it makes the code easier to follow, which will help when we modify it in future patches. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/diff.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'builtin') diff --git a/builtin/diff.c b/builtin/diff.c index d6b8f9834d..7b2a7448ed 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -301,20 +301,21 @@ int cmd_diff(int argc, const char **argv, const char *prefix) break; } - if (!no_index) + if (!no_index) { prefix = setup_git_directory_gently(&nongit); - /* - * Treat git diff with at least one path outside of the - * repo the same as if the command would have been executed - * outside of a git repository. In this case it behaves - * the same way as "git diff --no-index ", which acts - * as a colourful "diff" replacement. - */ - if (nongit || ((argc == i + 2) && - (!path_inside_repo(prefix, argv[i]) || - !path_inside_repo(prefix, argv[i + 1])))) - no_index = DIFF_NO_INDEX_IMPLICIT; + /* + * Treat git diff with at least one path outside of the + * repo the same as if the command would have been executed + * outside of a git repository. In this case it behaves + * the same way as "git diff --no-index ", which acts + * as a colourful "diff" replacement. + */ + if (nongit || ((argc == i + 2) && + (!path_inside_repo(prefix, argv[i]) || + !path_inside_repo(prefix, argv[i + 1])))) + no_index = DIFF_NO_INDEX_IMPLICIT; + } if (!no_index) gitmodules_config(); -- cgit v1.2.3 From 28a4e580218b79dd5a7d55c2a30431469129321d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:23:36 -0700 Subject: diff: always try to set up the repository If we see an explicit "--no-index", we do not bother calling setup_git_directory_gently() at all. This means that we may miss out on reading repo-specific config. It's arguable whether this is correct or not. If we were designing from scratch, making "git diff --no-index" completely ignore the repository makes some sense. But we are nowhere near scratch, so let's look at the existing behavior: 1. If you're in the top-level of a repository and run an explicit "diff --no-index", the config subsystem falls back to reading ".git/config", and we will respect repo config. 2. If you're in a subdirectory of a repository, then we still try to read ".git/config", but it generally doesn't exist. So "diff --no-index" there does not respect repo config. 3. If you have $GIT_DIR set in the environment, we read and respect $GIT_DIR/config, 4. If you run "git diff /tmp/foo /tmp/bar" to get an implicit no-index, we _do_ run the repository setup, and set $GIT_DIR (or respect an existing $GIT_DIR variable). We find the repo config no matter where we started, and respect it. So we already respect the repository config in a number of common cases, and case (2) is the only one that does not. And at least one of our tests, t4034, depends on case (1) behaving as it does now (though it is just incidental, not an explicit test for this behavior). So let's bring case (2) in line with the others by always running the repository setup, even with an explicit "--no-index". We shouldn't need to change anything else, as the implicit case already handles the prefix. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/diff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'builtin') diff --git a/builtin/diff.c b/builtin/diff.c index 7b2a7448ed..7be7806146 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -301,9 +301,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix) break; } - if (!no_index) { - prefix = setup_git_directory_gently(&nongit); + prefix = setup_git_directory_gently(&nongit); + if (!no_index) { /* * Treat git diff with at least one path outside of the * repo the same as if the command would have been executed -- cgit v1.2.3 From 7c0a842b46391230661d17ad758efa6b4eccdb93 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:24:19 -0700 Subject: init: expand comments explaining config trickery git-init may copy "config" from the templates directory and then re-read it. There are some comments explaining what's going on here, but they are not grouped very well with the matching code. Let's rearrange and expand them. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/init-db.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'builtin') diff --git a/builtin/init-db.c b/builtin/init-db.c index b2d8d40a67..0b0557138d 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -191,16 +191,19 @@ static int create_default_files(const char *template_path) /* Just look for `init.templatedir` */ git_config(git_init_db_config, NULL); - /* First copy the templates -- we might have the default + /* + * First copy the templates -- we might have the default * config file there, in which case we would want to read * from it after installing. */ copy_templates(template_path); - git_config(git_default_config, NULL); - is_bare_repository_cfg = init_is_bare_repository; - /* reading existing config may have overwrote it */ + /* + * We must make sure command-line options continue to override any + * values we might have just re-read from the config. + */ + is_bare_repository_cfg = init_is_bare_repository; if (init_shared_repository != -1) set_shared_repository(init_shared_repository); -- cgit v1.2.3 From 4543926ba8f8ec596dd4e45f206f4fbc29350567 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:24:23 -0700 Subject: init: reset cached config when entering new repo After we copy the templates into place, we re-read the config in case we copied in a default config file. But since git_config() is backed by a cache these days, it's possible that the call will not actually touch the filesystem at all; we need to tell it that something has changed behind the scenes. Note that we also need to reset the shared_repository config. At first glance, it seems like this should probably just be folded into git_config_clear(). But unfortunately that is not quite right. The shared repository value may come from config, _or_ it may have been set manually. So only the caller who knows whether or not they set it is the one who can clear it (and indeed, if you _do_ put it into git_config_clear(), then many tests fail, as we have to clear the config cache any time we set a new config variable). There are three tests here. The first two actually pass already, though it's largely luck: they just don't happen to actually read any config before we enter the new repo. But the third one does fail without this patch; we look at core.sharedrepository while creating the directory, but need to make sure the value from the template config overrides it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/init-db.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'builtin') diff --git a/builtin/init-db.c b/builtin/init-db.c index 0b0557138d..cc09fca81b 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -195,8 +195,14 @@ static int create_default_files(const char *template_path) * First copy the templates -- we might have the default * config file there, in which case we would want to read * from it after installing. + * + * Before reading that config, we also need to clear out any cached + * values (since we've just potentially changed what's available on + * disk). */ copy_templates(template_path); + git_config_clear(); + reset_shared_repository(); git_config(git_default_config, NULL); /* -- cgit v1.2.3