git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Stefan Beller <sbeller@google.com>
To: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Cc: "git@vger.kernel.org" <git@vger.kernel.org>,
	Max Kirillov <max@max630.net>, Junio C Hamano <gitster@pobox.com>,
	Michael J Gruber <git@drmicha.warpmail.net>,
	Jens Lehmann <Jens.Lehmann@web.de>,
	Lars Schneider <larsxschneider@gmail.com>,
	Michael Haggerty <mhagger@alum.mit.edu>
Subject: Re: [PATCH v4 1/4] worktree: add per-worktree config files
Date: Mon, 25 Jul 2016 17:59:03 -0700	[thread overview]
Message-ID: <CAGZ79kYET=z-b+U-JN+H5jkRTGHR0oMdTfUZPMRJx50aH-idbw@mail.gmail.com> (raw)
In-Reply-To: <20160720172419.25473-2-pclouds@gmail.com>

On Wed, Jul 20, 2016 at 10:24 AM, Nguyễn Thái Ngọc Duy
<pclouds@gmail.com> wrote:
> A new repo extension is added, worktreeConfig. When it is present:
>
>  - Repository config reading by default includes $GIT_DIR/config _and_
>    $GIT_DIR/config.worktree. "config" file remains shared in multiple
>    worktree setup.
>
>  - The special treatment for core.bare and core.worktree, to stay
>    effective only in main worktree, is gone. These config files are
>    supposed to be in config.worktree.
>
> This extension is most useful in multiple worktree setup because you
> now have an option to store per-worktree config (which is either
> .git/config.worktree for main worktree, or
> .git/worktrees/xx/config.worktree for linked ones).
>
> This extension can be used in single worktree mode, even though it's
> pretty much useless (but this can happen after you remove all linked
> worktrees and move back to single worktree).
>
> "git config" reads from both "config" and "config.worktree" by default
> (i.e. without either --user, --file...) when this extension is
> present. Default writes still go to "config", not "config.worktree". A
> new option --worktree is added for that (*).
>
> Since a new repo extension is introduced, existing git binaries should
> refuse to access to the repo (both from main and linked worktrees). So
> they will not misread the config file (i.e. skip the config.worktree
> part). They may still accidentally write to the config file anyway if
> they use with "git config --file <path>".
>
> This design places a bet on the assumption that the majority of config
> variables are shared so it is the default mode. A safer move would be
> default writes go to per-worktree file, so that accidental changes are
> isolated.
>
> (*) "git config --worktree" points back to "config" file when this
>     extension is not present so that it works in any setup.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>

I like the user facing design, but how am I supposed to use it internally?

Say I want to read a value preferably from the worktree I'd do a
    /*
     * maybe I don't even have to set it to 1 as
     * the user is supposed to do that?
     */
    repository_format_worktree_config = 1;
    git_config_get_{string,bool,int} (... as usual ...)

and if I want to read the value globally I would set the variable to 0
and read? (I would need to restore it, so I'll have a temporary variable
to keep the original value of repository_format_worktree_config)

Thanks,
Stefan


> ---
>  Documentation/config.txt               | 11 ++++-
>  Documentation/git-config.txt           | 26 ++++++++----
>  Documentation/git-worktree.txt         | 31 ++++++++++++++
>  Documentation/gitrepository-layout.txt |  8 ++++
>  builtin/config.c                       | 18 +++++++-
>  cache.h                                |  2 +
>  config.c                               |  7 ++++
>  environment.c                          |  1 +
>  setup.c                                |  5 ++-
>  t/t2028-worktree-config.sh (new +x)    | 77 ++++++++++++++++++++++++++++++++++
>  10 files changed, 175 insertions(+), 11 deletions(-)
>  create mode 100755 t/t2028-worktree-config.sh
>
> diff --git a/Documentation/config.txt b/Documentation/config.txt
> index 16dc22d..7d64da0 100644
> --- a/Documentation/config.txt
> +++ b/Documentation/config.txt
> @@ -2,8 +2,9 @@ CONFIGURATION FILE
>  ------------------
>
>  The Git configuration file contains a number of variables that affect
> -the Git commands' behavior. The `.git/config` file in each repository
> -is used to store the configuration for that repository, and
> +the Git commands' behavior. The files `.git/config` and optionally
> +`config.worktree` (see `extensions.worktreeConfig` below) are each
> +repository is used to store the configuration for that repository, and
>  `$HOME/.gitconfig` is used to store a per-user configuration as
>  fallback values for the `.git/config` file. The file `/etc/gitconfig`
>  can be used to store a system-wide default configuration.
> @@ -264,6 +265,12 @@ advice.*::
>                 show directions on how to proceed from the current state.
>  --
>
> +extensions.worktreeConfig::
> +       If set, by default "git config" reads from both "config" and
> +       "config.worktree" file in that order. In multiple working
> +       directory mode, "config" file is shared while
> +       "config.worktree" is per-working directory.
> +
>  core.fileMode::
>         Tells Git if the executable bit of files in the working tree
>         is to be honored.
> diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
> index f163113..9dfdb6a 100644
> --- a/Documentation/git-config.txt
> +++ b/Documentation/git-config.txt
> @@ -47,13 +47,15 @@ checks or transformations are performed on the value.
>
>  When reading, the values are read from the system, global and
>  repository local configuration files by default, and options
> -`--system`, `--global`, `--local` and `--file <filename>` can be
> -used to tell the command to read from only that location (see <<FILES>>).
> +`--system`, `--global`, `--local`, `--worktree` and
> +`--file <filename>` can be used to tell the command to read from only
> +that location (see <<FILES>>).
>
>  When writing, the new value is written to the repository local
>  configuration file by default, and options `--system`, `--global`,
> -`--file <filename>` can be used to tell the command to write to
> -that location (you can say `--local` but that is the default).
> +`--worktree`, `--file <filename>` can be used to tell the command to
> +write to that location (you can say `--local` but that is the
> +default).
>
>  This command will fail with non-zero status upon error.  Some exit
>  codes are:
> @@ -133,6 +135,11 @@ from all available files.
>  +
>  See also <<FILES>>.
>
> +--worktree::
> +       Similar to `--local` except that `.git/config.worktree` is
> +       read from or written to if `extensions.worktreeConfig` is
> +       present. If not it's the same as `--local`.
> +
>  -f config-file::
>  --file config-file::
>         Use the given config file instead of the one specified by GIT_CONFIG.
> @@ -253,6 +260,10 @@ $XDG_CONFIG_HOME/git/config::
>  $GIT_DIR/config::
>         Repository specific configuration file.
>
> +$GIT_DIR/config.worktree::
> +       This is optional and is only searched when
> +       `extensions.worktreeConfig` is present in $GIT_DIR/config.
> +
>  If no further options are given, all reading options will read all of these
>  files that are available. If the global or the system-wide configuration
>  file are not available they will be ignored. If the repository configuration
> @@ -268,9 +279,10 @@ configuration file. Note that this also affects options like `--replace-all`
>  and `--unset`. *'git config' will only ever change one file at a time*.
>
>  You can override these rules either by command-line options or by environment
> -variables. The `--global` and the `--system` options will limit the file used
> -to the global or system-wide file respectively. The `GIT_CONFIG` environment
> -variable has a similar effect, but you can specify any filename you want.
> +variables. The `--global`, `--system` and `--worktree` options will limit
> +the file used to the global, system-wide or per-worktree file respectively.
> +The `GIT_CONFIG` environment variable has a similar effect, but you
> +can specify any filename you want.
>
>
>  ENVIRONMENT
> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> index 7c4cfb0..41350db 100644
> --- a/Documentation/git-worktree.txt
> +++ b/Documentation/git-worktree.txt
> @@ -111,6 +111,37 @@ OPTIONS
>  --expire <time>::
>         With `prune`, only expire unused working trees older than <time>.
>
> +CONFIGURATION FILE
> +------------------
> +By default, the repository "config" file is shared across all working
> +directories. If the config variables `core.bare` or `core.worktree`
> +are already present in the config file, they will be applied to the
> +main working directory only.
> +
> +In order to have configuration specific to working directories, you
> +can turn on "worktreeConfig" extension, e.g.:
> +
> +------------
> +$ git config extensions.worktreeConfig true
> +------------
> +
> +In this mode, specific configuration stays in the path pointed by `git
> +rev-parse --git-path config.worktree`. You can add or update
> +configuration in this file with `git config --worktree`. Git before
> +version XXX will refuse to access repositories with this extension.
> +
> +Note that in this file, the exception for `core.bare` and
> +core.worktree` is gone. If you have them before, you need to move them
> +to the config.worktree of the main working directory. You may also
> +take this opportunity to move other configuration that you do not want
> +to share to all working directories:
> +
> + - `core.worktree` and `core.bare` should never be shared
> +
> + - `core.sparseCheckout` is recommended per working directory, unless
> +   you are sure you always use sparse checkout for all working
> +   directories.
> +
>  DETAILS
>  -------
>  Each linked working tree has a private sub-directory in the repository's
> diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
> index 577ee84..6cfdb4c 100644
> --- a/Documentation/gitrepository-layout.txt
> +++ b/Documentation/gitrepository-layout.txt
> @@ -143,6 +143,11 @@ config::
>         if $GIT_COMMON_DIR is set and "$GIT_COMMON_DIR/config" will be
>         used instead.
>
> +config.worktree::
> +       Working directory specific configuration file for the main
> +       working directory in multiple working directory setup (see
> +       linkgit:git-worktree[1]).
> +
>  branches::
>         A slightly deprecated way to store shorthands to be used
>         to specify a URL to 'git fetch', 'git pull' and 'git push'.
> @@ -276,6 +281,9 @@ worktrees/<id>/link::
>         file. It is used to detect if the linked repository is
>         manually removed.
>
> +worktrees/<id>/config.worktree::
> +       Working directory specific configuration file.
> +
>  SEE ALSO
>  --------
>  linkgit:git-init[1],
> diff --git a/builtin/config.c b/builtin/config.c
> index 1d7c6ef..535707c 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -4,6 +4,7 @@
>  #include "parse-options.h"
>  #include "urlmatch.h"
>  #include "quote.h"
> +#include "worktree.h"
>
>  static const char *const builtin_config_usage[] = {
>         N_("git config [<options>]"),
> @@ -23,6 +24,7 @@ static char key_delim = ' ';
>  static char term = '\n';
>
>  static int use_global_config, use_system_config, use_local_config;
> +static int use_worktree_config;
>  static struct git_config_source given_config_source;
>  static int actions, types;
>  static const char *get_color_slot, *get_colorbool_slot;
> @@ -57,6 +59,7 @@ static struct option builtin_config_options[] = {
>         OPT_BOOL(0, "global", &use_global_config, N_("use global config file")),
>         OPT_BOOL(0, "system", &use_system_config, N_("use system config file")),
>         OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")),
> +       OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")),
>         OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")),
>         OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")),
>         OPT_GROUP(N_("Action")),
> @@ -491,6 +494,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
>                              PARSE_OPT_STOP_AT_NON_OPTION);
>
>         if (use_global_config + use_system_config + use_local_config +
> +           use_worktree_config +
>             !!given_config_source.file + !!given_config_source.blob > 1) {
>                 error("only one config file at a time.");
>                 usage_with_options(builtin_config_usage, builtin_config_options);
> @@ -525,7 +529,19 @@ int cmd_config(int argc, const char **argv, const char *prefix)
>                 given_config_source.file = git_etc_gitconfig();
>         else if (use_local_config)
>                 given_config_source.file = git_pathdup("config");
> -       else if (given_config_source.file) {
> +       else if (use_worktree_config) {
> +               if (repository_format_worktree_config)
> +                       given_config_source.file = git_pathdup("config.worktree");
> +               else {
> +                       struct worktree **worktrees = get_worktrees();
> +                       if (worktrees[0] && worktrees[1])
> +                               die(_("Per-worktree configuration requires extensions.worktreeConfig\n"
> +                                     "Please read section CONFIGURATION in `git help worktree` before\n"
> +                                     "enabling it."));
> +                       free_worktrees(worktrees);
> +                       given_config_source.file = git_pathdup("config");
> +               }
> +       } else if (given_config_source.file) {
>                 if (!is_absolute_path(given_config_source.file) && prefix)
>                         given_config_source.file =
>                                 xstrdup(prefix_filename(prefix,
> diff --git a/cache.h b/cache.h
> index f1dc289..606500e 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -757,10 +757,12 @@ extern int grafts_replace_parents;
>  #define GIT_REPO_VERSION 0
>  #define GIT_REPO_VERSION_READ 1
>  extern int repository_format_precious_objects;
> +extern int repository_format_worktree_config;
>
>  struct repository_format {
>         int version;
>         int precious_objects;
> +       int worktree_config;
>         int is_bare;
>         char *work_tree;
>         struct string_list unknown_extensions;
> diff --git a/config.c b/config.c
> index bea937e..99ff6be 100644
> --- a/config.c
> +++ b/config.c
> @@ -1254,6 +1254,13 @@ static int do_git_config_sequence(config_fn_t fn, void *data)
>         if (repo_config && !access_or_die(repo_config, R_OK, 0))
>                 ret += git_config_from_file(fn, repo_config, data);
>
> +       if (repository_format_worktree_config) {
> +               char *path = git_pathdup("config.worktree");
> +               if (!access_or_die(path, R_OK, 0))
> +                       ret += git_config_from_file(fn, path, data);
> +               free(path);
> +       }
> +
>         current_parsing_scope = CONFIG_SCOPE_CMDLINE;
>         if (git_config_from_parameters(fn, data) < 0)
>                 die(_("unable to parse command-line config"));
> diff --git a/environment.c b/environment.c
> index ca72464..b4d56ef 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -26,6 +26,7 @@ int warn_ambiguous_refs = 1;
>  int warn_on_object_refname_ambiguity = 1;
>  int ref_paranoia = -1;
>  int repository_format_precious_objects;
> +int repository_format_worktree_config;
>  const char *git_commit_encoding;
>  const char *git_log_output_encoding;
>  const char *apply_default_whitespace;
> diff --git a/setup.c b/setup.c
> index 6d0e0c9..75c784f 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -389,6 +389,8 @@ static int check_repo_format(const char *var, const char *value, void *vdata)
>                         ;
>                 else if (!strcmp(ext, "preciousobjects"))
>                         data->precious_objects = git_config_bool(var, value);
> +               else if (!strcmp(ext, "worktreeconfig"))
> +                       data->worktree_config = git_config_bool(var, value);
>                 else
>                         string_list_append(&data->unknown_extensions, ext);
>         } else if (strcmp(var, "core.bare") == 0) {
> @@ -432,8 +434,9 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
>         }
>
>         repository_format_precious_objects = candidate.precious_objects;
> +       repository_format_worktree_config = candidate.worktree_config;
>         string_list_clear(&candidate.unknown_extensions, 0);
> -       if (!has_common) {
> +       if (!has_common || repository_format_worktree_config) {
>                 if (candidate.is_bare != -1) {
>                         is_bare_repository_cfg = candidate.is_bare;
>                         if (is_bare_repository_cfg == 1)
> diff --git a/t/t2028-worktree-config.sh b/t/t2028-worktree-config.sh
> new file mode 100755
> index 0000000..34067df
> --- /dev/null
> +++ b/t/t2028-worktree-config.sh
> @@ -0,0 +1,77 @@
> +#!/bin/sh
> +
> +test_description="config file in multi worktree"
> +
> +. ./test-lib.sh
> +
> +cmp_config() {
> +       if [ "$1" = "-C" ]; then
> +               shift &&
> +               GD="-C $1" &&
> +               shift
> +       else
> +               GD=
> +       fi &&
> +       echo "$1" >expected &&
> +       shift &&
> +       git $GD config "$@" >actual &&
> +       test_cmp expected actual
> +}
> +
> +test_expect_success 'setup' '
> +       test_commit start &&
> +       git config --worktree per.worktree is-ok &&
> +       git worktree add wt1 &&
> +       git worktree add wt2 &&
> +       test_must_fail git config --worktree per.worktree is-not-ok &&
> +       git config extensions.worktreeConfig true
> +'
> +
> +test_expect_success 'config is shared as before' '
> +       git config this.is shared &&
> +       cmp_config shared this.is &&
> +       cmp_config -C wt1 shared this.is &&
> +       cmp_config -C wt2 shared this.is
> +'
> +
> +test_expect_success 'config is shared (set from another worktree)' '
> +       git -C wt1 config that.is also-shared &&
> +       cmp_config also-shared that.is &&
> +       cmp_config -C wt1 also-shared that.is &&
> +       cmp_config -C wt2 also-shared that.is
> +'
> +
> +test_expect_success 'config private to main worktree' '
> +       git config --worktree this.is for-main &&
> +       cmp_config for-main this.is &&
> +       cmp_config -C wt1 shared this.is &&
> +       cmp_config -C wt2 shared this.is
> +'
> +
> +test_expect_success 'config private to linked worktree' '
> +       git -C wt1 config --worktree this.is for-wt1 &&
> +       cmp_config for-main this.is &&
> +       cmp_config -C wt1 for-wt1 this.is &&
> +       cmp_config -C wt2 shared this.is
> +'
> +
> +test_expect_success 'core.bare no longer for main only' '
> +       git config core.bare true &&
> +       cmp_config true core.bare &&
> +       cmp_config -C wt1 true core.bare &&
> +       cmp_config -C wt2 true core.bare &&
> +       git config --unset core.bare
> +'
> +
> +test_expect_success 'config.worktree no longer read without extension' '
> +       git config --unset extensions.worktreeConfig &&
> +       cmp_config shared this.is &&
> +       cmp_config -C wt1 shared this.is &&
> +       cmp_config -C wt2 shared this.is
> +'
> +
> +test_expect_success 'config --worktree fails in multi worktree without extension' '
> +       test_must_fail git config --worktree foo.bar true
> +'
> +
> +test_done
> --
> 2.9.1.566.gbd532d4
>

  reply	other threads:[~2016-07-26  0:59 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-19 20:59 Current state of Git worktree used with submodules? Lars Schneider
2016-07-20  4:14 ` Duy Nguyen
2016-07-20 17:24   ` [PATCH v4 0/4] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
2016-07-20 17:24     ` [PATCH v4 1/4] worktree: add per-worktree config files Nguyễn Thái Ngọc Duy
2016-07-26  0:59       ` Stefan Beller [this message]
2016-07-26 15:04         ` Duy Nguyen
2016-07-20 17:24     ` [PATCH v4 2/4] submodule: update core.worktree using git-config Nguyễn Thái Ngọc Duy
2016-07-20 22:04       ` Stefan Beller
2016-07-22 17:15         ` Duy Nguyen
2016-07-20 17:24     ` [PATCH v4 3/4] submodule: support running in multiple worktree setup Nguyễn Thái Ngọc Duy
2016-07-20 23:22       ` Stefan Beller
2016-07-22  0:37         ` Stefan Beller
2016-07-22  7:32         ` Jens Lehmann
2016-07-22 16:07           ` Stefan Beller
2016-07-22 16:55         ` Junio C Hamano
2016-07-22 17:40           ` Stefan Beller
2016-07-25 15:46             ` Junio C Hamano
2016-07-22 17:09         ` Duy Nguyen
2016-07-22 17:25           ` Stefan Beller
2016-07-22 17:42             ` Duy Nguyen
2016-07-25 23:25               ` Stefan Beller
2016-07-26 17:20                 ` Duy Nguyen
2016-07-26 18:15                   ` Stefan Beller
2016-07-27 14:37                     ` Jakub Narębski
2016-07-27 16:53                       ` Stefan Beller
2016-07-27 15:40                     ` Duy Nguyen
2016-08-03 21:47                       ` Stefan Beller
2016-07-27  4:10       ` Max Kirillov
2016-07-27 14:40         ` Jakub Narębski
2016-07-27 14:49         ` Duy Nguyen
2016-07-20 17:24     ` [PATCH v4 4/4] t2029: some really basic tests for submodules in multi worktree Nguyễn Thái Ngọc Duy

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='CAGZ79kYET=z-b+U-JN+H5jkRTGHR0oMdTfUZPMRJx50aH-idbw@mail.gmail.com' \
    --to=sbeller@google.com \
    --cc=Jens.Lehmann@web.de \
    --cc=git@drmicha.warpmail.net \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=larsxschneider@gmail.com \
    --cc=max@max630.net \
    --cc=mhagger@alum.mit.edu \
    --cc=pclouds@gmail.com \
    /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).