git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Johannes Schindelin <johannes.schindelin@gmx.de>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>, Jeff King <peff@peff.net>,
	Duy Nguyen <pclouds@gmail.com>
Subject: [PATCH v3 0/9] Fix the early config
Date: Fri, 3 Mar 2017 18:31:55 +0100 (CET)	[thread overview]
Message-ID: <cover.1488562287.git.johannes.schindelin@gmx.de> (raw)
In-Reply-To: <cover.1488506615.git.johannes.schindelin@gmx.de>

These patches are an attempt to make Git's startup sequence a bit less
surprising.

The idea here is to discover the .git/ directory gently (i.e. without
changing the current working directory, or global variables), and to use
it to read the .git/config file early, before we actually called
setup_git_directory() (if we ever do that).

This also allows us to fix the early config e.g. to determine the pager
or to resolve aliases in a non-surprising manner.

My dirty little secret is that I need to discover the Git directory
early, without changing global state, for usage statistics gathering in
the GVFS Git project, so I actually do not care all that much about the
early config, although it is a welcome fallout (and a good reason for
accepting these patches and thereby releasing me of more maintenance
burden :-)).

Notable notes:

- In contrast to earlier versions, I no longer special-case init and
  clone. Peff pointed out that this adds technical debt, and that we can
  actually argue (for consistency's sake) that early config reads the
  current repository config (if any) even for init and clone.

- The read_early_config() function does not cache Git directory
  discovery nor read values. If needed, this can be implemented later,
  in a separate patch series.

- The alias handling in git.c could possibly benefit from this work, but
  again, this is a separate topic from the current patch series.

Changes since v2:

- replaced `test -e` by `test_path_is_file`

- fixed premature "cwd -> dir" in 2/9

- the setup_git_directory_gently_1() function is no longer renamed
  because it is not exported directly, anyway

- fixed the way setup_discovered_git_dir() expected the offset parameter
  to exclude the trailing slash (which is not true for root
  directories); also verified that setup_bare_git_dir() does not require
  a corresponding patch

- switched to using size_t instead of int to save the length of the
  strbuf in discover_git_directory()

- ensured that discover_git_directory() turns a relative gitdir into an
  absolute one even if there is already some text in the strbuf

- clarified under which circumstances we turn a relative gitdir into an
  absolute one

- avoided absolute gitdir with trailing "/." to be returned

- the commit that fixes the "really dirty hack" now rewords that comment
  to reflect that it is no longer a really dirty hack

- dropped the special-casing of init and clone

- the discover_git_directory() function now correctly checks the
  repository version, warning (and returning NULL) in case of a problem


Johannes Schindelin (9):
  t7006: replace dubious test
  setup_git_directory(): use is_dir_sep() helper
  Prepare setup_discovered_git_directory() the root directory
  setup_git_directory_1(): avoid changing global state
  Export the discover_git_directory() function
  Make read_early_config() reusable
  read_early_config(): avoid .git/config hack when unneeded
  read_early_config(): really discover .git/
  Test read_early_config()

 cache.h                 |   3 +
 config.c                |  27 ++++++
 pager.c                 |  31 -------
 setup.c                 | 237 ++++++++++++++++++++++++++++++++----------------
 t/helper/test-config.c  |  15 +++
 t/t1309-early-config.sh |  50 ++++++++++
 t/t7006-pager.sh        |  18 +++-
 7 files changed, 269 insertions(+), 112 deletions(-)
 create mode 100755 t/t1309-early-config.sh


base-commit: 3bc53220cb2dcf709f7a027a3f526befd021d858
Published-As: https://github.com/dscho/git/releases/tag/early-config-v3
Fetch-It-Via: git fetch https://github.com/dscho/git early-config-v3

Interdiff vs v2:

 diff --git a/cache.h b/cache.h
 index 0af7141242f..8a4580f921d 100644
 --- a/cache.h
 +++ b/cache.h
 @@ -518,6 +518,7 @@ extern void set_git_work_tree(const char *tree);
  #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
  
  extern void setup_work_tree(void);
 +/* Find GIT_DIR without changing the working directory or other global state */
  extern const char *discover_git_directory(struct strbuf *gitdir);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
 @@ -2070,7 +2071,7 @@ const char *split_cmdline_strerror(int cmdline_errno);
  
  /* setup.c */
  struct startup_info {
 -	int have_repository, creating_repository;
 +	int have_repository;
  	const char *prefix;
  };
  extern struct startup_info *startup_info;
 diff --git a/config.c b/config.c
 index bcda397d42e..749623a9649 100644
 --- a/config.c
 +++ b/config.c
 @@ -1419,25 +1419,16 @@ void read_early_config(config_fn_t cb, void *data)
  	git_config_with_options(cb, data, NULL, 1);
  
  	/*
 -	 * Note that this is a really dirty hack that does the wrong thing in
 -	 * many cases. The crux of the problem is that we cannot run
 -	 * setup_git_directory() early on in git's setup, so we have no idea if
 -	 * we are in a repository or not, and therefore are not sure whether
 -	 * and how to read repository-local config.
 -	 *
 -	 * So if we _aren't_ in a repository (or we are but we would reject its
 -	 * core.repositoryformatversion), we'll read whatever is in .git/config
 -	 * blindly. Similarly, if we _are_ in a repository, but not at the
 -	 * root, we'll fail to find .git/config (because it's really
 -	 * ../.git/config, etc). See t7006 for a complete set of failures.
 -	 *
 -	 * However, we have historically provided this hack because it does
 -	 * work some of the time (namely when you are at the top-level of a
 -	 * valid repository), and would rarely make things worse (i.e., you do
 -	 * not generally have a .git/config file sitting around).
 +	 * When we are not about to create a repository ourselves (init or
 +	 * clone) and when no .git/ directory was set up yet (in which case
 +	 * git_config_with_options() would already have picked up the
 +	 * repository config), we ask discover_git_directory() to figure out
 +	 * whether there is any repository config we should use (but unlike
 +	 * setup_git_directory_gently(), no global state is changed, most
 +	 * notably, the current working directory is still the same after
 +	 * the call).
  	 */
 -	if (!startup_info->creating_repository && !have_git_dir() &&
 -	    discover_git_directory(&buf)) {
 +	if (!have_git_dir() && discover_git_directory(&buf)) {
  		struct git_config_source repo_config;
  
  		memset(&repo_config, 0, sizeof(repo_config));
 diff --git a/git.c b/git.c
 index 9fb9bb90a21..33f52acbcc8 100644
 --- a/git.c
 +++ b/git.c
 @@ -337,9 +337,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
  	struct stat st;
  	const char *prefix;
  
 -	if (p->fn == cmd_init_db || p->fn == cmd_clone)
 -		startup_info->creating_repository = 1;
 -
  	prefix = NULL;
  	help = argc == 2 && !strcmp(argv[1], "-h");
  	if (!help) {
 diff --git a/setup.c b/setup.c
 index 7ceca6cc6ef..5320ae37314 100644
 --- a/setup.c
 +++ b/setup.c
 @@ -721,8 +721,10 @@ static const char *setup_discovered_git_dir(const char *gitdir,
  	if (offset == cwd->len)
  		return NULL;
  
 -	/* Make "offset" point to past the '/', and add a '/' at the end */
 -	offset++;
 +	/* Make "offset" point past the '/' (already the case for root dirs) */
 +	if (offset != offset_1st_component(cwd->buf))
 +		offset++;
 +	/* Add a '/' at the end */
  	strbuf_addch(cwd, '/');
  	return cwd->buf + offset;
  }
 @@ -839,8 +841,8 @@ enum discovery_result {
   * the discovered .git/ directory, if any. This path may be relative against
   * `dir` (i.e. *not* necessarily the cwd).
   */
 -static enum discovery_result discover_git_directory_1(struct strbuf *dir,
 -						      struct strbuf *gitdir)
 +static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
 +							  struct strbuf *gitdir)
  {
  	const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
  	struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
 @@ -923,24 +925,44 @@ static enum discovery_result discover_git_directory_1(struct strbuf *dir,
  
  const char *discover_git_directory(struct strbuf *gitdir)
  {
 -	struct strbuf dir = STRBUF_INIT;
 -	int len;
 +	struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
 +	size_t gitdir_offset = gitdir->len, cwd_len;
 +	struct repository_format candidate;
  
  	if (strbuf_getcwd(&dir))
  		return NULL;
  
 -	len = dir.len;
 -	if (discover_git_directory_1(&dir, gitdir) < 0) {
 +	cwd_len = dir.len;
 +	if (setup_git_directory_gently_1(&dir, gitdir) < 0) {
  		strbuf_release(&dir);
  		return NULL;
  	}
  
 -	if (dir.len < len && !is_absolute_path(gitdir->buf)) {
 -		strbuf_addch(&dir, '/');
 -		strbuf_insert(gitdir, 0, dir.buf, dir.len);
 +	/*
 +	 * The returned gitdir is relative to dir, and if dir does not reflect
 +	 * the current working directory, we simply make the gitdir absolute.
 +	 */
 +	if (dir.len < cwd_len && !is_absolute_path(gitdir->buf + gitdir_offset)) {
 +		/* Avoid a trailing "/." */
 +		if (!strcmp(".", gitdir->buf + gitdir_offset))
 +			strbuf_setlen(gitdir, gitdir_offset);
 +		else
 +			strbuf_addch(&dir, '/');
 +		strbuf_insert(gitdir, gitdir_offset, dir.buf, dir.len);
  	}
 +
 +	strbuf_reset(&dir);
 +	strbuf_addf(&dir, "%s/config", gitdir->buf + gitdir_offset);
 +	read_repository_format(&candidate, dir.buf);
  	strbuf_release(&dir);
  
 +	if (verify_repository_format(&candidate, &err) < 0) {
 +		warning("ignoring git dir '%s': %s",
 +			gitdir->buf + gitdir_offset, err.buf);
 +		strbuf_release(&err);
 +		return NULL;
 +	}
 +
  	return gitdir->buf;
  }
  
 @@ -970,7 +992,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
  		die_errno(_("Unable to read current working directory"));
  	strbuf_addbuf(&dir, &cwd);
  
 -	switch (discover_git_directory_1(&dir, &gitdir)) {
 +	switch (setup_git_directory_gently_1(&dir, &gitdir)) {
  	case GIT_DIR_NONE:
  		prefix = NULL;
  		break;
 @@ -1000,7 +1022,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
  		      "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."),
  		    dir.buf);
  	default:
 -		die("BUG: unhandled discover_git_directory() result");
 +		die("BUG: unhandled setup_git_directory_1() result");
  	}
  
  	if (prefix)
 diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
 index bf89340988b..4f3794d415e 100755
 --- a/t/t7006-pager.sh
 +++ b/t/t7006-pager.sh
 @@ -387,7 +387,7 @@ test_expect_success TTY 'core.pager in repo config works and retains cwd' '
  		cd sub &&
  		rm -f cwd-retained &&
  		test_terminal git -p rev-parse HEAD &&
 -		test -e cwd-retained
 +		test_path_is_file cwd-retained
  	)
  '
  

-- 
2.12.0.windows.1.7.g94dafc3b124


  parent reply	other threads:[~2017-03-03 17:32 UTC|newest]

Thread overview: 123+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-08 15:35 [PATCH/RFC 0/7] Pie-in-the-sky attempt to fix the early config Johannes Schindelin
2016-12-08 15:36 ` [PATCH/RFC 1/7] Make read_early_config() reusable Johannes Schindelin
2016-12-08 15:36 ` [PATCH/RFC 2/7] read_early_config(): avoid .git/config hack when unneeded Johannes Schindelin
2016-12-08 15:36 ` [PATCH/RFC 3/7] Mark builtins that create .git/ directories Johannes Schindelin
2016-12-08 15:36 ` [PATCH/RFC 4/7] read_early_config(): special-case `init` and `clone` Johannes Schindelin
2016-12-08 15:36 ` [PATCH/RFC 5/7] read_early_config(): really discover .git/ Johannes Schindelin
2016-12-08 15:36 ` [PATCH/RFC 6/7] WIP read_config_early(): respect ceiling directories Johannes Schindelin
2016-12-08 15:36 ` [PATCH/RFC 7/7] WIP: read_early_config(): add tests Johannes Schindelin
2016-12-08 17:26 ` [PATCH/RFC 0/7] Pie-in-the-sky attempt to fix the early config Jeff King
2016-12-09 17:28   ` Johannes Schindelin
2016-12-09 17:55     ` Jeff King
2016-12-09 12:42 ` Duy Nguyen
2016-12-09 16:52   ` Johannes Schindelin
2017-03-03  2:03 ` [PATCH v2 0/9] Fix " Johannes Schindelin
2017-03-03  2:04   ` [PATCH v2 1/9] t7006: replace dubious test Johannes Schindelin
2017-03-03  3:36     ` Jeff King
2017-03-03 11:10       ` Johannes Schindelin
2017-03-03  2:04   ` [PATCH v2 2/9] setup_git_directory(): use is_dir_sep() helper Johannes Schindelin
2017-03-03  3:37     ` Jeff King
2017-03-03 11:16       ` Johannes Schindelin
2017-03-03 11:26         ` Jeff King
2017-03-03 15:35           ` Johannes Schindelin
2017-03-03  2:04   ` [PATCH v2 3/9] setup_git_directory(): avoid changing global state during discovery Johannes Schindelin
2017-03-03  4:24     ` Jeff King
2017-03-03 13:54       ` Johannes Schindelin
2017-03-03  2:04   ` [PATCH v2 4/9] Export the discover_git_directory() function Johannes Schindelin
2017-03-03  4:45     ` Jeff King
2017-03-03 14:49       ` Johannes Schindelin
2017-03-03  2:04   ` [PATCH v2 5/9] Make read_early_config() reusable Johannes Schindelin
2017-03-03  4:46     ` Jeff King
2017-03-03 14:11       ` Johannes Schindelin
2017-03-03  2:04   ` [PATCH v2 6/9] read_early_config(): special-case builtins that create a repository Johannes Schindelin
2017-03-03  4:51     ` Jeff King
2017-03-03 15:11       ` Johannes Schindelin
2017-03-03  2:04   ` [PATCH v2 7/9] read_early_config(): avoid .git/config hack when unneeded Johannes Schindelin
2017-03-03  4:51     ` Jeff King
2017-03-03  2:04   ` [PATCH v2 8/9] read_early_config(): really discover .git/ Johannes Schindelin
2017-03-03  5:06     ` Jeff King
2017-03-03 15:26       ` Johannes Schindelin
2017-03-03  2:04   ` [PATCH v2 9/9] Test read_early_config() Johannes Schindelin
2017-03-03  5:07     ` Jeff King
2017-03-03 15:04       ` Johannes Schindelin
2017-03-03  5:14   ` [PATCH v2 0/9] Fix the early config Jeff King
2017-03-03 15:31     ` Johannes Schindelin
2017-03-03 17:31   ` Johannes Schindelin [this message]
2017-03-03 17:32     ` [PATCH v3 1/9] t7006: replace dubious test Johannes Schindelin
2017-03-03 17:32     ` [PATCH v3 2/9] setup_git_directory(): use is_dir_sep() helper Johannes Schindelin
2017-03-03 17:32     ` [PATCH v3 3/9] Prepare setup_discovered_git_directory() the root directory Johannes Schindelin
2017-03-03 17:32     ` [PATCH v3 4/9] setup_git_directory_1(): avoid changing global state Johannes Schindelin
2017-03-03 17:33     ` [PATCH v3 5/9] Export the discover_git_directory() function Johannes Schindelin
2017-03-03 17:33     ` [PATCH v3 6/9] Make read_early_config() reusable Johannes Schindelin
2017-03-03 17:33     ` [PATCH v3 7/9] read_early_config(): avoid .git/config hack when unneeded Johannes Schindelin
2017-03-03 17:33     ` [PATCH v3 8/9] read_early_config(): really discover .git/ Johannes Schindelin
2017-03-03 17:33     ` [PATCH v3 9/9] Test read_early_config() Johannes Schindelin
2017-03-03 21:35     ` [PATCH v3 0/9] Fix the early config Junio C Hamano
2017-03-07 11:55       ` Johannes Schindelin
2017-03-07 15:18       ` Johannes Schindelin
2017-03-04  7:39     ` Jeff King
2017-03-05  3:36       ` Junio C Hamano
2017-03-07 14:31       ` Johannes Schindelin
2017-03-08  7:30         ` Jeff King
2017-03-08 16:18           ` Johannes Schindelin
2017-03-08 16:29             ` Jeff King
2017-03-08 17:09           ` Junio C Hamano
2017-03-08 17:42             ` Jeff King
2017-03-08 22:43               ` Junio C Hamano
2017-03-09 11:51                 ` Johannes Schindelin
2017-03-09 12:16                   ` Jeff King
2017-03-10 16:39                     ` Junio C Hamano
2017-03-07 14:32     ` [PATCH v4 00/10] " Johannes Schindelin
2017-03-07 14:32       ` [PATCH v4 01/10] t7006: replace dubious test Johannes Schindelin
2017-03-07 14:32       ` [PATCH v4 02/10] setup_git_directory(): use is_dir_sep() helper Johannes Schindelin
2017-03-07 14:32       ` [PATCH v4 03/10] Prepare setup_discovered_git_directory() the root directory Johannes Schindelin
2017-03-07 14:32       ` [PATCH v4 04/10] setup_git_directory_1(): avoid changing global state Johannes Schindelin
2017-03-07 23:24         ` Junio C Hamano
2017-03-07 23:35         ` Brandon Williams
2017-03-08  0:57           ` Johannes Schindelin
2017-03-08  2:10             ` Brandon Williams
2017-03-07 14:33       ` [PATCH v4 05/10] Introduce the discover_git_directory() function Johannes Schindelin
2017-03-07 14:33       ` [PATCH v4 06/10] Make read_early_config() reusable Johannes Schindelin
2017-03-07 14:33       ` [PATCH v4 07/10] read_early_config(): avoid .git/config hack when unneeded Johannes Schindelin
2017-03-07 14:33       ` [PATCH v4 08/10] read_early_config(): really discover .git/ Johannes Schindelin
2017-03-07 14:33       ` [PATCH v4 09/10] Test read_early_config() Johannes Schindelin
2017-03-07 14:33       ` [PATCH v4 10/10] setup_git_directory_gently_1(): avoid die()ing Johannes Schindelin
2017-03-09 22:23       ` [PATCH v5 00/11] Fix the early config Johannes Schindelin
2017-03-09 22:23         ` [PATCH v5 01/11] t7006: replace dubious test Johannes Schindelin
2017-03-09 22:23         ` [PATCH v5 02/11] setup_git_directory(): use is_dir_sep() helper Johannes Schindelin
2017-03-09 22:23         ` [PATCH v5 03/11] Prepare setup_discovered_git_directory() the root directory Johannes Schindelin
2017-03-09 22:24         ` [PATCH v5 04/11] setup_git_directory_1(): avoid changing global state Johannes Schindelin
2017-03-10 19:34           ` Junio C Hamano
2017-03-09 22:24         ` [PATCH v5 05/11] Introduce the discover_git_directory() function Johannes Schindelin
2017-03-09 22:24         ` [PATCH v5 06/11] Make read_early_config() reusable Johannes Schindelin
2017-03-09 22:24         ` [PATCH v5 07/11] read_early_config(): avoid .git/config hack when unneeded Johannes Schindelin
2017-03-09 22:25         ` [PATCH v5 08/11] read_early_config(): really discover .git/ Johannes Schindelin
2017-03-09 22:25         ` [PATCH v5 09/11] Test read_early_config() Johannes Schindelin
2017-03-10 19:02           ` Junio C Hamano
2017-03-13 17:19             ` Johannes Schindelin
2017-03-13 17:32               ` Junio C Hamano
2017-03-09 22:25         ` [PATCH v5 10/11] setup_git_directory_gently_1(): avoid die()ing Johannes Schindelin
2017-03-10 18:58           ` Junio C Hamano
2017-03-13 19:38             ` Johannes Schindelin
2017-03-13 19:47               ` Junio C Hamano
2017-03-13 20:20                 ` Junio C Hamano
2017-03-13 21:46                   ` Johannes Schindelin
2017-03-13 23:31                     ` Junio C Hamano
2017-03-09 22:25         ` [PATCH v5 11/11] t1309: document cases where we would want early config not to die() Johannes Schindelin
2017-03-13 20:09         ` [PATCH v6 00/12] Fix the early config Johannes Schindelin
2017-03-13 20:09           ` [PATCH v6 01/12] t7006: replace dubious test Johannes Schindelin
2017-03-13 20:09           ` [PATCH v6 02/12] setup_git_directory(): use is_dir_sep() helper Johannes Schindelin
2017-03-13 20:09           ` [PATCH v6 03/12] Prepare setup_discovered_git_directory() the root directory Johannes Schindelin
2017-03-13 20:34             ` Junio C Hamano
2017-03-13 21:44               ` Johannes Schindelin
2017-03-13 20:10           ` [PATCH v6 04/12] setup_git_directory_1(): avoid changing global state Johannes Schindelin
2017-03-13 20:10           ` [PATCH v6 05/12] Introduce the discover_git_directory() function Johannes Schindelin
2017-03-13 20:11           ` [PATCH v6 06/12] Make read_early_config() reusable Johannes Schindelin
2017-03-13 20:11           ` [PATCH v6 07/12] read_early_config(): avoid .git/config hack when unneeded Johannes Schindelin
2017-03-13 20:11           ` [PATCH v6 08/12] read_early_config(): really discover .git/ Johannes Schindelin
2017-03-13 20:11           ` [PATCH v6 09/12] Add t1309 to test read_early_config() Johannes Schindelin
2017-03-13 20:11           ` [PATCH v6 10/12] setup_git_directory_gently_1(): avoid die()ing Johannes Schindelin
2017-03-13 20:11           ` [PATCH v6 11/12] t1309: document cases where we would want early config not to die() Johannes Schindelin
2017-03-13 20:12           ` [PATCH v6 12/12] setup.c: mention unresolved problems Johannes Schindelin
2017-03-13 22:31           ` [PATCH v6 00/12] Fix the early config Junio C Hamano
2017-03-14 18:01             ` Jeff King

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cover.1488562287.git.johannes.schindelin@gmx.de \
    --to=johannes.schindelin@gmx.de \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=pclouds@gmail.com \
    --cc=peff@peff.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).