Skip to content

Commit d845d72

Browse files
committed
Merge branch 'jk/setup-sequence-update'
There were numerous corner cases in which the configuration files are read and used or not read at all depending on the directory a Git command was run, leading to inconsistent behaviour. The code to set-up repository access at the beginning of a Git process has been updated to fix them. * jk/setup-sequence-update: t1007: factor out repeated setup init: reset cached config when entering new repo init: expand comments explaining config trickery config: only read .git/config from configured repos test-config: setup git directory t1302: use "git -C" pager: handle early config pager: use callbacks instead of configset pager: make pager_program a file-local static pager: stop loading git_default_config() pager: remove obsolete comment diff: always try to set up the repository diff: handle --no-index prefixes consistently diff: skip implicit no-index check when given --no-index patch-id: use RUN_SETUP_GENTLY hash-object: always try to set up the git repository
2 parents ac8ddd7 + 4d0efa1 commit d845d72

16 files changed

+268
-99
lines changed

builtin/diff.c

+14-13
Original file line numberDiff line numberDiff line change
@@ -301,20 +301,21 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
301301
break;
302302
}
303303

304-
if (!no_index)
305-
prefix = setup_git_directory_gently(&nongit);
304+
prefix = setup_git_directory_gently(&nongit);
306305

307-
/*
308-
* Treat git diff with at least one path outside of the
309-
* repo the same as if the command would have been executed
310-
* outside of a git repository. In this case it behaves
311-
* the same way as "git diff --no-index <a> <b>", which acts
312-
* as a colourful "diff" replacement.
313-
*/
314-
if (nongit || ((argc == i + 2) &&
315-
(!path_inside_repo(prefix, argv[i]) ||
316-
!path_inside_repo(prefix, argv[i + 1]))))
317-
no_index = DIFF_NO_INDEX_IMPLICIT;
306+
if (!no_index) {
307+
/*
308+
* Treat git diff with at least one path outside of the
309+
* repo the same as if the command would have been executed
310+
* outside of a git repository. In this case it behaves
311+
* the same way as "git diff --no-index <a> <b>", which acts
312+
* as a colourful "diff" replacement.
313+
*/
314+
if (nongit || ((argc == i + 2) &&
315+
(!path_inside_repo(prefix, argv[i]) ||
316+
!path_inside_repo(prefix, argv[i + 1]))))
317+
no_index = DIFF_NO_INDEX_IMPLICIT;
318+
}
318319

319320
if (!no_index)
320321
gitmodules_config();

builtin/hash-object.c

+8-5
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
8787
int stdin_paths = 0;
8888
int no_filters = 0;
8989
int literally = 0;
90+
int nongit = 0;
9091
unsigned flags = HASH_FORMAT_CHECK;
9192
const char *vpath = NULL;
9293
const struct option hash_object_options[] = {
@@ -107,12 +108,14 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
107108
argc = parse_options(argc, argv, NULL, hash_object_options,
108109
hash_object_usage, 0);
109110

110-
if (flags & HASH_WRITE_OBJECT) {
111+
if (flags & HASH_WRITE_OBJECT)
111112
prefix = setup_git_directory();
112-
prefix_length = prefix ? strlen(prefix) : 0;
113-
if (vpath && prefix)
114-
vpath = prefix_filename(prefix, prefix_length, vpath);
115-
}
113+
else
114+
prefix = setup_git_directory_gently(&nongit);
115+
116+
prefix_length = prefix ? strlen(prefix) : 0;
117+
if (vpath && prefix)
118+
vpath = prefix_filename(prefix, prefix_length, vpath);
116119

117120
git_config(git_default_config, NULL);
118121

builtin/init-db.c

+13-4
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,25 @@ static int create_default_files(const char *template_path)
185185
/* Just look for `init.templatedir` */
186186
git_config(git_init_db_config, NULL);
187187

188-
/* First copy the templates -- we might have the default
188+
/*
189+
* First copy the templates -- we might have the default
189190
* config file there, in which case we would want to read
190191
* from it after installing.
192+
*
193+
* Before reading that config, we also need to clear out any cached
194+
* values (since we've just potentially changed what's available on
195+
* disk).
191196
*/
192197
copy_templates(template_path);
193-
198+
git_config_clear();
199+
reset_shared_repository();
194200
git_config(git_default_config, NULL);
195-
is_bare_repository_cfg = init_is_bare_repository;
196201

197-
/* reading existing config may have overwrote it */
202+
/*
203+
* We must make sure command-line options continue to override any
204+
* values we might have just re-read from the config.
205+
*/
206+
is_bare_repository_cfg = init_is_bare_repository;
198207
if (init_shared_repository != -1)
199208
set_shared_repository(init_shared_repository);
200209

cache.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,12 @@ static inline enum object_type object_type(unsigned int mode)
453453
*/
454454
extern const char * const local_repo_env[];
455455

456+
/*
457+
* Returns true iff we have a configured git repository (either via
458+
* setup_git_directory, or in the environment via $GIT_DIR).
459+
*/
460+
int have_git_dir(void);
461+
456462
extern int is_bare_repository_cfg;
457463
extern int is_bare_repository(void);
458464
extern int is_inside_git_dir(void);
@@ -665,8 +671,15 @@ extern size_t delta_base_cache_limit;
665671
extern unsigned long big_file_threshold;
666672
extern unsigned long pack_size_limit_cfg;
667673

674+
/*
675+
* Accessors for the core.sharedrepository config which lazy-load the value
676+
* from the config (if not already set). The "reset" function can be
677+
* used to unset "set" or cached value, meaning that the value will be loaded
678+
* fresh from the config file on the next call to get_shared_repository().
679+
*/
668680
void set_shared_repository(int value);
669681
int get_shared_repository(void);
682+
void reset_shared_repository(void);
670683

671684
/*
672685
* Do replace refs need to be checked this run? This variable is
@@ -1813,7 +1826,6 @@ extern void write_file(const char *path, const char *fmt, ...);
18131826

18141827
/* pager.c */
18151828
extern void setup_pager(void);
1816-
extern const char *pager_program;
18171829
extern int pager_in_use(void);
18181830
extern int pager_use_color;
18191831
extern int term_columns(void);

config.c

+1-4
Original file line numberDiff line numberDiff line change
@@ -927,9 +927,6 @@ static int git_default_core_config(const char *var, const char *value)
927927
return 0;
928928
}
929929

930-
if (!strcmp(var, "core.pager"))
931-
return git_config_string(&pager_program, var, value);
932-
933930
if (!strcmp(var, "core.editor"))
934931
return git_config_string(&editor_program, var, value);
935932

@@ -1289,7 +1286,7 @@ static int do_git_config_sequence(config_fn_t fn, void *data)
12891286
int ret = 0;
12901287
char *xdg_config = xdg_config_home("config");
12911288
char *user_config = expand_user_path("~/.gitconfig");
1292-
char *repo_config = git_pathdup("config");
1289+
char *repo_config = have_git_dir() ? git_pathdup("config") : NULL;
12931290

12941291
current_parsing_scope = CONFIG_SCOPE_SYSTEM;
12951292
if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0))

diff-no-index.c

+3
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ void diff_no_index(struct rev_info *revs,
281281

282282
DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
283283

284+
DIFF_OPT_SET(&revs->diffopt, RELATIVE_NAME);
285+
revs->diffopt.prefix = prefix;
286+
284287
revs->max_count = -2;
285288
diff_setup_done(&revs->diffopt);
286289

environment.c

+12-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
4040
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
4141
size_t delta_base_cache_limit = 96 * 1024 * 1024;
4242
unsigned long big_file_threshold = 512 * 1024 * 1024;
43-
const char *pager_program;
4443
int pager_use_color = 1;
4544
const char *editor_program;
4645
const char *askpass_program;
@@ -196,6 +195,13 @@ int is_bare_repository(void)
196195
return is_bare_repository_cfg && !get_git_work_tree();
197196
}
198197

198+
int have_git_dir(void)
199+
{
200+
return startup_info->have_repository
201+
|| git_dir
202+
|| getenv(GIT_DIR_ENVIRONMENT);
203+
}
204+
199205
const char *get_git_dir(void)
200206
{
201207
if (!git_dir)
@@ -345,3 +351,8 @@ int get_shared_repository(void)
345351
}
346352
return the_shared_repository;
347353
}
354+
355+
void reset_shared_repository(void)
356+
{
357+
need_shared_repository_from_config = 1;
358+
}

git.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ static struct cmd_struct commands[] = {
444444
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
445445
{ "pack-redundant", cmd_pack_redundant, RUN_SETUP },
446446
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
447-
{ "patch-id", cmd_patch_id },
447+
{ "patch-id", cmd_patch_id, RUN_SETUP_GENTLY },
448448
{ "pickaxe", cmd_blame, RUN_SETUP },
449449
{ "prune", cmd_prune, RUN_SETUP },
450450
{ "prune-packed", cmd_prune_packed, RUN_SETUP },

pager.c

+73-20
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,8 @@
66
#define DEFAULT_PAGER "less"
77
#endif
88

9-
/*
10-
* This is split up from the rest of git so that we can do
11-
* something different on Windows.
12-
*/
13-
149
static struct child_process pager_process = CHILD_PROCESS_INIT;
10+
static const char *pager_program;
1511

1612
static void wait_for_pager(int in_signal)
1713
{
@@ -40,6 +36,44 @@ static void wait_for_pager_signal(int signo)
4036
raise(signo);
4137
}
4238

39+
static int core_pager_config(const char *var, const char *value, void *data)
40+
{
41+
if (!strcmp(var, "core.pager"))
42+
return git_config_string(&pager_program, var, value);
43+
return 0;
44+
}
45+
46+
static void read_early_config(config_fn_t cb, void *data)
47+
{
48+
git_config_with_options(cb, data, NULL, 1);
49+
50+
/*
51+
* Note that this is a really dirty hack that does the wrong thing in
52+
* many cases. The crux of the problem is that we cannot run
53+
* setup_git_directory() early on in git's setup, so we have no idea if
54+
* we are in a repository or not, and therefore are not sure whether
55+
* and how to read repository-local config.
56+
*
57+
* So if we _aren't_ in a repository (or we are but we would reject its
58+
* core.repositoryformatversion), we'll read whatever is in .git/config
59+
* blindly. Similarly, if we _are_ in a repository, but not at the
60+
* root, we'll fail to find .git/config (because it's really
61+
* ../.git/config, etc). See t7006 for a complete set of failures.
62+
*
63+
* However, we have historically provided this hack because it does
64+
* work some of the time (namely when you are at the top-level of a
65+
* valid repository), and would rarely make things worse (i.e., you do
66+
* not generally have a .git/config file sitting around).
67+
*/
68+
if (!startup_info->have_repository) {
69+
struct git_config_source repo_config;
70+
71+
memset(&repo_config, 0, sizeof(repo_config));
72+
repo_config.file = ".git/config";
73+
git_config_with_options(cb, data, &repo_config, 1);
74+
}
75+
}
76+
4377
const char *git_pager(int stdout_is_tty)
4478
{
4579
const char *pager;
@@ -50,7 +84,7 @@ const char *git_pager(int stdout_is_tty)
5084
pager = getenv("GIT_PAGER");
5185
if (!pager) {
5286
if (!pager_program)
53-
git_config(git_default_config, NULL);
87+
read_early_config(core_pager_config, NULL);
5488
pager = pager_program;
5589
}
5690
if (!pager)
@@ -180,23 +214,42 @@ int decimal_width(uintmax_t number)
180214
return width;
181215
}
182216

183-
/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
184-
int check_pager_config(const char *cmd)
217+
struct pager_command_config_data {
218+
const char *cmd;
219+
int want;
220+
char *value;
221+
};
222+
223+
static int pager_command_config(const char *var, const char *value, void *vdata)
185224
{
186-
int want = -1;
187-
struct strbuf key = STRBUF_INIT;
188-
const char *value = NULL;
189-
strbuf_addf(&key, "pager.%s", cmd);
190-
if (git_config_key_is_valid(key.buf) &&
191-
!git_config_get_value(key.buf, &value)) {
192-
int b = git_config_maybe_bool(key.buf, value);
225+
struct pager_command_config_data *data = vdata;
226+
const char *cmd;
227+
228+
if (skip_prefix(var, "pager.", &cmd) && !strcmp(cmd, data->cmd)) {
229+
int b = git_config_maybe_bool(var, value);
193230
if (b >= 0)
194-
want = b;
231+
data->want = b;
195232
else {
196-
want = 1;
197-
pager_program = xstrdup(value);
233+
data->want = 1;
234+
data->value = xstrdup(value);
198235
}
199236
}
200-
strbuf_release(&key);
201-
return want;
237+
238+
return 0;
239+
}
240+
241+
/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
242+
int check_pager_config(const char *cmd)
243+
{
244+
struct pager_command_config_data data;
245+
246+
data.cmd = cmd;
247+
data.want = -1;
248+
data.value = NULL;
249+
250+
read_early_config(pager_command_config, &data);
251+
252+
if (data.value)
253+
pager_program = data.value;
254+
return data.want;
202255
}

t/helper/test-config.c

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ int cmd_main(int argc, const char **argv)
7272
const char *v;
7373
const struct string_list *strptr;
7474
struct config_set cs;
75+
76+
setup_git_directory();
77+
7578
git_configset_init(&cs);
7679

7780
if (argc < 2) {

t/t0001-init.sh

+9
Original file line numberDiff line numberDiff line change
@@ -384,4 +384,13 @@ test_expect_success MINGW 'bare git dir not hidden' '
384384
! is_hidden newdir
385385
'
386386

387+
test_expect_success 'remote init from does not use config from cwd' '
388+
rm -rf newdir &&
389+
test_config core.logallrefupdates true &&
390+
git init newdir &&
391+
echo true >expect &&
392+
git -C newdir config --bool core.logallrefupdates >actual &&
393+
test_cmp expect actual
394+
'
395+
387396
test_done

0 commit comments

Comments
 (0)