{"thread":{"id":"46082","subject":"[PATCH 00/31] repository object","startedAt":"2017-05-31T21:44:38Z","lastAt":"2017-06-23T17:38:53Z","messageCount":196,"participants":["Brandon Williams","Stefan Beller","Jacob Keller","Jeff King","Johannes Schindelin","Ævar Arnfjörð Bjarmason","Martin Ågren","Christian Couder","Jonathan Nieder","Eric Wong","Jonathan Tan","Junio C Hamano","Andreas Schwab","Jeff Hostetler"],"isPatch":true,"patchVersion":1,"patchTotal":31},"messages":[{"id":"321171","messageId":"20170531214417.38857-1-bmwill@google.com","threadId":"46082","inReplyTo":null,"subject":"[PATCH 00/31] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:46Z","receivedAt":"2017-05-31T21:44:38Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Given the vast interest expressed when I sent out my RFC series I decided it\nwould be worth it to invest more time to making a repository object a reality.\n\nThis series is an extension of the last series I sent out (in that ls-files is\nconverted to working on submodules in-process using repository objects instead\nof spawning a child process to do the work).  The big difference from the RFC\nseries is that I went through and did the work to migrate key repository state\nfrom global variables in 'environment.c' to being stored in a repository object\nitself.  I migrated the bits of state that seemed reasonable for this series,\nthere is still a lot of global state which could be migrated in the future.\n\nI do think that we need to be slightly cautious about moving global state into\nthe repository object though, I don't want 'struct repo' to simply become a\nkitchen sink where everything gets dumped.  But this is just a warning for the\nfuture.\n\nSince this is a v1 I'm fairly certain that it still has a lot of rough edges\n(like I think I need to write better commit messages, and we should probably\nhave more comments documenting object fields/contract) but I want to get the\nreview process started sooner rather than later since I'm sure people will have\nopinions (e.g. should it be called 'struct repo' or 'struct repository'?!).\n\nSo here it is!  Thank you so much for taking the time review this, any and all\ncomments would be appreciated.\n\n- Brandon\n\nPatches [01-14] -> Introducing the Repository object and migrating some state\n\t\t   to be stored in 'the_repository'.\n\nPatches [15-31] -> Converting ls-files to use 'struct repo' in order to recurse\n\t\t   submodules in-process.\n\nBrandon Williams (31):\n  config: create config.h\n  config: don't include config.h by default\n  config: don't implicitly use gitdir\n  setup: don't perform lazy initialization of repository state\n  environment: remove namespace_len variable\n  repo: introduce the repository object\n  environment: place key repository state in the_repository\n  environment: store worktree in the_repository\n  setup: add comment indicating a hack\n  config: migrate the_configset to the_repository\n  repo: add index_state to struct repo\n  submodule-config: store the_submodule_cache in the_repository\n  repo: add repo_read_gitmodules\n  submodule: convert is_submodule_initialized to work on a repository\n  convert: convert get_cached_convert_stats_ascii to take an index\n  convert: convert crlf_to_git to take an index\n  convert: convert convert_to_git_filter_fd to take an index\n  convert: convert convert_to_git to take an index\n  convert: convert renormalize_buffer to take an index\n  tree: convert read_tree to take an index parameter\n  ls-files: convert overlay_tree_on_cache to take an index\n  ls-files: convert write_eolinfo to take an index\n  ls-files: convert show_killed_files to take an index\n  ls-files: convert show_other_files to take an index\n  ls-files: convert show_ru_info to take an index\n  ls-files: convert ce_excluded to take an index\n  ls-files: convert prune_cache to take an index\n  ls-files: convert show_files to take an index\n  ls-files: factor out debug info into a function\n  ls-files: factor out tag calculation\n  ls-files: use repository object\n\n Makefile                               |   1 +\n advice.c                               |   1 +\n alias.c                                |   1 +\n apply.c                                |   3 +-\n archive-tar.c                          |   1 +\n archive-zip.c                          |   1 +\n archive.c                              |   1 +\n attr.c                                 |   1 +\n bisect.c                               |   1 +\n branch.c                               |   1 +\n builtin/add.c                          |   1 +\n builtin/am.c                           |   1 +\n builtin/blame.c                        |   3 +-\n builtin/branch.c                       |   1 +\n builtin/cat-file.c                     |   1 +\n builtin/check-attr.c                   |   1 +\n builtin/check-ignore.c                 |   1 +\n builtin/check-mailmap.c                |   1 +\n builtin/checkout-index.c               |   1 +\n builtin/checkout.c                     |   1 +\n builtin/clean.c                        |   1 +\n builtin/clone.c                        |   1 +\n builtin/column.c                       |   1 +\n builtin/commit-tree.c                  |   1 +\n builtin/commit.c                       |   4 +-\n builtin/config.c                       |   3 +\n builtin/count-objects.c                |   1 +\n builtin/describe.c                     |   1 +\n builtin/diff-files.c                   |   1 +\n builtin/diff-index.c                   |   1 +\n builtin/diff-tree.c                    |   1 +\n builtin/diff.c                         |   1 +\n builtin/difftool.c                     |   1 +\n builtin/fast-export.c                  |   1 +\n builtin/fetch.c                        |   1 +\n builtin/fmt-merge-msg.c                |   1 +\n builtin/for-each-ref.c                 |   1 +\n builtin/fsck.c                         |   1 +\n builtin/gc.c                           |   1 +\n builtin/grep.c                         |   4 +-\n builtin/hash-object.c                  |   1 +\n builtin/help.c                         |   1 +\n builtin/index-pack.c                   |   1 +\n builtin/init-db.c                      |   1 +\n builtin/log.c                          |   1 +\n builtin/ls-files.c                     | 343 ++++++++++++++++-----------------\n builtin/ls-tree.c                      |   1 +\n builtin/merge-base.c                   |   1 +\n builtin/merge-file.c                   |   1 +\n builtin/merge.c                        |   1 +\n builtin/mv.c                           |   1 +\n builtin/name-rev.c                     |   1 +\n builtin/notes.c                        |   1 +\n builtin/pack-objects.c                 |   1 +\n builtin/patch-id.c                     |   1 +\n builtin/pull.c                         |   1 +\n builtin/push.c                         |   1 +\n builtin/read-tree.c                    |   1 +\n builtin/rebase--helper.c               |   1 +\n builtin/receive-pack.c                 |   1 +\n builtin/reflog.c                       |   1 +\n builtin/remote.c                       |   1 +\n builtin/repack.c                       |   1 +\n builtin/replace.c                      |   1 +\n builtin/rerere.c                       |   1 +\n builtin/reset.c                        |   1 +\n builtin/rev-list.c                     |   1 +\n builtin/rev-parse.c                    |   1 +\n builtin/revert.c                       |   1 +\n builtin/rm.c                           |   1 +\n builtin/send-pack.c                    |   1 +\n builtin/shortlog.c                     |   1 +\n builtin/show-branch.c                  |   1 +\n builtin/stripspace.c                   |   1 +\n builtin/submodule--helper.c            |  10 +-\n builtin/symbolic-ref.c                 |   1 +\n builtin/tag.c                          |   1 +\n builtin/unpack-file.c                  |   1 +\n builtin/unpack-objects.c               |   1 +\n builtin/update-index.c                 |   1 +\n builtin/update-ref.c                   |   1 +\n builtin/update-server-info.c           |   1 +\n builtin/var.c                          |   1 +\n builtin/verify-commit.c                |   1 +\n builtin/verify-pack.c                  |   1 +\n builtin/verify-tag.c                   |   1 +\n builtin/worktree.c                     |   1 +\n builtin/write-tree.c                   |   1 +\n cache.h                                | 196 +------------------\n color.c                                |   1 +\n column.c                               |   1 +\n combine-diff.c                         |   2 +-\n config.c                               | 186 +++++++++++-------\n config.h                               | 204 ++++++++++++++++++++\n connect.c                              |   1 +\n convert.c                              |  32 +--\n convert.h                              |  19 +-\n credential-cache--daemon.c             |   1 +\n credential.c                           |   1 +\n daemon.c                               |   1 +\n diff.c                                 |   7 +-\n dir.c                                  |   3 +-\n environment.c                          | 101 +++-------\n fast-import.c                          |   1 +\n fetch-pack.c                           |   1 +\n git.c                                  |   3 +-\n gpg-interface.c                        |   1 +\n graph.c                                |   1 +\n grep.c                                 |   1 +\n help.c                                 |   1 +\n http-backend.c                         |   1 +\n http-fetch.c                           |   1 +\n http.c                                 |   1 +\n ident.c                                |   1 +\n imap-send.c                            |   1 +\n ll-merge.c                             |   3 +-\n log-tree.c                             |   1 +\n mailinfo.c                             |   1 +\n merge-recursive.c                      |   5 +-\n notes-utils.c                          |   1 +\n notes.c                                |   1 +\n pager.c                                |   1 +\n parse-options.c                        |   1 +\n path.c                                 |  11 +-\n pathspec.c                             |   1 +\n pretty.c                               |   1 +\n prompt.c                               |   1 +\n read-cache.c                           |   1 +\n refs.c                                 |   1 +\n refs/files-backend.c                   |   1 +\n remote-curl.c                          |   1 +\n remote.c                               |   1 +\n repo.c                                 | 192 ++++++++++++++++++\n repo.h                                 |  45 +++++\n rerere.c                               |   1 +\n send-pack.c                            |   1 +\n sequencer.c                            |   1 +\n setup.c                                |  34 ++++\n sha1_file.c                            |   7 +-\n sha1_name.c                            |   1 +\n submodule-config.c                     |  72 +++++--\n submodule-config.h                     |  10 +\n submodule.c                            |  22 +--\n submodule.h                            |   3 +-\n t/helper/test-config.c                 |   1 +\n t/helper/test-submodule-config.c       |   1 +\n t/t3007-ls-files-recurse-submodules.sh |  39 ++++\n trailer.c                              |   1 +\n transport.c                            |   1 +\n tree.c                                 |  28 ++-\n tree.h                                 |   3 +-\n unpack-trees.c                         |   1 +\n upload-pack.c                          |   1 +\n userdiff.c                             |   1 +\n versioncmp.c                           |   1 +\n wrapper.c                              |   1 +\n xdiff-interface.c                      |   1 +\n 157 files changed, 1130 insertions(+), 593 deletions(-)\n create mode 100644 config.h\n create mode 100644 repo.c\n create mode 100644 repo.h\n\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321172","messageId":"20170531214417.38857-2-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 01/31] config: create config.h","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:47Z","receivedAt":"2017-05-31T21:44:40Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Move all config related declarations from cache.h to a new config.h\nheader file.  This makes cache.h smaller and allows for the opportunity\nin a following patch to only include config.h when needed.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h  | 190 +------------------------------------------------------------\n config.h | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 195 insertions(+), 189 deletions(-)\n create mode 100644 config.h\n\ndiff --git a/cache.h b/cache.h\nindex ae4c45d37..a27fee458 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -11,6 +11,7 @@\n #include \"string-list.h\"\n #include \"pack-revindex.h\"\n #include \"hash.h\"\n+#include \"config.h\"\n \n #ifndef platform_SHA_CTX\n /*\n@@ -1866,188 +1867,9 @@ extern int packed_object_info(struct packed_git *pack, off_t offset, struct obje\n /* Dumb servers support */\n extern int update_server_info(int);\n \n-/* git_config_parse_key() returns these negated: */\n-#define CONFIG_INVALID_KEY 1\n-#define CONFIG_NO_SECTION_OR_NAME 2\n-/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */\n-#define CONFIG_NO_LOCK -1\n-#define CONFIG_INVALID_FILE 3\n-#define CONFIG_NO_WRITE 4\n-#define CONFIG_NOTHING_SET 5\n-#define CONFIG_INVALID_PATTERN 6\n-#define CONFIG_GENERIC_ERROR 7\n-\n-#define CONFIG_REGEX_NONE ((void *)1)\n-\n-struct git_config_source {\n-\tunsigned int use_stdin:1;\n-\tconst char *file;\n-\tconst char *blob;\n-};\n-\n-enum config_origin_type {\n-\tCONFIG_ORIGIN_BLOB,\n-\tCONFIG_ORIGIN_FILE,\n-\tCONFIG_ORIGIN_STDIN,\n-\tCONFIG_ORIGIN_SUBMODULE_BLOB,\n-\tCONFIG_ORIGIN_CMDLINE\n-};\n-\n-struct config_options {\n-\tunsigned int respect_includes : 1;\n-\tconst char *git_dir;\n-};\n-\n-typedef int (*config_fn_t)(const char *, const char *, void *);\n-extern int git_default_config(const char *, const char *, void *);\n-extern int git_config_from_file(config_fn_t fn, const char *, void *);\n-extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,\n-\t\t\t\t\tconst char *name, const char *buf, size_t len, void *data);\n-extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,\n-\t\t\t\t     const unsigned char *sha1, void *data);\n-extern void git_config_push_parameter(const char *text);\n-extern int git_config_from_parameters(config_fn_t fn, void *data);\n-extern void read_early_config(config_fn_t cb, void *data);\n-extern void git_config(config_fn_t fn, void *);\n-extern int git_config_with_options(config_fn_t fn, void *,\n-\t\t\t\t   struct git_config_source *config_source,\n-\t\t\t\t   const struct config_options *opts);\n-extern int git_parse_ulong(const char *, unsigned long *);\n-extern int git_parse_maybe_bool(const char *);\n-extern int git_config_int(const char *, const char *);\n-extern int64_t git_config_int64(const char *, const char *);\n-extern unsigned long git_config_ulong(const char *, const char *);\n-extern ssize_t git_config_ssize_t(const char *, const char *);\n-extern int git_config_bool_or_int(const char *, const char *, int *);\n-extern int git_config_bool(const char *, const char *);\n-extern int git_config_maybe_bool(const char *, const char *);\n-extern int git_config_string(const char **, const char *, const char *);\n-extern int git_config_pathname(const char **, const char *, const char *);\n-extern int git_config_set_in_file_gently(const char *, const char *, const char *);\n-extern void git_config_set_in_file(const char *, const char *, const char *);\n-extern int git_config_set_gently(const char *, const char *);\n-extern void git_config_set(const char *, const char *);\n-extern int git_config_parse_key(const char *, char **, int *);\n-extern int git_config_key_is_valid(const char *key);\n-extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);\n-extern void git_config_set_multivar(const char *, const char *, const char *, int);\n-extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);\n-extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);\n-extern int git_config_rename_section(const char *, const char *);\n-extern int git_config_rename_section_in_file(const char *, const char *, const char *);\n-extern const char *git_etc_gitconfig(void);\n-extern int git_env_bool(const char *, int);\n-extern unsigned long git_env_ulong(const char *, unsigned long);\n-extern int git_config_system(void);\n-extern int config_error_nonbool(const char *);\n-#if defined(__GNUC__)\n-#define config_error_nonbool(s) (config_error_nonbool(s), const_error())\n-#endif\n extern const char *get_log_output_encoding(void);\n extern const char *get_commit_output_encoding(void);\n \n-extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);\n-\n-enum config_scope {\n-\tCONFIG_SCOPE_UNKNOWN = 0,\n-\tCONFIG_SCOPE_SYSTEM,\n-\tCONFIG_SCOPE_GLOBAL,\n-\tCONFIG_SCOPE_REPO,\n-\tCONFIG_SCOPE_CMDLINE,\n-};\n-\n-extern enum config_scope current_config_scope(void);\n-extern const char *current_config_origin_type(void);\n-extern const char *current_config_name(void);\n-\n-struct config_include_data {\n-\tint depth;\n-\tconfig_fn_t fn;\n-\tvoid *data;\n-\tconst struct config_options *opts;\n-};\n-#define CONFIG_INCLUDE_INIT { 0 }\n-extern int git_config_include(const char *name, const char *value, void *data);\n-\n-/*\n- * Match and parse a config key of the form:\n- *\n- *   section.(subsection.)?key\n- *\n- * (i.e., what gets handed to a config_fn_t). The caller provides the section;\n- * we return -1 if it does not match, 0 otherwise. The subsection and key\n- * out-parameters are filled by the function (and *subsection is NULL if it is\n- * missing).\n- *\n- * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if\n- * there is no subsection at all.\n- */\n-extern int parse_config_key(const char *var,\n-\t\t\t    const char *section,\n-\t\t\t    const char **subsection, int *subsection_len,\n-\t\t\t    const char **key);\n-\n-struct config_set_element {\n-\tstruct hashmap_entry ent;\n-\tchar *key;\n-\tstruct string_list value_list;\n-};\n-\n-struct configset_list_item {\n-\tstruct config_set_element *e;\n-\tint value_index;\n-};\n-\n-/*\n- * the contents of the list are ordered according to their\n- * position in the config files and order of parsing the files.\n- * (i.e. key-value pair at the last position of .git/config will\n- * be at the last item of the list)\n- */\n-struct configset_list {\n-\tstruct configset_list_item *items;\n-\tunsigned int nr, alloc;\n-};\n-\n-struct config_set {\n-\tstruct hashmap config_hash;\n-\tint hash_initialized;\n-\tstruct configset_list list;\n-};\n-\n-extern void git_configset_init(struct config_set *cs);\n-extern int git_configset_add_file(struct config_set *cs, const char *filename);\n-extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);\n-extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);\n-extern void git_configset_clear(struct config_set *cs);\n-extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);\n-extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);\n-extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);\n-extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);\n-extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);\n-extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);\n-extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);\n-extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);\n-\n-extern int git_config_get_value(const char *key, const char **value);\n-extern const struct string_list *git_config_get_value_multi(const char *key);\n-extern void git_config_clear(void);\n-extern void git_config_iter(config_fn_t fn, void *data);\n-extern int git_config_get_string_const(const char *key, const char **dest);\n-extern int git_config_get_string(const char *key, char **dest);\n-extern int git_config_get_int(const char *key, int *dest);\n-extern int git_config_get_ulong(const char *key, unsigned long *dest);\n-extern int git_config_get_bool(const char *key, int *dest);\n-extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);\n-extern int git_config_get_maybe_bool(const char *key, int *dest);\n-extern int git_config_get_pathname(const char *key, const char **dest);\n-extern int git_config_get_untracked_cache(void);\n-extern int git_config_get_split_index(void);\n-extern int git_config_get_max_percent_split_change(void);\n-\n-/* This dies if the configured or default date is in the future */\n-extern int git_config_get_expiry(const char *key, const char **output);\n-\n /*\n  * This is a hack for test programs like test-dump-untracked-cache to\n  * ensure that they do not modify the untracked cache when reading it.\n@@ -2055,16 +1877,6 @@ extern int git_config_get_expiry(const char *key, const char **output);\n  */\n extern int ignore_untracked_cache_config;\n \n-struct key_value_info {\n-\tconst char *filename;\n-\tint linenr;\n-\tenum config_origin_type origin_type;\n-\tenum config_scope scope;\n-};\n-\n-extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));\n-extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);\n-\n extern int committer_ident_sufficiently_given(void);\n extern int author_ident_sufficiently_given(void);\n \ndiff --git a/config.h b/config.h\nnew file mode 100644\nindex 000000000..f7f8b66c5\n--- /dev/null\n+++ b/config.h\n@@ -0,0 +1,194 @@\n+#ifndef CONFIG_H\n+#define CONFIG_H\n+\n+/* git_config_parse_key() returns these negated: */\n+#define CONFIG_INVALID_KEY 1\n+#define CONFIG_NO_SECTION_OR_NAME 2\n+/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */\n+#define CONFIG_NO_LOCK -1\n+#define CONFIG_INVALID_FILE 3\n+#define CONFIG_NO_WRITE 4\n+#define CONFIG_NOTHING_SET 5\n+#define CONFIG_INVALID_PATTERN 6\n+#define CONFIG_GENERIC_ERROR 7\n+\n+#define CONFIG_REGEX_NONE ((void *)1)\n+\n+struct git_config_source {\n+\tunsigned int use_stdin:1;\n+\tconst char *file;\n+\tconst char *blob;\n+};\n+\n+enum config_origin_type {\n+\tCONFIG_ORIGIN_BLOB,\n+\tCONFIG_ORIGIN_FILE,\n+\tCONFIG_ORIGIN_STDIN,\n+\tCONFIG_ORIGIN_SUBMODULE_BLOB,\n+\tCONFIG_ORIGIN_CMDLINE\n+};\n+\n+struct config_options {\n+\tunsigned int respect_includes : 1;\n+\tconst char *git_dir;\n+};\n+\n+typedef int (*config_fn_t)(const char *, const char *, void *);\n+extern int git_default_config(const char *, const char *, void *);\n+extern int git_config_from_file(config_fn_t fn, const char *, void *);\n+extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,\n+\t\t\t\t\tconst char *name, const char *buf, size_t len, void *data);\n+extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,\n+\t\t\t\t     const unsigned char *sha1, void *data);\n+extern void git_config_push_parameter(const char *text);\n+extern int git_config_from_parameters(config_fn_t fn, void *data);\n+extern void read_early_config(config_fn_t cb, void *data);\n+extern void git_config(config_fn_t fn, void *);\n+extern int git_config_with_options(config_fn_t fn, void *,\n+\t\t\t\t   struct git_config_source *config_source,\n+\t\t\t\t   const struct config_options *opts);\n+extern int git_parse_ulong(const char *, unsigned long *);\n+extern int git_parse_maybe_bool(const char *);\n+extern int git_config_int(const char *, const char *);\n+extern int64_t git_config_int64(const char *, const char *);\n+extern unsigned long git_config_ulong(const char *, const char *);\n+extern ssize_t git_config_ssize_t(const char *, const char *);\n+extern int git_config_bool_or_int(const char *, const char *, int *);\n+extern int git_config_bool(const char *, const char *);\n+extern int git_config_maybe_bool(const char *, const char *);\n+extern int git_config_string(const char **, const char *, const char *);\n+extern int git_config_pathname(const char **, const char *, const char *);\n+extern int git_config_set_in_file_gently(const char *, const char *, const char *);\n+extern void git_config_set_in_file(const char *, const char *, const char *);\n+extern int git_config_set_gently(const char *, const char *);\n+extern void git_config_set(const char *, const char *);\n+extern int git_config_parse_key(const char *, char **, int *);\n+extern int git_config_key_is_valid(const char *key);\n+extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);\n+extern void git_config_set_multivar(const char *, const char *, const char *, int);\n+extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);\n+extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);\n+extern int git_config_rename_section(const char *, const char *);\n+extern int git_config_rename_section_in_file(const char *, const char *, const char *);\n+extern const char *git_etc_gitconfig(void);\n+extern int git_env_bool(const char *, int);\n+extern unsigned long git_env_ulong(const char *, unsigned long);\n+extern int git_config_system(void);\n+extern int config_error_nonbool(const char *);\n+#if defined(__GNUC__)\n+#define config_error_nonbool(s) (config_error_nonbool(s), const_error())\n+#endif\n+\n+extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);\n+\n+enum config_scope {\n+\tCONFIG_SCOPE_UNKNOWN = 0,\n+\tCONFIG_SCOPE_SYSTEM,\n+\tCONFIG_SCOPE_GLOBAL,\n+\tCONFIG_SCOPE_REPO,\n+\tCONFIG_SCOPE_CMDLINE,\n+};\n+\n+extern enum config_scope current_config_scope(void);\n+extern const char *current_config_origin_type(void);\n+extern const char *current_config_name(void);\n+\n+struct config_include_data {\n+\tint depth;\n+\tconfig_fn_t fn;\n+\tvoid *data;\n+\tconst struct config_options *opts;\n+};\n+#define CONFIG_INCLUDE_INIT { 0 }\n+extern int git_config_include(const char *name, const char *value, void *data);\n+\n+/*\n+ * Match and parse a config key of the form:\n+ *\n+ *   section.(subsection.)?key\n+ *\n+ * (i.e., what gets handed to a config_fn_t). The caller provides the section;\n+ * we return -1 if it does not match, 0 otherwise. The subsection and key\n+ * out-parameters are filled by the function (and *subsection is NULL if it is\n+ * missing).\n+ *\n+ * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if\n+ * there is no subsection at all.\n+ */\n+extern int parse_config_key(const char *var,\n+\t\t\t    const char *section,\n+\t\t\t    const char **subsection, int *subsection_len,\n+\t\t\t    const char **key);\n+\n+struct config_set_element {\n+\tstruct hashmap_entry ent;\n+\tchar *key;\n+\tstruct string_list value_list;\n+};\n+\n+struct configset_list_item {\n+\tstruct config_set_element *e;\n+\tint value_index;\n+};\n+\n+/*\n+ * the contents of the list are ordered according to their\n+ * position in the config files and order of parsing the files.\n+ * (i.e. key-value pair at the last position of .git/config will\n+ * be at the last item of the list)\n+ */\n+struct configset_list {\n+\tstruct configset_list_item *items;\n+\tunsigned int nr, alloc;\n+};\n+\n+struct config_set {\n+\tstruct hashmap config_hash;\n+\tint hash_initialized;\n+\tstruct configset_list list;\n+};\n+\n+extern void git_configset_init(struct config_set *cs);\n+extern int git_configset_add_file(struct config_set *cs, const char *filename);\n+extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);\n+extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);\n+extern void git_configset_clear(struct config_set *cs);\n+extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);\n+extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);\n+extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);\n+extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);\n+extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);\n+extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);\n+extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);\n+extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);\n+\n+extern int git_config_get_value(const char *key, const char **value);\n+extern const struct string_list *git_config_get_value_multi(const char *key);\n+extern void git_config_clear(void);\n+extern void git_config_iter(config_fn_t fn, void *data);\n+extern int git_config_get_string_const(const char *key, const char **dest);\n+extern int git_config_get_string(const char *key, char **dest);\n+extern int git_config_get_int(const char *key, int *dest);\n+extern int git_config_get_ulong(const char *key, unsigned long *dest);\n+extern int git_config_get_bool(const char *key, int *dest);\n+extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);\n+extern int git_config_get_maybe_bool(const char *key, int *dest);\n+extern int git_config_get_pathname(const char *key, const char **dest);\n+extern int git_config_get_untracked_cache(void);\n+extern int git_config_get_split_index(void);\n+extern int git_config_get_max_percent_split_change(void);\n+\n+/* This dies if the configured or default date is in the future */\n+extern int git_config_get_expiry(const char *key, const char **output);\n+\n+struct key_value_info {\n+\tconst char *filename;\n+\tint linenr;\n+\tenum config_origin_type origin_type;\n+\tenum config_scope scope;\n+};\n+\n+extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));\n+extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);\n+\n+#endif /* CONFIG_H */\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321173","messageId":"20170531214417.38857-3-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 02/31] config: don't include config.h by default","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:48Z","receivedAt":"2017-05-31T21:44:45Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Stop including config.h by default in cache.h.  Instead only include\nconfig.h in those files which require use of the config system.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n advice.c                         | 1 +\n alias.c                          | 1 +\n apply.c                          | 1 +\n archive-tar.c                    | 1 +\n archive-zip.c                    | 1 +\n archive.c                        | 1 +\n attr.c                           | 1 +\n bisect.c                         | 1 +\n branch.c                         | 1 +\n builtin/add.c                    | 1 +\n builtin/am.c                     | 1 +\n builtin/blame.c                  | 1 +\n builtin/branch.c                 | 1 +\n builtin/cat-file.c               | 1 +\n builtin/check-attr.c             | 1 +\n builtin/check-ignore.c           | 1 +\n builtin/check-mailmap.c          | 1 +\n builtin/checkout-index.c         | 1 +\n builtin/checkout.c               | 1 +\n builtin/clean.c                  | 1 +\n builtin/clone.c                  | 1 +\n builtin/column.c                 | 1 +\n builtin/commit-tree.c            | 1 +\n builtin/commit.c                 | 1 +\n builtin/config.c                 | 1 +\n builtin/count-objects.c          | 1 +\n builtin/describe.c               | 1 +\n builtin/diff-files.c             | 1 +\n builtin/diff-index.c             | 1 +\n builtin/diff-tree.c              | 1 +\n builtin/diff.c                   | 1 +\n builtin/difftool.c               | 1 +\n builtin/fast-export.c            | 1 +\n builtin/fetch.c                  | 1 +\n builtin/fmt-merge-msg.c          | 1 +\n builtin/for-each-ref.c           | 1 +\n builtin/fsck.c                   | 1 +\n builtin/gc.c                     | 1 +\n builtin/grep.c                   | 1 +\n builtin/hash-object.c            | 1 +\n builtin/help.c                   | 1 +\n builtin/index-pack.c             | 1 +\n builtin/init-db.c                | 1 +\n builtin/log.c                    | 1 +\n builtin/ls-files.c               | 1 +\n builtin/ls-tree.c                | 1 +\n builtin/merge-base.c             | 1 +\n builtin/merge-file.c             | 1 +\n builtin/merge.c                  | 1 +\n builtin/mv.c                     | 1 +\n builtin/name-rev.c               | 1 +\n builtin/notes.c                  | 1 +\n builtin/pack-objects.c           | 1 +\n builtin/patch-id.c               | 1 +\n builtin/pull.c                   | 1 +\n builtin/push.c                   | 1 +\n builtin/read-tree.c              | 1 +\n builtin/rebase--helper.c         | 1 +\n builtin/receive-pack.c           | 1 +\n builtin/reflog.c                 | 1 +\n builtin/remote.c                 | 1 +\n builtin/repack.c                 | 1 +\n builtin/replace.c                | 1 +\n builtin/rerere.c                 | 1 +\n builtin/reset.c                  | 1 +\n builtin/rev-list.c               | 1 +\n builtin/rev-parse.c              | 1 +\n builtin/revert.c                 | 1 +\n builtin/rm.c                     | 1 +\n builtin/send-pack.c              | 1 +\n builtin/shortlog.c               | 1 +\n builtin/show-branch.c            | 1 +\n builtin/stripspace.c             | 1 +\n builtin/submodule--helper.c      | 1 +\n builtin/symbolic-ref.c           | 1 +\n builtin/tag.c                    | 1 +\n builtin/unpack-file.c            | 1 +\n builtin/unpack-objects.c         | 1 +\n builtin/update-index.c           | 1 +\n builtin/update-ref.c             | 1 +\n builtin/update-server-info.c     | 1 +\n builtin/var.c                    | 1 +\n builtin/verify-commit.c          | 1 +\n builtin/verify-pack.c            | 1 +\n builtin/verify-tag.c             | 1 +\n builtin/worktree.c               | 1 +\n builtin/write-tree.c             | 1 +\n cache.h                          | 1 -\n color.c                          | 1 +\n column.c                         | 1 +\n config.c                         | 1 +\n connect.c                        | 1 +\n convert.c                        | 1 +\n credential-cache--daemon.c       | 1 +\n credential.c                     | 1 +\n daemon.c                         | 1 +\n diff.c                           | 1 +\n dir.c                            | 1 +\n environment.c                    | 1 +\n fast-import.c                    | 1 +\n fetch-pack.c                     | 1 +\n git.c                            | 1 +\n gpg-interface.c                  | 1 +\n graph.c                          | 1 +\n grep.c                           | 1 +\n help.c                           | 1 +\n http-backend.c                   | 1 +\n http-fetch.c                     | 1 +\n http.c                           | 1 +\n ident.c                          | 1 +\n imap-send.c                      | 1 +\n ll-merge.c                       | 1 +\n log-tree.c                       | 1 +\n mailinfo.c                       | 1 +\n merge-recursive.c                | 1 +\n notes-utils.c                    | 1 +\n notes.c                          | 1 +\n pager.c                          | 1 +\n parse-options.c                  | 1 +\n pathspec.c                       | 1 +\n pretty.c                         | 1 +\n prompt.c                         | 1 +\n read-cache.c                     | 1 +\n refs.c                           | 1 +\n refs/files-backend.c             | 1 +\n remote-curl.c                    | 1 +\n remote.c                         | 1 +\n rerere.c                         | 1 +\n send-pack.c                      | 1 +\n sequencer.c                      | 1 +\n setup.c                          | 1 +\n sha1_file.c                      | 1 +\n sha1_name.c                      | 1 +\n submodule-config.c               | 1 +\n submodule.c                      | 1 +\n t/helper/test-config.c           | 1 +\n t/helper/test-submodule-config.c | 1 +\n trailer.c                        | 1 +\n transport.c                      | 1 +\n unpack-trees.c                   | 1 +\n upload-pack.c                    | 1 +\n userdiff.c                       | 1 +\n versioncmp.c                     | 1 +\n wrapper.c                        | 1 +\n xdiff-interface.c                | 1 +\n 145 files changed, 144 insertions(+), 1 deletion(-)\n\ndiff --git a/advice.c b/advice.c\nindex b84ae4960..3fa04fca0 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n \n int advice_push_update_rejected = 1;\n int advice_push_non_ff_current = 1;\ndiff --git a/alias.c b/alias.c\nindex 3b90397a9..052f34136 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n \n char *alias_lookup(const char *alias)\n {\ndiff --git a/apply.c b/apply.c\nindex c49cef063..87db9618d 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -8,6 +8,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"blob.h\"\n #include \"delta.h\"\n #include \"diff.h\"\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 073e60ebd..c6ed96ee7 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -2,6 +2,7 @@\n  * Copyright (c) 2005, 2006 Rene Scharfe\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tar.h\"\n #include \"archive.h\"\n #include \"streaming.h\"\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 27563e9e2..e8913e5a2 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -2,6 +2,7 @@\n  * Copyright (c) 2006 Rene Scharfe\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"archive.h\"\n #include \"streaming.h\"\n #include \"utf8.h\"\ndiff --git a/archive.c b/archive.c\nindex b15a922da..60b3035a7 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"commit.h\"\n #include \"tree-walk.h\"\ndiff --git a/attr.c b/attr.c\nindex 7e2134471..9f8b02936 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -9,6 +9,7 @@\n \n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"exec_cmd.h\"\n #include \"attr.h\"\n #include \"dir.h\"\ndiff --git a/bisect.c b/bisect.c\nindex d88f9bc3d..c2acb9455 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n #include \"revision.h\"\ndiff --git a/branch.c b/branch.c\nindex 985316eb7..a8a548ccf 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"branch.h\"\n #include \"refs.h\"\n #include \"remote.h\"\ndiff --git a/builtin/add.c b/builtin/add.c\nindex d9a2491e4..f2415e99f 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Linus Torvalds\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 0f63dcab1..0b6b1265d 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -4,6 +4,7 @@\n  * Based on git-am.sh by Junio C Hamano.\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 1043e5376..c0ae49298 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -6,6 +6,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\n #include \"blob.h\"\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 83fcda43d..c958e9325 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -6,6 +6,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"color.h\"\n #include \"refs.h\"\n #include \"commit.h\"\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 9af863e79..7bc45f600 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n #include \"userdiff.h\"\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 4d01ca0c8..91444dc04 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"attr.h\"\n #include \"quote.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex c7b8c0889..3e280b9c7 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"quote.h\"\n #include \"pathspec.h\"\ndiff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c\nindex cf0f54f6b..cdce144f3 100644\n--- a/builtin/check-mailmap.c\n+++ b/builtin/check-mailmap.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"mailmap.h\"\n #include \"parse-options.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex 07631d0c9..39c8be05d 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -5,6 +5,7 @@\n  *\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"quote.h\"\n #include \"cache-tree.h\"\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex a6b2af39d..45fab5a4d 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 329b68c40..09adf0551 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -8,6 +8,7 @@\n \n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 743f16ae2..4922a5496 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -9,6 +9,7 @@\n  */\n \n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"fetch-pack.h\"\ndiff --git a/builtin/column.c b/builtin/column.c\nindex 33314b4d7..0c3223d64 100644\n--- a/builtin/column.c\n+++ b/builtin/column.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"parse-options.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/commit-tree.c b/builtin/commit-tree.c\nindex f39c2b273..a4a923d7c 100644\n--- a/builtin/commit-tree.c\n+++ b/builtin/commit-tree.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"tree.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex da1ba4c86..805da4915 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -6,6 +6,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"cache-tree.h\"\n #include \"color.h\"\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 7f6c25d4d..753c40a5c 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"color.h\"\n #include \"parse-options.h\"\n #include \"urlmatch.h\"\ndiff --git a/builtin/count-objects.c b/builtin/count-objects.c\nindex acb05940f..1d82e61f2 100644\n--- a/builtin/count-objects.c\n+++ b/builtin/count-objects.c\n@@ -5,6 +5,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 893c8789f..70eb14460 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"commit.h\"\n #include \"tag.h\"\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 15c61fd8d..29d3e4f41 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n #include \"revision.h\"\ndiff --git a/builtin/diff-index.c b/builtin/diff-index.c\nindex 1af373d00..e3d418361 100644\n--- a/builtin/diff-index.c\n+++ b/builtin/diff-index.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n #include \"revision.h\"\ndiff --git a/builtin/diff-tree.c b/builtin/diff-tree.c\nindex 5ea1c1431..9af942b6b 100644\n--- a/builtin/diff-tree.c\n+++ b/builtin/diff-tree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n #include \"log-tree.h\"\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 8c03ddaf5..b85af112a 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -4,6 +4,7 @@\n  * Copyright (c) 2006 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"color.h\"\n #include \"commit.h\"\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex b9a892f26..9199227f6 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -12,6 +12,7 @@\n  * Copyright (C) 2016 Johannes Schindelin\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"run-command.h\"\n #include \"exec_cmd.h\"\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 24e29ad7e..0dfd980dd 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -5,6 +5,7 @@\n  */\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"commit.h\"\n #include \"object.h\"\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex d4d573b98..284595911 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -2,6 +2,7 @@\n  * \"git fetch\"\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"commit.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c\nindex 70137b0b7..10cbb4341 100644\n--- a/builtin/fmt-merge-msg.c\n+++ b/builtin/fmt-merge-msg.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"commit.h\"\n #include \"diff.h\"\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex eca365bf8..52be99cba 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"object.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex cb2ba6cd1..90593491e 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"tree.h\"\n #include \"blob.h\"\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex f484eda43..bd91f136f 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -11,6 +11,7 @@\n  */\n \n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"tempfile.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex c6c26e9b9..0f4a1e5a3 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -4,6 +4,7 @@\n  * Copyright (c) 2006 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"blob.h\"\n #include \"tree.h\"\n #include \"commit.h\"\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex bbeaf20bc..d04baf999 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -5,6 +5,7 @@\n  * Copyright (C) Junio C Hamano, 2005\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"blob.h\"\n #include \"quote.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 49f7a07f8..334a8494a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -2,6 +2,7 @@\n  * Builtin help command\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 04b9dcaf0..edc1a91d8 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"delta.h\"\n #include \"pack.h\"\n #include \"csum-file.h\"\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex 8a6acb0ec..47823f9aa 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\ndiff --git a/builtin/log.c b/builtin/log.c\nindex a440601ef..72a9fd968 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -5,6 +5,7 @@\n  *\t\t 2006 Junio Hamano\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"color.h\"\n #include \"commit.h\"\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex b376afc31..c4357dc30 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -6,6 +6,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"quote.h\"\n #include \"dir.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex ee7b293b1..ef965408e 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"blob.h\"\n #include \"tree.h\"\n #include \"commit.h\"\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex 0c36a70ad..6dbd167d3 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"diff.h\"\ndiff --git a/builtin/merge-file.c b/builtin/merge-file.c\nindex 47dde7c39..b08803e61 100644\n--- a/builtin/merge-file.c\n+++ b/builtin/merge-file.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"xdiff/xdiff.h\"\n #include \"xdiff-interface.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex a4a098f40..2512370c1 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -7,6 +7,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"builtin.h\"\n #include \"lockfile.h\"\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 61d20037a..dcf6736b5 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Johannes Schindelin\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"pathspec.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 7fc7e66e8..e21715f1d 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"tag.h\"\n #include \"refs.h\"\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex f2847c41e..231ad1f01 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -8,6 +8,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"notes.h\"\n #include \"blob.h\"\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 80439047a..9fe1fa8e1 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"attr.h\"\n #include \"object.h\"\n #include \"blob.h\"\ndiff --git a/builtin/patch-id.c b/builtin/patch-id.c\nindex 81552e02e..970d0d30b 100644\n--- a/builtin/patch-id.c\n+++ b/builtin/patch-id.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n \n static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)\n {\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex 318c273eb..af325d9fc 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -6,6 +6,7 @@\n  * Fetch one or more remote refs and merge it/them into the current HEAD.\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n #include \"exec_cmd.h\"\ndiff --git a/builtin/push.c b/builtin/push.c\nindex a597759d8..76aa713d2 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -2,6 +2,7 @@\n  * \"git push\"\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"run-command.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex 78d319365..6eb2a0e57 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -5,6 +5,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"object.h\"\n #include \"tree.h\"\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex ca1ebb2fa..c82b4dce6 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex b1706a573..71c0c768d 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"pack.h\"\n #include \"refs.h\"\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 920c16dac..44cdc2dbd 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"commit.h\"\n #include \"refs.h\"\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex addf97ad2..a470ed7c6 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"transport.h\"\n #include \"remote.h\"\ndiff --git a/builtin/repack.c b/builtin/repack.c\nindex 38ba4ef82..f17a68a17 100644\n--- a/builtin/repack.c\n+++ b/builtin/repack.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\n #include \"run-command.h\"\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex c921bc976..80a15cf35 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -9,6 +9,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/rerere.c b/builtin/rerere.c\nindex 1bf72423b..ffb66e290 100644\n--- a/builtin/rerere.c\n+++ b/builtin/rerere.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 430602d10..d0b604103 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -8,6 +8,7 @@\n  * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"tag.h\"\n #include \"object.h\"\ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex 718c6059c..f8e2b7bf5 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n #include \"revision.h\"\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex efdc14473..c78b7b33d 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"quote.h\"\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 345d9586a..16028b9ea 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n #include \"diff.h\"\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex 7c323d012..824d1de9e 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds 2006\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"cache-tree.h\"\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex b8e2e74fe..633e0c3cd 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\ndiff --git a/builtin/shortlog.c b/builtin/shortlog.c\nindex 7cff1839f..43c4799ea 100644\n--- a/builtin/shortlog.c\n+++ b/builtin/shortlog.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 4a6cc6f49..e4cf1b5bb 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 1e62a008c..bdf032886 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"strbuf.h\"\n \ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 8cc648d85..4dcbfb952 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"quote.h\"\n #include \"pathspec.h\"\ndiff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c\nindex 70addef15..df75cb9d4 100644\n--- a/builtin/symbolic-ref.c\n+++ b/builtin/symbolic-ref.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"cache.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1f74a56db..01154ea8d 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -7,6 +7,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"refs.h\"\n #include \"tag.h\"\ndiff --git a/builtin/unpack-file.c b/builtin/unpack-file.c\nindex 6fc6bcdf7..73f133419 100644\n--- a/builtin/unpack-file.c\n+++ b/builtin/unpack-file.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n \n static char *create_temp_file(unsigned char *sha1)\n {\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 8bc999776..193f8b9d5 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"object.h\"\n #include \"delta.h\"\n #include \"pack.h\"\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex ebfc09faa..0a4c23648 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"quote.h\"\n #include \"cache-tree.h\"\ndiff --git a/builtin/update-ref.c b/builtin/update-ref.c\nindex 0b2ecf41a..40ccfc193 100644\n--- a/builtin/update-ref.c\n+++ b/builtin/update-ref.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/update-server-info.c b/builtin/update-server-info.c\nindex 6c8cc3edc..873070e51 100644\n--- a/builtin/update-server-info.c\n+++ b/builtin/update-server-info.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n \ndiff --git a/builtin/var.c b/builtin/var.c\nindex aedbb53a2..6c6f46b4a 100644\n--- a/builtin/var.c\n+++ b/builtin/var.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Eric Biederman, 2005\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n \n static const char var_usage[] = \"git var (-l | <variable>)\";\n \ndiff --git a/builtin/verify-commit.c b/builtin/verify-commit.c\nindex 05b734e6d..ba38ac9b1 100644\n--- a/builtin/verify-commit.c\n+++ b/builtin/verify-commit.c\n@@ -6,6 +6,7 @@\n  * Based on git-verify-tag\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"commit.h\"\n #include \"run-command.h\"\ndiff --git a/builtin/verify-pack.c b/builtin/verify-pack.c\nindex c94e15693..c2a1a5c50 100644\n--- a/builtin/verify-pack.c\n+++ b/builtin/verify-pack.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"run-command.h\"\n #include \"parse-options.h\"\n \ndiff --git a/builtin/verify-tag.c b/builtin/verify-tag.c\nindex 5199553d9..f9a5f7535 100644\n--- a/builtin/verify-tag.c\n+++ b/builtin/verify-tag.c\n@@ -6,6 +6,7 @@\n  * Based on git-verify-tag.sh\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"tag.h\"\n #include \"run-command.h\"\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 793306ea5..0c5476ee9 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/write-tree.c b/builtin/write-tree.c\nindex 084c0df78..bd0a78aa3 100644\n--- a/builtin/write-tree.c\n+++ b/builtin/write-tree.c\n@@ -5,6 +5,7 @@\n  */\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tree.h\"\n #include \"cache-tree.h\"\n #include \"parse-options.h\"\ndiff --git a/cache.h b/cache.h\nindex a27fee458..272f8e021 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -11,7 +11,6 @@\n #include \"string-list.h\"\n #include \"pack-revindex.h\"\n #include \"hash.h\"\n-#include \"config.h\"\n \n #ifndef platform_SHA_CTX\n /*\ndiff --git a/color.c b/color.c\nindex dee61557e..31b6207a0 100644\n--- a/color.c\n+++ b/color.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"color.h\"\n \n static int git_use_color_default = GIT_COLOR_AUTO;\ndiff --git a/column.c b/column.c\nindex d55ead18e..ff7bdab1a 100644\n--- a/column.c\n+++ b/column.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"column.h\"\n #include \"string-list.h\"\n #include \"parse-options.h\"\ndiff --git a/config.c b/config.c\nindex 146cb3452..2390f98e3 100644\n--- a/config.c\n+++ b/config.c\n@@ -6,6 +6,7 @@\n  *\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"exec_cmd.h\"\n #include \"strbuf.h\"\ndiff --git a/connect.c b/connect.c\nindex cd21a1b6f..efddb30ea 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"pkt-line.h\"\n #include \"quote.h\"\n #include \"refs.h\"\ndiff --git a/convert.c b/convert.c\nindex f1e168bc3..5f4a4b1f5 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"attr.h\"\n #include \"run-command.h\"\n #include \"quote.h\"\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex f3814cc47..0d5c62509 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tempfile.h\"\n #include \"credential.h\"\n #include \"unix-socket.h\"\ndiff --git a/credential.c b/credential.c\nindex aa996669f..67a523353 100644\n--- a/credential.c\n+++ b/credential.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"credential.h\"\n #include \"string-list.h\"\n #include \"run-command.h\"\ndiff --git a/daemon.c b/daemon.c\nindex ac7181a48..30747075f 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"pkt-line.h\"\n #include \"run-command.h\"\n #include \"strbuf.h\"\ndiff --git a/diff.c b/diff.c\nindex f3546536b..2f2467c6d 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2,6 +2,7 @@\n  * Copyright (C) 2005 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tempfile.h\"\n #include \"quote.h\"\n #include \"diff.h\"\ndiff --git a/dir.c b/dir.c\nindex 3f3167e55..0c26a53d2 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -9,6 +9,7 @@\n  */\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"attr.h\"\n #include \"refs.h\"\ndiff --git a/environment.c b/environment.c\nindex aa478e71d..d40b21fb7 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,7 @@\n  * are.\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"fmt-merge-msg.h\"\n #include \"commit.h\"\ndiff --git a/fast-import.c b/fast-import.c\nindex e69d21968..2881d4898 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -154,6 +154,7 @@ Format of STDIN stream:\n \n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"object.h\"\n #include \"blob.h\"\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex cd86865be..fbbc99c88 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\ndiff --git a/git.c b/git.c\nindex 8ff44f081..594436e43 100644\n--- a/git.c\n+++ b/git.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"exec_cmd.h\"\n #include \"help.h\"\n #include \"run-command.h\"\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex e44cc27da..8ab32df45 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"run-command.h\"\n #include \"strbuf.h\"\n #include \"gpg-interface.h\"\ndiff --git a/graph.c b/graph.c\nindex 8b9049dd2..e7e20650d 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"color.h\"\n #include \"graph.h\"\ndiff --git a/grep.c b/grep.c\nindex 47cee4506..d5211fc5a 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"grep.h\"\n #include \"userdiff.h\"\n #include \"xdiff-interface.h\"\ndiff --git a/help.c b/help.c\nindex db7f3d79a..5d44f811a 100644\n--- a/help.c\n+++ b/help.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"run-command.h\"\ndiff --git a/http-backend.c b/http-backend.c\nindex ba5ff1aa2..519025d2c 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\n #include \"object.h\"\ndiff --git a/http-fetch.c b/http-fetch.c\nindex 3b556d661..8af380050 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"exec_cmd.h\"\n #include \"http.h\"\n #include \"walker.h\"\ndiff --git a/http.c b/http.c\nindex d2e11ec6f..013bb0cc6 100644\n--- a/http.c\n+++ b/http.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"http.h\"\n+#include \"config.h\"\n #include \"pack.h\"\n #include \"sideband.h\"\n #include \"run-command.h\"\ndiff --git a/ident.c b/ident.c\nindex bea871c8e..d41fc9119 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -6,6 +6,7 @@\n  * Copyright (C) 2005 Linus Torvalds\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n \n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\ndiff --git a/imap-send.c b/imap-send.c\nindex 857591660..59e9b12d2 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -23,6 +23,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"credential.h\"\n #include \"exec_cmd.h\"\n #include \"run-command.h\"\ndiff --git a/ll-merge.c b/ll-merge.c\nindex ac0d4a5d7..24ff94e1d 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -5,6 +5,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"attr.h\"\n #include \"xdiff-interface.h\"\n #include \"run-command.h\"\ndiff --git a/log-tree.c b/log-tree.c\nindex a4ec11c2b..7e1dfd749 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n #include \"tag.h\"\ndiff --git a/mailinfo.c b/mailinfo.c\nindex f92cb9f72..f59162453 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"utf8.h\"\n #include \"strbuf.h\"\n #include \"mailinfo.h\"\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex ae5238d82..c2494f34f 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -4,6 +4,7 @@\n  * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"advice.h\"\n #include \"lockfile.h\"\n #include \"cache-tree.h\"\ndiff --git a/notes-utils.c b/notes-utils.c\nindex 325ff3daa..ebde2273c 100644\n--- a/notes-utils.c\n+++ b/notes-utils.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"notes-utils.h\"\ndiff --git a/notes.c b/notes.c\nindex 542563b28..dbcfef4d7 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"notes.h\"\n #include \"blob.h\"\n #include \"tree.h\"\ndiff --git a/pager.c b/pager.c\nindex c113d898a..4dd9e1b26 100644\n--- a/pager.c\n+++ b/pager.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n \ndiff --git a/parse-options.c b/parse-options.c\nindex a23a1e67f..cbf84a604 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -1,6 +1,7 @@\n #include \"git-compat-util.h\"\n #include \"parse-options.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"color.h\"\n #include \"utf8.h\"\ndiff --git a/pathspec.c b/pathspec.c\nindex 828405021..ecc5331c2 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -1,5 +1,6 @@\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"pathspec.h\"\n #include \"attr.h\"\ndiff --git a/pretty.c b/pretty.c\nindex 09701bd2f..9c9f81b5b 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"utf8.h\"\n #include \"diff.h\"\ndiff --git a/prompt.c b/prompt.c\nindex 75406390c..6d5885d00 100644\n--- a/prompt.c\n+++ b/prompt.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"run-command.h\"\n #include \"strbuf.h\"\n #include \"prompt.h\"\ndiff --git a/read-cache.c b/read-cache.c\nindex 92eb15c00..2650ad98a 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -5,6 +5,7 @@\n  */\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tempfile.h\"\n #include \"lockfile.h\"\n #include \"cache-tree.h\"\ndiff --git a/refs.c b/refs.c\nindex 8af9641aa..7dfdc08bf 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -3,6 +3,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"hashmap.h\"\n #include \"lockfile.h\"\n #include \"iterator.h\"\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex cb1f528cb..f88b94484 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1,4 +1,5 @@\n #include \"../cache.h\"\n+#include \"../config.h\"\n #include \"../refs.h\"\n #include \"refs-internal.h\"\n #include \"ref-cache.h\"\ndiff --git a/remote-curl.c b/remote-curl.c\nindex ece45993d..0053b0954 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"remote.h\"\n #include \"strbuf.h\"\n #include \"walker.h\"\ndiff --git a/remote.c b/remote.c\nindex fdc52d802..a84e68767 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"remote.h\"\n #include \"refs.h\"\n #include \"commit.h\"\ndiff --git a/rerere.c b/rerere.c\nindex 3bd55caf3..344d6aa81 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"string-list.h\"\n #include \"rerere.h\"\ndiff --git a/send-pack.c b/send-pack.c\nindex 78bb34ebe..ed3cee321 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\ndiff --git a/sequencer.c b/sequencer.c\nindex a23b948ac..b9962dc89 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"sequencer.h\"\n #include \"dir.h\"\ndiff --git a/setup.c b/setup.c\nindex e3f7699a9..e99a82cbe 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"string-list.h\"\n \ndiff --git a/sha1_file.c b/sha1_file.c\nindex 59a4ed2ed..44561e0b9 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -7,6 +7,7 @@\n  * creation etc.\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"string-list.h\"\n #include \"lockfile.h\"\n #include \"delta.h\"\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 389276e9d..0ad85ec54 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tag.h\"\n #include \"commit.h\"\n #include \"tree.h\"\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4f58491dd..d8f8d5ea3 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n #include \"strbuf.h\"\ndiff --git a/submodule.c b/submodule.c\nindex bf5a93d16..95328de61 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n #include \"dir.h\"\ndiff --git a/t/helper/test-config.c b/t/helper/test-config.c\nindex 8e3ed6a76..1a7b8bd3d 100644\n--- a/t/helper/test-config.c\n+++ b/t/helper/test-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"string-list.h\"\n \n /*\ndiff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c\nindex 2f144d539..c6c57bba0 100644\n--- a/t/helper/test-submodule-config.c\n+++ b/t/helper/test-submodule-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n \ndiff --git a/trailer.c b/trailer.c\nindex 11f0b9fb4..751b56c00 100644\n--- a/trailer.c\n+++ b/trailer.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"string-list.h\"\n #include \"run-command.h\"\n #include \"commit.h\"\ndiff --git a/transport.c b/transport.c\nindex 9bfcf870f..b9995306f 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"transport.h\"\n #include \"run-command.h\"\n #include \"pkt-line.h\"\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex d38c37e38..dd535bc84 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1,5 +1,6 @@\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"tree.h\"\n #include \"tree-walk.h\"\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 5330c02c1..7efff2fbf 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\n #include \"sideband.h\"\ndiff --git a/userdiff.c b/userdiff.c\nindex 8b732e40b..2c1502f71 100644\n--- a/userdiff.c\n+++ b/userdiff.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"userdiff.h\"\n #include \"attr.h\"\n \ndiff --git a/versioncmp.c b/versioncmp.c\nindex 9f81dc106..069ee94a4 100644\n--- a/versioncmp.c\n+++ b/versioncmp.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"string-list.h\"\n \n /*\ndiff --git a/wrapper.c b/wrapper.c\nindex d83741770..487a9f753 100644\n--- a/wrapper.c\n+++ b/wrapper.c\n@@ -2,6 +2,7 @@\n  * Various trivial helper wrappers around standard functions\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n \n static void do_nothing(size_t size)\n {\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex 060038c2d..5ac07d734 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"xdiff-interface.h\"\n #include \"xdiff/xtypes.h\"\n #include \"xdiff/xdiffi.h\"\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321174","messageId":"20170531214417.38857-6-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 05/31] environment: remove namespace_len variable","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:51Z","receivedAt":"2017-05-31T21:44:46Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Use 'skip_prefix' instead of 'starts_with' so that we can drop the need\nto keep around 'namespace_len'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n environment.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex a73b08f5d..e035f6372 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -98,7 +98,6 @@ char *git_work_tree_cfg;\n static char *work_tree;\n \n static const char *namespace;\n-static size_t namespace_len;\n \n static const char *super_prefix;\n \n@@ -190,7 +189,6 @@ void setup_git_env(void)\n \tgit_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base\n \t\t\t\t\t\t\t  : \"refs/replace/\");\n \tnamespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));\n-\tnamespace_len = strlen(namespace);\n \tshallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);\n \tif (shallow_file)\n \t\tset_alternate_shallow_file(shallow_file, 0);\n@@ -231,9 +229,10 @@ const char *get_git_namespace(void)\n \n const char *strip_namespace(const char *namespaced_ref)\n {\n-\tif (!starts_with(namespaced_ref, get_git_namespace()))\n-\t\treturn NULL;\n-\treturn namespaced_ref + namespace_len;\n+\tconst char *out;\n+\tif (skip_prefix(namespaced_ref, get_git_namespace(), &out))\n+\t\treturn out;\n+\treturn NULL;\n }\n \n const char *get_super_prefix(void)\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321175","messageId":"20170531214417.38857-7-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 06/31] repo: introduce the repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:52Z","receivedAt":"2017-05-31T21:44:49Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce the repository object 'struct repo' which can be used hold all\nstate pertaining to a git repository.\n\nThe aim of object-ifying the repository is to (1) make the code base\nmore readable and easier to reason about and (2) allow for working on\nmultiple repositories, specifically submodules, within the same process.\n\nTODO: Add more motivating points for adding a repository object?\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Makefile      |   1 +\n cache.h       |   1 +\n environment.c |   2 +-\n repo.c        | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n repo.h        |  25 ++++++++++++\n 5 files changed, 152 insertions(+), 1 deletion(-)\n create mode 100644 repo.c\n create mode 100644 repo.h\n\ndiff --git a/Makefile b/Makefile\nindex 2ed6db728..3d3d556ef 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -821,6 +821,7 @@ LIB_OBJS += refs/ref-cache.o\n LIB_OBJS += ref-filter.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\n+LIB_OBJS += repo.o\n LIB_OBJS += rerere.o\n LIB_OBJS += resolve-undo.o\n LIB_OBJS += revision.o\ndiff --git a/cache.h b/cache.h\nindex d41aab82f..c0b4c8d83 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -483,6 +483,7 @@ extern char *get_graft_file(void);\n extern int set_git_dir(const char *path);\n extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n extern int get_common_dir(struct strbuf *sb, const char *gitdir);\n+extern char *expand_namespace(const char *raw_namespace);\n extern const char *get_git_namespace(void);\n extern const char *strip_namespace(const char *namespaced_ref);\n extern const char *get_super_prefix(void);\ndiff --git a/environment.c b/environment.c\nindex e035f6372..77900b31a 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -127,7 +127,7 @@ const char * const local_repo_env[] = {\n \tNULL\n };\n \n-static char *expand_namespace(const char *raw_namespace)\n+char *expand_namespace(const char *raw_namespace)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct strbuf **components, **c;\ndiff --git a/repo.c b/repo.c\nnew file mode 100644\nindex 000000000..f7c3617a9\n--- /dev/null\n+++ b/repo.c\n@@ -0,0 +1,124 @@\n+#include \"cache.h\"\n+#include \"repo.h\"\n+\n+/*\n+ * This may be the wrong place for this.\n+ * It may be better to go in env.c or setup for the time being?\n+ */\n+struct repo the_repository;\n+\n+static char *git_path_from_env(const char *envvar, const char *git_dir,\n+\t\t\t       const char *path, int fromenv)\n+{\n+\tif (fromenv) {\n+\t\tconst char *value = getenv(envvar);\n+\t\tif (value)\n+\t\t\treturn xstrdup(value);\n+\t}\n+\n+\treturn xstrfmt(\"%s/%s\", git_dir, path);\n+}\n+\n+static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)\n+{\n+\tif (fromenv) {\n+\t\tconst char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n+\t\tif (value) {\n+\t\t\tstrbuf_addstr(sb, value);\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\n+\treturn get_common_dir_noenv(sb, gitdir);\n+}\n+\n+/* called after setting gitdir */\n+static void repo_setup_env(struct repo *repo)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tif (!repo->gitdir)\n+\t\tBUG(\"gitdir wasn't set before setting up the environment\");\n+\n+\trepo->different_commondir = find_common_dir(&sb, repo->gitdir,\n+\t\t\t\t\t\t    !repo->ignore_env);\n+\trepo->commondir = strbuf_detach(&sb, NULL);\n+\trepo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,\n+\t\t\t\t\t    \"objects\", !repo->ignore_env);\n+\trepo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,\n+\t\t\t\t\t     \"index\", !repo->ignore_env);\n+\trepo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,\n+\t\t\t\t\t     \"info/grafts\", !repo->ignore_env);\n+\trepo->namespace = expand_namespace(repo->ignore_env ? NULL :\n+\t\t\t\t\t   getenv(GIT_NAMESPACE_ENVIRONMENT));\n+}\n+\n+static void repo_clear_env(struct repo *repo)\n+{\n+\tfree(repo->gitdir);\n+\trepo->gitdir = NULL;\n+\tfree(repo->commondir);\n+\trepo->commondir = NULL;\n+\tfree(repo->objectdir);\n+\trepo->objectdir = NULL;\n+\tfree(repo->index_file);\n+\trepo->index_file = NULL;\n+\tfree(repo->graft_file);\n+\trepo->graft_file = NULL;\n+\tfree(repo->namespace);\n+\trepo->namespace = NULL;\n+}\n+\n+void repo_set_gitdir(struct repo *repo, const char *path)\n+{\n+\tconst char *gitfile = read_gitfile(path);\n+\n+\t/*\n+\t * NEEDSWORK: Eventually we want to be able to free gitdir and the rest\n+\t * of the environment before reinitializing it again, but we have some\n+\t * crazy code paths where we try to set gitdir with the current gitdir\n+\t * and we don't want to free gitdir before copying the passed in value.\n+\t */\n+\trepo->gitdir = xstrdup(gitfile ? gitfile : path);\n+\n+\trepo_setup_env(repo);\n+}\n+\n+int repo_init(struct repo *repo, const char *gitdir)\n+{\n+\tint error = 0;\n+\tchar *abspath = real_pathdup(gitdir, 1);\n+\tchar *suspect = xstrfmt(\"%s/.git\", abspath);\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *resolved_gitdir;\n+\n+\tmemset(repo, 0, sizeof(struct repo));\n+\n+\trepo->ignore_env = 1;\n+\n+\t/* First assume 'gitdir' references the gitdir directly */\n+\tresolved_gitdir = resolve_gitdir_gently(abspath, &error);\n+\t/* otherwise; try 'gitdir'.git */\n+\tif (!resolved_gitdir) {\n+\t\tresolved_gitdir = resolve_gitdir_gently(suspect, &error);\n+\t\tif (!resolved_gitdir) {\n+\t\t\tdie(\"'%s' is not a repository\\n\", abspath);\n+\t\t\treturn error;\n+\t\t}\n+\t}\n+\n+\trepo_set_gitdir(repo, resolved_gitdir);\n+\n+\t/* NEEDSWORK: Verify repository format version */\n+\n+\tfree(abspath);\n+\tfree(suspect);\n+\tstrbuf_release(&sb);\n+\n+\treturn error;\n+}\n+\n+void repo_clear(struct repo *repo)\n+{\n+\trepo_clear_env(repo);\n+}\ndiff --git a/repo.h b/repo.h\nnew file mode 100644\nindex 000000000..453049e67\n--- /dev/null\n+++ b/repo.h\n@@ -0,0 +1,25 @@\n+#ifndef REPO_H\n+#define REPO_H\n+\n+struct repo {\n+\t/* Environment */\n+\tchar *gitdir;\n+\tchar *commondir;\n+\tchar *objectdir;\n+\tchar *index_file;\n+\tchar *graft_file;\n+\tchar *namespace;\n+\n+\t/* Configurations */\n+\tunsigned ignore_env:1;\n+\t/* Indicates if a repository has a different 'commondir' from 'gitdir' */\n+\tunsigned different_commondir:1;\n+};\n+\n+extern struct repo the_repository;\n+\n+extern void repo_set_gitdir(struct repo *repo, const char *path);\n+extern int repo_init(struct repo *repo, const char *path);\n+extern void repo_clear(struct repo *repo);\n+\n+#endif /* REPO_H */\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321176","messageId":"20170531214417.38857-4-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 03/31] config: don't implicitly use gitdir","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:49Z","receivedAt":"2017-05-31T21:44:55Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Commit 2185fde56 (config: handle conditional include when $GIT_DIR is\nnot set up) added a 'git_dir' field to the config_options struct.  Let's\nuse this option field explicitly all the time instead of occasionally\nfalling back to calling 'git_pathdup(\"config\")' to get the path to the\nlocal repository configuration.  This allows 'go_git_config_sequence()'\nto not implicitly rely on global repository state.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/config.c | 2 ++\n config.c         | 4 ++--\n 2 files changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 753c40a5c..90f49a6ee 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -539,6 +539,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t\tconfig_options.respect_includes = !given_config_source.file;\n \telse\n \t\tconfig_options.respect_includes = respect_includes_opt;\n+\tif (have_git_dir())\n+\t\tconfig_options.git_dir = get_git_common_dir();\n \n \tif (end_null) {\n \t\tterm = '\\0';\ndiff --git a/config.c b/config.c\nindex 2390f98e3..ff09b27b8 100644\n--- a/config.c\n+++ b/config.c\n@@ -1548,8 +1548,6 @@ static int do_git_config_sequence(const struct config_options *opts,\n \n \tif (opts->git_dir)\n \t\trepo_config = mkpathdup(\"%s/config\", opts->git_dir);\n-\telse if (have_git_dir())\n-\t\trepo_config = git_pathdup(\"config\");\n \telse\n \t\trepo_config = NULL;\n \n@@ -1613,6 +1611,8 @@ static void git_config_raw(config_fn_t fn, void *data)\n \tstruct config_options opts = {0};\n \n \topts.respect_includes = 1;\n+\tif (have_git_dir())\n+\t\topts.git_dir = get_git_common_dir();\n \tif (git_config_with_options(fn, data, NULL, &opts) < 0)\n \t\t/*\n \t\t * git_config_with_options() normally returns only\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321177","messageId":"20170531214417.38857-9-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 08/31] environment: store worktree in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:54Z","receivedAt":"2017-05-31T21:44:57Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate 'work_tree' to be stored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n environment.c | 9 ++++-----\n repo.c        | 7 +++++++\n repo.h        | 2 ++\n 3 files changed, 13 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex a0519f4f3..2722ebb9f 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -96,7 +96,6 @@ int ignore_untracked_cache_config;\n \n /* This is set by setup_git_dir_gently() and/or git_default_config() */\n char *git_work_tree_cfg;\n-static char *work_tree;\n \n static const char *super_prefix;\n \n@@ -220,19 +219,19 @@ void set_git_work_tree(const char *new_work_tree)\n {\n \tif (git_work_tree_initialized) {\n \t\tnew_work_tree = real_path(new_work_tree);\n-\t\tif (strcmp(new_work_tree, work_tree))\n+\t\tif (strcmp(new_work_tree, the_repository.worktree))\n \t\t\tdie(\"internal error: work tree has already been set\\n\"\n \t\t\t    \"Current worktree: %s\\nNew worktree: %s\",\n-\t\t\t    work_tree, new_work_tree);\n+\t\t\t    the_repository.worktree, new_work_tree);\n \t\treturn;\n \t}\n \tgit_work_tree_initialized = 1;\n-\twork_tree = real_pathdup(new_work_tree, 1);\n+\trepo_set_worktree(&the_repository, new_work_tree);\n }\n \n const char *get_git_work_tree(void)\n {\n-\treturn work_tree;\n+\treturn the_repository.worktree;\n }\n \n char *get_object_directory(void)\ndiff --git a/repo.c b/repo.c\nindex f7c3617a9..789ffdd78 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -84,6 +84,11 @@ void repo_set_gitdir(struct repo *repo, const char *path)\n \trepo_setup_env(repo);\n }\n \n+void repo_set_worktree(struct repo *repo, const char *path)\n+{\n+\trepo->worktree = real_pathdup(path, 1);\n+}\n+\n int repo_init(struct repo *repo, const char *gitdir)\n {\n \tint error = 0;\n@@ -121,4 +126,6 @@ int repo_init(struct repo *repo, const char *gitdir)\n void repo_clear(struct repo *repo)\n {\n \trepo_clear_env(repo);\n+\tfree(repo->worktree);\n+\trepo->worktree = NULL;\n }\ndiff --git a/repo.h b/repo.h\nindex 453049e67..95d021049 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -9,6 +9,7 @@ struct repo {\n \tchar *index_file;\n \tchar *graft_file;\n \tchar *namespace;\n+\tchar *worktree;\n \n \t/* Configurations */\n \tunsigned ignore_env:1;\n@@ -19,6 +20,7 @@ struct repo {\n extern struct repo the_repository;\n \n extern void repo_set_gitdir(struct repo *repo, const char *path);\n+extern void repo_set_worktree(struct repo *repo, const char *path);\n extern int repo_init(struct repo *repo, const char *path);\n extern void repo_clear(struct repo *repo);\n \n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321178","messageId":"20170531214417.38857-14-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 13/31] repo: add repo_read_gitmodules","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:59Z","receivedAt":"2017-05-31T21:44:59Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach the repo object to be able to populate the submodule_cache by\nreading the repository's gitmodules file.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n repo.c | 14 ++++++++++++++\n repo.h |  1 +\n 2 files changed, 15 insertions(+)\n\ndiff --git a/repo.c b/repo.c\nindex 13b7d244f..6f7b2015f 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -116,6 +116,20 @@ void repo_read_index(struct repo *repo)\n \t\tdie(_(\"failure reading index\"));\n }\n \n+static int gitmodules_cb(const char *var, const char *value, void *data)\n+{\n+\tstruct repo *repo = data;\n+\treturn submodule_config_option(repo, var, value);\n+}\n+\n+void repo_read_gitmodules(struct repo *repo)\n+{\n+\tchar *gitmodules_path = xstrfmt(\"%s/.gitmodules\", repo->worktree);\n+\n+\tgit_config_from_file(gitmodules_cb, gitmodules_path, repo);\n+\tfree(gitmodules_path);\n+}\n+\n int repo_init(struct repo *repo, const char *gitdir)\n {\n \tint error = 0;\ndiff --git a/repo.h b/repo.h\nindex ebce2a408..ad0184eaa 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -37,6 +37,7 @@ extern void repo_set_gitdir(struct repo *repo, const char *path);\n extern void repo_set_worktree(struct repo *repo, const char *path);\n extern void repo_read_config(struct repo *repo);\n extern void repo_read_index(struct repo *repo);\n+extern void repo_read_gitmodules(struct repo *repo);\n extern int repo_init(struct repo *repo, const char *path);\n extern void repo_clear(struct repo *repo);\n \n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321179","messageId":"20170531214417.38857-12-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 11/31] repo: add index_state to struct repo","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:57Z","receivedAt":"2017-05-31T21:45:01Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n repo.c | 17 +++++++++++++++++\n repo.h |  3 +++\n 2 files changed, 20 insertions(+)\n\ndiff --git a/repo.c b/repo.c\nindex c67cad5a2..c79d29534 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -104,6 +104,17 @@ void repo_read_config(struct repo *repo)\n \tgit_config_with_options(config_set_callback, repo->config, NULL, &opts);\n }\n \n+void repo_read_index(struct repo *repo)\n+{\n+\tif (!repo->index)\n+\t\trepo->index = xcalloc(1, sizeof(struct index_state));\n+\telse\n+\t\tdiscard_index(repo->index);\n+\n+\tif (read_index_from(repo->index, repo->index_file) < 0)\n+\t\tdie(_(\"failure reading index\"));\n+}\n+\n int repo_init(struct repo *repo, const char *gitdir)\n {\n \tint error = 0;\n@@ -149,4 +160,10 @@ void repo_clear(struct repo *repo)\n \t\tfree(repo->config);\n \t\trepo->config = NULL;\n \t}\n+\n+\tif (repo->index) {\n+\t\tdiscard_index(repo->index);\n+\t\tfree(repo->index);\n+\t\trepo->index = NULL;\n+\t}\n }\ndiff --git a/repo.h b/repo.h\nindex 284452832..756cda9e1 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -2,6 +2,7 @@\n #define REPO_H\n \n struct config_set;\n+struct index_state;\n \n struct repo {\n \t/* Environment */\n@@ -20,6 +21,7 @@ struct repo {\n \t * ~/.gitconfig, XDG config file and the global /etc/gitconfig)\n \t */\n \tstruct config_set *config;\n+\tstruct index_state *index;\n \n \t/* Configurations */\n \tunsigned ignore_env:1;\n@@ -32,6 +34,7 @@ extern struct repo the_repository;\n extern void repo_set_gitdir(struct repo *repo, const char *path);\n extern void repo_set_worktree(struct repo *repo, const char *path);\n extern void repo_read_config(struct repo *repo);\n+extern void repo_read_index(struct repo *repo);\n extern int repo_init(struct repo *repo, const char *path);\n extern void repo_clear(struct repo *repo);\n \n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321180","messageId":"20170531214417.38857-8-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 07/31] environment: place key repository state in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:53Z","receivedAt":"2017-05-31T21:45:04Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate 'git_dir', 'git_common_dir', 'git_object_dir', 'git_index_file',\n'git_graft_file', and 'namespace' to be stored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h       |  1 -\n environment.c | 65 ++++++++++++++---------------------------------------------\n path.c        | 11 +++++-----\n setup.c       | 17 ++++++++++++++--\n 4 files changed, 36 insertions(+), 58 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c0b4c8d83..02ab5f801 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -769,7 +769,6 @@ extern int core_apply_sparse_checkout;\n extern int precomposed_unicode;\n extern int protect_hfs;\n extern int protect_ntfs;\n-extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n \n /*\n  * Include broken refs in all ref iterations, which will\ndiff --git a/environment.c b/environment.c\nindex 77900b31a..a0519f4f3 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,7 @@\n  * are.\n  */\n #include \"cache.h\"\n+#include \"repo.h\"\n #include \"config.h\"\n #include \"refs.h\"\n #include \"fmt-merge-msg.h\"\n@@ -97,14 +98,8 @@ int ignore_untracked_cache_config;\n char *git_work_tree_cfg;\n static char *work_tree;\n \n-static const char *namespace;\n-\n static const char *super_prefix;\n \n-static const char *git_dir, *git_common_dir;\n-static char *git_object_dir, *git_index_file, *git_graft_file;\n-int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -148,47 +143,16 @@ char *expand_namespace(const char *raw_namespace)\n \treturn strbuf_detach(&buf, NULL);\n }\n \n-static char *git_path_from_env(const char *envvar, const char *git_dir,\n-\t\t\t       const char *path, int *fromenv)\n-{\n-\tconst char *value = getenv(envvar);\n-\tif (!value)\n-\t\treturn xstrfmt(\"%s/%s\", git_dir, path);\n-\tif (fromenv)\n-\t\t*fromenv = 1;\n-\treturn xstrdup(value);\n-}\n-\n void setup_git_env(void)\n {\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *gitfile;\n \tconst char *shallow_file;\n \tconst char *replace_ref_base;\n \n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n-\tif (!git_dir) {\n-\t\tif (!startup_info->have_repository)\n-\t\t\tBUG(\"setup_git_env called without repository\");\n-\t\tgit_dir = DEFAULT_GIT_DIR_ENVIRONMENT;\n-\t}\n-\tgitfile = read_gitfile(git_dir);\n-\tgit_dir = xstrdup(gitfile ? gitfile : git_dir);\n-\tif (get_common_dir(&sb, git_dir))\n-\t\tgit_common_dir_env = 1;\n-\tgit_common_dir = strbuf_detach(&sb, NULL);\n-\tgit_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,\n-\t\t\t\t\t   \"objects\", &git_db_env);\n-\tgit_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,\n-\t\t\t\t\t   \"index\", &git_index_env);\n-\tgit_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, git_common_dir,\n-\t\t\t\t\t   \"info/grafts\", &git_graft_env);\n \tif (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))\n \t\tcheck_replace_refs = 0;\n \treplace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);\n \tgit_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base\n \t\t\t\t\t\t\t  : \"refs/replace/\");\n-\tnamespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));\n \tshallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);\n \tif (shallow_file)\n \t\tset_alternate_shallow_file(shallow_file, 0);\n@@ -203,28 +167,28 @@ int is_bare_repository(void)\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n-\t\t|| git_dir;\n+\t\t|| the_repository.gitdir;\n }\n \n const char *get_git_dir(void)\n {\n-\tif (!git_dir)\n+\tif (!the_repository.gitdir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_dir;\n+\treturn the_repository.gitdir;\n }\n \n const char *get_git_common_dir(void)\n {\n-\tif (!git_dir)\n+\tif (!the_repository.commondir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_common_dir;\n+\treturn the_repository.commondir;\n }\n \n const char *get_git_namespace(void)\n {\n-\tif (!namespace)\n+\tif (!the_repository.namespace)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn namespace;\n+\treturn the_repository.namespace;\n }\n \n const char *strip_namespace(const char *namespaced_ref)\n@@ -273,9 +237,9 @@ const char *get_git_work_tree(void)\n \n char *get_object_directory(void)\n {\n-\tif (!git_object_dir)\n+\tif (!the_repository.objectdir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_object_dir;\n+\treturn the_repository.objectdir;\n }\n \n int odb_mkstemp(struct strbuf *template, const char *pattern)\n@@ -313,22 +277,23 @@ int odb_pack_keep(const char *name)\n \n char *get_index_file(void)\n {\n-\tif (!git_index_file)\n+\tif (!the_repository.index_file)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_index_file;\n+\treturn the_repository.index_file;\n }\n \n char *get_graft_file(void)\n {\n-\tif (!git_graft_file)\n+\tif (!the_repository.graft_file)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_graft_file;\n+\treturn the_repository.graft_file;\n }\n \n int set_git_dir(const char *path)\n {\n \tif (setenv(GIT_DIR_ENVIRONMENT, path, 1))\n \t\treturn error(\"Could not set GIT_DIR to '%s'\", path);\n+\trepo_set_gitdir(&the_repository, path);\n \tsetup_git_env();\n \treturn 0;\n }\ndiff --git a/path.c b/path.c\nindex c1cb1cf62..a1a7c2653 100644\n--- a/path.c\n+++ b/path.c\n@@ -2,6 +2,7 @@\n  * Utilities for paths and pathnames\n  */\n #include \"cache.h\"\n+#include \"repo.h\"\n #include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"dir.h\"\n@@ -355,7 +356,7 @@ void report_linked_checkout_garbage(void)\n \tconst struct common_dir *p;\n \tint len;\n \n-\tif (!git_common_dir_env)\n+\tif (!the_repository.different_commondir)\n \t\treturn;\n \tstrbuf_addf(&sb, \"%s/\", get_git_dir());\n \tlen = sb.len;\n@@ -374,17 +375,17 @@ void report_linked_checkout_garbage(void)\n static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n {\n \tconst char *base = buf->buf + git_dir_len;\n-\tif (git_graft_env && is_dir_file(base, \"info\", \"grafts\"))\n+\tif (is_dir_file(base, \"info\", \"grafts\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      get_graft_file(), strlen(get_graft_file()));\n-\telse if (git_index_env && !strcmp(base, \"index\"))\n+\telse if (!strcmp(base, \"index\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      get_index_file(), strlen(get_index_file()));\n-\telse if (git_db_env && dir_prefix(base, \"objects\"))\n+\telse if (dir_prefix(base, \"objects\"))\n \t\treplace_dir(buf, git_dir_len + 7, get_object_directory());\n \telse if (git_hooks_path && dir_prefix(base, \"hooks\"))\n \t\treplace_dir(buf, git_dir_len + 5, git_hooks_path);\n-\telse if (git_common_dir_env)\n+\telse if (the_repository.different_commondir)\n \t\tupdate_common_dir(buf, git_dir_len, NULL);\n }\n \ndiff --git a/setup.c b/setup.c\nindex b2e05145c..dba3abd00 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repo.h\"\n #include \"config.h\"\n #include \"dir.h\"\n #include \"string-list.h\"\n@@ -376,6 +377,11 @@ void setup_work_tree(void)\n \tif (getenv(GIT_WORK_TREE_ENVIRONMENT))\n \t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, \".\", 1);\n \n+\t/*\n+\t * NEEDSWORK: this call can essentially be set_git_dir(get_git_dir())\n+\t * which can cause some problems when trying to free the old value of\n+\t * gitdir.\n+\t */\n \tset_git_dir(remove_leading_path(git_dir, work_tree));\n \tinitialized = 1;\n }\n@@ -1074,8 +1080,15 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t * the user has set GIT_DIR.  It may be beneficial to disallow bogus\n \t * GIT_DIR values at some point in the future.\n \t */\n-\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT))\n-\t\tsetup_git_env();\n+\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT)) {\n+\t\tif (!the_repository.gitdir) {\n+\t\t\tconst char *gitdir = getenv(GIT_DIR_ENVIRONMENT);\n+\t\t\tif (!gitdir)\n+\t\t\t\tgitdir = DEFAULT_GIT_DIR_ENVIRONMENT;\n+\t\t\trepo_set_gitdir(&the_repository, gitdir);\n+\t\t\tsetup_git_env();\n+\t\t}\n+\t}\n \n \tstrbuf_release(&dir);\n \tstrbuf_release(&gitdir);\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321181","messageId":"20170531214417.38857-13-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 12/31] submodule-config: store the_submodule_cache in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:58Z","receivedAt":"2017-05-31T21:45:05Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Refactor how 'the_submodule_cache' is handled so that it can be stored\ninside of a repository object.  Also migrate 'the_submodule_cache' to be\nstored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n repo.c             |  6 +++++\n repo.h             |  2 ++\n submodule-config.c | 71 ++++++++++++++++++++++++++++++++++++++++--------------\n submodule-config.h | 10 ++++++++\n 4 files changed, 71 insertions(+), 18 deletions(-)\n\ndiff --git a/repo.c b/repo.c\nindex c79d29534..13b7d244f 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"repo.h\"\n #include \"config.h\"\n+#include \"submodule-config.h\"\n \n /*\n  * This may be the wrong place for this.\n@@ -166,4 +167,9 @@ void repo_clear(struct repo *repo)\n \t\tfree(repo->index);\n \t\trepo->index = NULL;\n \t}\n+\n+\tif (repo->submodule_cache) {\n+\t\tsubmodule_cache_free(repo->submodule_cache);\n+\t\trepo->submodule_cache = NULL;\n+\t}\n }\ndiff --git a/repo.h b/repo.h\nindex 756cda9e1..ebce2a408 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -3,6 +3,7 @@\n \n struct config_set;\n struct index_state;\n+struct submodule_cache;\n \n struct repo {\n \t/* Environment */\n@@ -22,6 +23,7 @@ struct repo {\n \t */\n \tstruct config_set *config;\n \tstruct index_state *index;\n+\tstruct submodule_cache *submodule_cache;\n \n \t/* Configurations */\n \tunsigned ignore_env:1;\ndiff --git a/submodule-config.c b/submodule-config.c\nindex d8f8d5ea3..cd356fec0 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repo.h\"\n #include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n@@ -15,6 +16,7 @@\n struct submodule_cache {\n \tstruct hashmap for_path;\n \tstruct hashmap for_name;\n+\tunsigned initialized:1;\n };\n \n /*\n@@ -31,9 +33,6 @@ enum lookup_type {\n \tlookup_path\n };\n \n-static struct submodule_cache the_submodule_cache;\n-static int is_cache_init;\n-\n static int config_path_cmp(const struct submodule_entry *a,\n \t\t\t   const struct submodule_entry *b,\n \t\t\t   const void *unused)\n@@ -50,10 +49,16 @@ static int config_name_cmp(const struct submodule_entry *a,\n \t       hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);\n }\n \n-static void cache_init(struct submodule_cache *cache)\n+static struct submodule_cache *submodule_cache_alloc(void)\n+{\n+\treturn xcalloc(1, sizeof(struct submodule_cache));\n+}\n+\n+static void submodule_cache_init(struct submodule_cache *cache)\n {\n \thashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);\n \thashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);\n+\tcache->initialized = 1;\n }\n \n static void free_one_config(struct submodule_entry *entry)\n@@ -65,11 +70,14 @@ static void free_one_config(struct submodule_entry *entry)\n \tfree(entry->config);\n }\n \n-static void cache_free(struct submodule_cache *cache)\n+static void submodule_cache_clear(struct submodule_cache *cache)\n {\n \tstruct hashmap_iter iter;\n \tstruct submodule_entry *entry;\n \n+\tif (!cache->initialized)\n+\t\treturn;\n+\n \t/*\n \t * We iterate over the name hash here to be symmetric with the\n \t * allocation of struct submodule entries. Each is allocated by\n@@ -81,6 +89,13 @@ static void cache_free(struct submodule_cache *cache)\n \n \thashmap_free(&cache->for_path, 1);\n \thashmap_free(&cache->for_name, 1);\n+\tcache->initialized = 0;\n+}\n+\n+void submodule_cache_free(struct submodule_cache *cache)\n+{\n+\tsubmodule_cache_clear(cache);\n+\tfree(cache);\n }\n \n static unsigned int hash_sha1_string(const unsigned char *sha1,\n@@ -494,43 +509,63 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \treturn submodule;\n }\n \n-static void ensure_cache_init(void)\n+static void submodule_cache_check_init(struct repo *repository)\n {\n-\tif (is_cache_init)\n+\tif (repository->submodule_cache && repository->submodule_cache->initialized)\n \t\treturn;\n \n-\tcache_init(&the_submodule_cache);\n-\tis_cache_init = 1;\n+\tif (!repository->submodule_cache)\n+\t\trepository->submodule_cache = submodule_cache_alloc();\n+\n+\tsubmodule_cache_init(repository->submodule_cache);\n }\n \n-int parse_submodule_config_option(const char *var, const char *value)\n+int submodule_config_option(struct repo *repository,\n+\t\t\t    const char *var, const char *value)\n {\n \tstruct parse_config_parameter parameter;\n-\tparameter.cache = &the_submodule_cache;\n+\n+\tsubmodule_cache_check_init(repository);\n+\n+\tparameter.cache = repository->submodule_cache;\n \tparameter.treeish_name = NULL;\n \tparameter.gitmodules_sha1 = null_sha1;\n \tparameter.overwrite = 1;\n \n-\tensure_cache_init();\n \treturn parse_config(var, value, &parameter);\n }\n \n+int parse_submodule_config_option(const char *var, const char *value)\n+{\n+\treturn submodule_config_option(&the_repository, var, value);\n+}\n+\n const struct submodule *submodule_from_name(const unsigned char *treeish_name,\n \t\tconst char *name)\n {\n-\tensure_cache_init();\n-\treturn config_from(&the_submodule_cache, treeish_name, name, lookup_name);\n+\tsubmodule_cache_check_init(&the_repository);\n+\treturn config_from(the_repository.submodule_cache, treeish_name, name, lookup_name);\n }\n \n const struct submodule *submodule_from_path(const unsigned char *treeish_name,\n \t\tconst char *path)\n {\n-\tensure_cache_init();\n-\treturn config_from(&the_submodule_cache, treeish_name, path, lookup_path);\n+\tsubmodule_cache_check_init(&the_repository);\n+\treturn config_from(the_repository.submodule_cache, treeish_name, path, lookup_path);\n }\n \n+const struct submodule *submodule_from_cache(struct repo *repository,\n+\t\t\t\t\t     const unsigned char *treeish_name,\n+\t\t\t\t\t     const char *key)\n+{\n+\tsubmodule_cache_check_init(repository);\n+\treturn config_from(repository->submodule_cache, treeish_name,\n+\t\t\t   key, lookup_path);\n+}\n+\n+\n void submodule_free(void)\n {\n-\tcache_free(&the_submodule_cache);\n-\tis_cache_init = 0;\n+\tif (the_repository.submodule_cache)\n+\t\tsubmodule_cache_clear(the_repository.submodule_cache);\n }\ndiff --git a/submodule-config.h b/submodule-config.h\nindex d434ecdb4..2bfe78d89 100644\n--- a/submodule-config.h\n+++ b/submodule-config.h\n@@ -22,14 +22,24 @@ struct submodule {\n \tint recommend_shallow;\n };\n \n+struct submodule_cache;\n+struct repo;\n+\n+extern void submodule_cache_free(struct submodule_cache *cache);\n+\n extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_submodule_config_option(const char *var, const char *value);\n+extern int submodule_config_option(struct repo *repository,\n+\t\t\t\t   const char *var, const char *value);\n extern const struct submodule *submodule_from_name(\n \t\tconst unsigned char *commit_or_tree, const char *name);\n extern const struct submodule *submodule_from_path(\n \t\tconst unsigned char *commit_or_tree, const char *path);\n+extern const struct submodule *submodule_from_cache(struct repo *repository,\n+\t\t\t\t\t\t    const unsigned char *treeish_name,\n+\t\t\t\t\t\t    const char *key);\n extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,\n \t\t\t\t      unsigned char *gitmodules_sha1,\n \t\t\t\t      struct strbuf *rev);\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321182","messageId":"20170531214417.38857-15-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 14/31] submodule: convert is_submodule_initialized to work on a repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:00Z","receivedAt":"2017-05-31T21:45:07Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'is_submodule_initialized()' to take a repository object and\nwhile we're at it, lets rename the function to 'is_submodule_active()'\nand remove the NEEDSWORK comment.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/grep.c              |  3 ++-\n builtin/submodule--helper.c |  9 +++++----\n config.c                    | 12 ++++++------\n config.h                    |  9 +++++++++\n submodule.c                 | 21 +++++++++------------\n submodule.h                 |  3 ++-\n 6 files changed, 33 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0f4a1e5a3..c3086bc0b 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -4,6 +4,7 @@\n  * Copyright (c) 2006 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"repo.h\"\n #include \"config.h\"\n #include \"blob.h\"\n #include \"tree.h\"\n@@ -626,7 +627,7 @@ static int grep_submodule_launch(struct grep_opt *opt,\n static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1,\n \t\t\t  const char *filename, const char *path)\n {\n-\tif (!is_submodule_initialized(path))\n+\tif (!is_submodule_active(&the_repository, path))\n \t\treturn 0;\n \tif (!is_submodule_populated_gently(path, NULL)) {\n \t\t/*\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4dcbfb952..d2d6fa914 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"repo.h\"\n #include \"cache.h\"\n #include \"config.h\"\n #include \"parse-options.h\"\n@@ -280,7 +281,7 @@ static void module_list_active(struct module_list *list)\n \tfor (i = 0; i < list->nr; i++) {\n \t\tconst struct cache_entry *ce = list->entries[i];\n \n-\t\tif (!is_submodule_initialized(ce->name))\n+\t\tif (!is_submodule_active(&the_repository, ce->name))\n \t\t\tcontinue;\n \n \t\tALLOC_GROW(active_modules.entries,\n@@ -362,7 +363,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t *\n \t * Set active flag for the submodule being initialized\n \t */\n-\tif (!is_submodule_initialized(path)) {\n+\tif (!is_submodule_active(&the_repository, path)) {\n \t\tstrbuf_reset(&sb);\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n@@ -817,7 +818,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \t}\n \n \t/* Check if the submodule has been initialized. */\n-\tif (!is_submodule_initialized(ce->name)) {\n+\tif (!is_submodule_active(&the_repository, ce->name)) {\n \t\tnext_submodule_warn_missing(suc, out, displaypath);\n \t\tgoto cleanup;\n \t}\n@@ -1193,7 +1194,7 @@ static int is_active(int argc, const char **argv, const char *prefix)\n \n \tgitmodules_config();\n \n-\treturn !is_submodule_initialized(argv[1]);\n+\treturn !is_submodule_active(&the_repository, argv[1]);\n }\n \n #define SUPPORT_SUPER_PREFIX (1<<0)\ndiff --git a/config.c b/config.c\nindex 930333e89..977bba233 100644\n--- a/config.c\n+++ b/config.c\n@@ -1885,8 +1885,8 @@ static int repo_config_get_value(struct repo *repository,\n \treturn git_configset_get_value(repository->config, key, value);\n }\n \n-static const struct string_list *repo_config_get_value_multi(struct repo *repository,\n-\t\t\t\t\t\t\t     const char *key)\n+const struct string_list *repo_config_get_value_multi(struct repo *repository,\n+\t\t\t\t\t\t      const char *key)\n {\n \tgit_config_check_init(repository);\n \treturn git_configset_get_value_multi(repository->config, key);\n@@ -1903,8 +1903,8 @@ static int repo_config_get_string_const(struct repo *repository,\n \treturn ret;\n }\n \n-static int repo_config_get_string(struct repo *repository,\n-\t\t\t\t  const char *key, char **dest)\n+int repo_config_get_string(struct repo *repository,\n+\t\t\t   const char *key, char **dest)\n {\n \tgit_config_check_init(repository);\n \treturn repo_config_get_string_const(repository, key, (const char **)dest);\n@@ -1924,8 +1924,8 @@ static int repo_config_get_ulong(struct repo *repository,\n \treturn git_configset_get_ulong(repository->config, key, dest);\n }\n \n-static int repo_config_get_bool(struct repo *repository,\n-\t\t\t\tconst char *key, int *dest)\n+int repo_config_get_bool(struct repo *repository,\n+\t\t\t const char *key, int *dest)\n {\n \tgit_config_check_init(repository);\n \treturn git_configset_get_bool(repository->config, key, dest);\ndiff --git a/config.h b/config.h\nindex 4cd9e2915..c4406b728 100644\n--- a/config.h\n+++ b/config.h\n@@ -163,6 +163,15 @@ extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key,\n extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);\n extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);\n \n+struct repo;\n+\n+extern const struct string_list *repo_config_get_value_multi(struct repo *repository,\n+\t\t\t\t\t\t\t     const char *key);\n+extern int repo_config_get_string(struct repo *repository,\n+\t\t\t\t  const char *key, char **dest);\n+extern int repo_config_get_bool(struct repo *repository,\n+\t\t\t\tconst char *key, int *dest);\n+\n extern int git_config_get_value(const char *key, const char **value);\n extern const struct string_list *git_config_get_value_multi(const char *key);\n extern void git_config_clear(void);\ndiff --git a/submodule.c b/submodule.c\nindex 95328de61..84600bde7 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repo.h\"\n #include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n@@ -215,21 +216,17 @@ void gitmodules_config_sha1(const unsigned char *commit_sha1)\n }\n \n /*\n- * NEEDSWORK: With the addition of different configuration options to determine\n- * if a submodule is of interests, the validity of this function's name comes\n- * into question.  Once the dust has settled and more concrete terminology is\n- * decided upon, come up with a more proper name for this function.  One\n- * potential candidate could be 'is_submodule_active()'.\n- *\n  * Determine if a submodule has been initialized at a given 'path'\n  */\n-int is_submodule_initialized(const char *path)\n+int is_submodule_active(struct repo *repo, const char *path)\n {\n \tint ret = 0;\n \tchar *key = NULL;\n \tchar *value = NULL;\n \tconst struct string_list *sl;\n-\tconst struct submodule *module = submodule_from_path(null_sha1, path);\n+\tconst struct submodule *module;\n+\t\n+\tmodule = submodule_from_cache(repo, null_sha1, path);\n \n \t/* early return if there isn't a path->module mapping */\n \tif (!module)\n@@ -237,14 +234,14 @@ int is_submodule_initialized(const char *path)\n \n \t/* submodule.<name>.active is set */\n \tkey = xstrfmt(\"submodule.%s.active\", module->name);\n-\tif (!git_config_get_bool(key, &ret)) {\n+\tif (!repo_config_get_bool(repo, key, &ret)) {\n \t\tfree(key);\n \t\treturn ret;\n \t}\n \tfree(key);\n \n \t/* submodule.active is set */\n-\tsl = git_config_get_value_multi(\"submodule.active\");\n+\tsl = repo_config_get_value_multi(repo, \"submodule.active\");\n \tif (sl) {\n \t\tstruct pathspec ps;\n \t\tstruct argv_array args = ARGV_ARRAY_INIT;\n@@ -264,7 +261,7 @@ int is_submodule_initialized(const char *path)\n \n \t/* fallback to checking if the URL is set */\n \tkey = xstrfmt(\"submodule.%s.url\", module->name);\n-\tret = !git_config_get_string(key, &value);\n+\tret = !repo_config_get_string(repo, key, &value);\n \n \tfree(value);\n \tfree(key);\n@@ -1469,7 +1466,7 @@ int submodule_move_head(const char *path,\n \tconst struct submodule *sub;\n \tint *error_code_ptr, error_code;\n \n-\tif (!is_submodule_initialized(path))\n+\tif (!is_submodule_active(&the_repository, path))\n \t\treturn 0;\n \n \tif (flags & SUBMODULE_MOVE_HEAD_FORCE)\ndiff --git a/submodule.h b/submodule.h\nindex 8fb0f2549..5c30eea55 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -1,6 +1,7 @@\n #ifndef SUBMODULE_H\n #define SUBMODULE_H\n \n+struct repo;\n struct diff_options;\n struct argv_array;\n struct oid_array;\n@@ -41,7 +42,7 @@ extern void set_diffopt_flags_from_submodule_config(struct diff_options *,\n extern int submodule_config(const char *var, const char *value, void *cb);\n extern void gitmodules_config(void);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n-extern int is_submodule_initialized(const char *path);\n+extern int is_submodule_active(struct repo *repo, const char *path);\n /*\n  * Determine if a submodule has been populated at a given 'path' by checking if\n  * the <path>/.git resolves to a valid git repository.\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321183","messageId":"20170531214417.38857-17-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 16/31] convert: convert crlf_to_git to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:02Z","receivedAt":"2017-05-31T21:45:09Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex 574003023..ff3e72657 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -219,13 +219,13 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \t}\n }\n \n-static int has_cr_in_index(const char *path)\n+static int has_cr_in_index(const struct index_state *istate, const char *path)\n {\n \tunsigned long sz;\n \tvoid *data;\n \tint has_cr;\n \n-\tdata = read_blob_data_from_cache(path, &sz);\n+\tdata = read_blob_data_from_index(istate, path, &sz);\n \tif (!data)\n \t\treturn 0;\n \thas_cr = memchr(data, '\\r', sz) != NULL;\n@@ -255,7 +255,8 @@ static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats,\n \n }\n \n-static int crlf_to_git(const char *path, const char *src, size_t len,\n+static int crlf_to_git(const struct index_state *istate,\n+\t\t       const char *path, const char *src, size_t len,\n \t\t       struct strbuf *buf,\n \t\t       enum crlf_action crlf_action, enum safe_crlf checksafe)\n {\n@@ -287,7 +288,8 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \t\t * unless we want to renormalize in a merge or\n \t\t * cherry-pick.\n \t\t */\n-\t\tif ((checksafe != SAFE_CRLF_RENORMALIZE) && has_cr_in_index(path))\n+\t\tif ((checksafe != SAFE_CRLF_RENORMALIZE) &&\n+\t\t    has_cr_in_index(istate, path))\n \t\t\tconvert_crlf_into_lf = 0;\n \t}\n \tif ((checksafe == SAFE_CRLF_WARN ||\n@@ -1099,7 +1101,7 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\tret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);\n+\tret |= crlf_to_git(&the_index, path, src, len, dst, ca.crlf_action, checksafe);\n \tif (ret && dst) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -1119,7 +1121,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n \tif (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))\n \t\tdie(\"%s: clean filter '%s' failed\", path, ca.drv->name);\n \n-\tcrlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n+\tcrlf_to_git(&the_index, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321184","messageId":"20170531214417.38857-16-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 15/31] convert: convert get_cached_convert_stats_ascii to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:01Z","receivedAt":"2017-05-31T21:45:15Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 3 ++-\n convert.c          | 5 +++--\n convert.h          | 5 ++++-\n 3 files changed, 9 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex c4357dc30..f16ce0053 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -64,7 +64,8 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path)\n \t\tconst char *w_txt = \"\";\n \t\tconst char *a_txt = get_convert_attr_ascii(path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n-\t\t\ti_txt = get_cached_convert_stats_ascii(ce->name);\n+\t\t\ti_txt = get_cached_convert_stats_ascii(&the_index,\n+\t\t\t\t\t\t\t       ce->name);\n \t\tif (!lstat(path, &st) && S_ISREG(st.st_mode))\n \t\t\tw_txt = get_wt_convert_stats_ascii(path);\n \t\tprintf(\"i/%-5s w/%-5s attr/%-17s\\t\", i_txt, w_txt, a_txt);\ndiff --git a/convert.c b/convert.c\nindex 5f4a4b1f5..574003023 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -135,11 +135,12 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n-const char *get_cached_convert_stats_ascii(const char *path)\n+const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n+\t\t\t\t\t   const char *path)\n {\n \tconst char *ret;\n \tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n+\tvoid *data = read_blob_data_from_index(istate, path, &sz);\n \tret = gather_convert_stats_ascii(data, sz);\n \tfree(data);\n \treturn ret;\ndiff --git a/convert.h b/convert.h\nindex 82871a11d..667b7dfe0 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -4,6 +4,8 @@\n #ifndef CONVERT_H\n #define CONVERT_H\n \n+struct index_state;\n+\n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\n \tSAFE_CRLF_FAIL = 1,\n@@ -33,7 +35,8 @@ enum eol {\n };\n \n extern enum eol core_eol;\n-extern const char *get_cached_convert_stats_ascii(const char *path);\n+extern const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n+\t\t\t\t\t\t  const char *path);\n extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n \n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321185","messageId":"20170531214417.38857-20-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 19/31] convert: convert renormalize_buffer to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:05Z","receivedAt":"2017-05-31T21:45:18Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c         | 6 ++++--\n convert.h         | 3 ++-\n ll-merge.c        | 2 +-\n merge-recursive.c | 4 ++--\n 4 files changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex 5af6fdf3f..7d2a519da 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"config.h\"\n #include \"attr.h\"\n@@ -1166,14 +1167,15 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc\n \treturn convert_to_working_tree_internal(path, src, len, dst, 0);\n }\n \n-int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)\n+int renormalize_buffer(const struct index_state *istate, const char *path,\n+\t\t       const char *src, size_t len, struct strbuf *dst)\n {\n \tint ret = convert_to_working_tree_internal(path, src, len, dst, 1);\n \tif (ret) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(&the_index, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n+\treturn ret | convert_to_git(istate, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex 60cb41d6a..cecf59d1a 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -46,7 +46,8 @@ extern int convert_to_git(const struct index_state *istate,\n \t\t\t  struct strbuf *dst, enum safe_crlf checksafe);\n extern int convert_to_working_tree(const char *path, const char *src,\n \t\t\t\t   size_t len, struct strbuf *dst);\n-extern int renormalize_buffer(const char *path, const char *src, size_t len,\n+extern int renormalize_buffer(const struct index_state *istate,\n+\t\t\t      const char *path, const char *src, size_t len,\n \t\t\t      struct strbuf *dst);\n static inline int would_convert_to_git(const struct index_state *istate,\n \t\t\t\t       const char *path)\ndiff --git a/ll-merge.c b/ll-merge.c\nindex 24ff94e1d..b9576efe9 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -340,7 +340,7 @@ static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr\n static void normalize_file(mmfile_t *mm, const char *path)\n {\n \tstruct strbuf strbuf = STRBUF_INIT;\n-\tif (renormalize_buffer(path, mm->ptr, mm->size, &strbuf)) {\n+\tif (renormalize_buffer(&the_index, path, mm->ptr, mm->size, &strbuf)) {\n \t\tfree(mm->ptr);\n \t\tmm->size = strbuf.len;\n \t\tmm->ptr = strbuf_detach(&strbuf, NULL);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex c2494f34f..a4b3858d0 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -1640,8 +1640,8 @@ static int blob_unchanged(struct merge_options *opt,\n \t * performed.  Comparison can be skipped if both files are\n \t * unchanged since their sha1s have already been compared.\n \t */\n-\tif (renormalize_buffer(path, o.buf, o.len, &o) |\n-\t    renormalize_buffer(path, a.buf, a.len, &a))\n+\tif (renormalize_buffer(&the_index, path, o.buf, o.len, &o) |\n+\t    renormalize_buffer(&the_index, path, a.buf, a.len, &a))\n \t\tret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));\n \n error_return:\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321186","messageId":"20170531214417.38857-23-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 22/31] ls-files: convert write_eolinfo to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:08Z","receivedAt":"2017-05-31T21:45:19Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 13 ++++++-------\n 1 file changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex a5ceeb052..c37e9de11 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -54,17 +54,16 @@ static const char *tag_modified = \"\";\n static const char *tag_skip_worktree = \"\";\n static const char *tag_resolve_undo = \"\";\n \n-static void write_eolinfo(const struct cache_entry *ce, const char *path)\n+static void write_eolinfo(const struct index_state *istate,\n+\t\t\t  const struct cache_entry *ce, const char *path)\n {\n-\tif (!show_eol)\n-\t\treturn;\n-\telse {\n+\tif (show_eol) {\n \t\tstruct stat st;\n \t\tconst char *i_txt = \"\";\n \t\tconst char *w_txt = \"\";\n \t\tconst char *a_txt = get_convert_attr_ascii(path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n-\t\t\ti_txt = get_cached_convert_stats_ascii(&the_index,\n+\t\t\ti_txt = get_cached_convert_stats_ascii(istate,\n \t\t\t\t\t\t\t       ce->name);\n \t\tif (!lstat(path, &st) && S_ISREG(st.st_mode))\n \t\t\tw_txt = get_wt_convert_stats_ascii(path);\n@@ -106,7 +105,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \t\treturn;\n \n \tfputs(tag, stdout);\n-\twrite_eolinfo(NULL, ent->name);\n+\twrite_eolinfo(NULL, NULL, ent->name);\n \twrite_name(ent->name);\n }\n \n@@ -276,7 +275,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n \t\t\t       ce_stage(ce));\n \t\t}\n-\t\twrite_eolinfo(ce, ce->name);\n+\t\twrite_eolinfo(&the_index, ce, ce->name);\n \t\twrite_name(ce->name);\n \t\tif (debug_mode) {\n \t\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321187","messageId":"20170531214417.38857-22-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 21/31] ls-files: convert overlay_tree_on_cache to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:07Z","receivedAt":"2017-05-31T21:45:24Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/commit.c   |  3 ++-\n builtin/ls-files.c | 15 ++++++++-------\n cache.h            |  3 ++-\n 3 files changed, 12 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 805da4915..3d98084fb 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -254,7 +254,8 @@ static int list_paths(struct string_list *list, const char *with_tree,\n \n \tif (with_tree) {\n \t\tchar *max_prefix = common_prefix(pattern);\n-\t\toverlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix);\n+\t\toverlay_tree_on_index(&the_index, with_tree,\n+\t\t\t\t      max_prefix ? max_prefix : prefix);\n \t\tfree(max_prefix);\n \t}\n \ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 620487a77..a5ceeb052 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -432,7 +432,8 @@ static int get_common_prefix_len(const char *common_prefix)\n  * that were given from the command line.  We are not\n  * going to write this index out.\n  */\n-void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n+void overlay_tree_on_index(struct index_state *istate,\n+\t\t\t   const char *tree_name, const char *prefix)\n {\n \tstruct tree *tree;\n \tstruct object_id oid;\n@@ -447,8 +448,8 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\tdie(\"bad tree-ish %s\", tree_name);\n \n \t/* Hoist the unmerged entries up to stage #3 to make room */\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n \t\tce->ce_flags |= CE_STAGEMASK;\n@@ -461,11 +462,11 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\t\t       PATHSPEC_PREFER_CWD, prefix, matchbuf);\n \t} else\n \t\tmemset(&pathspec, 0, sizeof(pathspec));\n-\tif (read_tree(tree, 1, &pathspec, &the_index))\n+\tif (read_tree(tree, 1, &pathspec, istate))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \t\tswitch (ce_stage(ce)) {\n \t\tcase 0:\n \t\t\tlast_stage0 = ce;\n@@ -680,7 +681,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n-\t\toverlay_tree_on_cache(with_tree, max_prefix);\n+\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n \t}\n \tshow_files(&dir);\n \tif (show_resolve_undo)\ndiff --git a/cache.h b/cache.h\nindex 02ab5f801..73724a3ad 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1993,7 +1993,8 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule);\n #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)\n \n /* ls-files */\n-void overlay_tree_on_cache(const char *tree_name, const char *prefix);\n+void overlay_tree_on_index(struct index_state *istate,\n+\t\t\t   const char *tree_name, const char *prefix);\n \n char *alias_lookup(const char *alias);\n int split_cmdline(char *cmdline, const char ***argv);\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321188","messageId":"20170531214417.38857-21-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 20/31] tree: convert read_tree to take an index parameter","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:06Z","receivedAt":"2017-05-31T21:45:26Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c |  2 +-\n tree.c             | 28 ++++++++++++++++++----------\n tree.h             |  3 ++-\n 3 files changed, 21 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex f16ce0053..620487a77 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -461,7 +461,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\t\t       PATHSPEC_PREFER_CWD, prefix, matchbuf);\n \t} else\n \t\tmemset(&pathspec, 0, sizeof(pathspec));\n-\tif (read_tree(tree, 1, &pathspec))\n+\tif (read_tree(tree, 1, &pathspec, &the_index))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \n \tfor (i = 0; i < active_nr; i++) {\ndiff --git a/tree.c b/tree.c\nindex 603b29ee8..dd69423d9 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"cache-tree.h\"\n #include \"tree.h\"\n@@ -8,7 +9,11 @@\n \n const char *tree_type = \"tree\";\n \n-static int read_one_entry_opt(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, int opt)\n+static int read_one_entry_opt(struct index_state *istate,\n+\t\t\t      const unsigned char *sha1,\n+\t\t\t      const char *base, int baselen,\n+\t\t\t      const char *pathname,\n+\t\t\t      unsigned mode, int stage, int opt)\n {\n \tint len;\n \tunsigned int size;\n@@ -27,14 +32,15 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b\n \tmemcpy(ce->name, base, baselen);\n \tmemcpy(ce->name + baselen, pathname, len+1);\n \thashcpy(ce->oid.hash, sha1);\n-\treturn add_cache_entry(ce, opt);\n+\treturn add_index_entry(istate, ce, opt);\n }\n \n static int read_one_entry(const unsigned char *sha1, struct strbuf *base,\n \t\t\t  const char *pathname, unsigned mode, int stage,\n \t\t\t  void *context)\n {\n-\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\tstruct index_state *istate = context;\n+\treturn read_one_entry_opt(istate, sha1, base->buf, base->len, pathname,\n \t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);\n }\n@@ -47,7 +53,8 @@ static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,\n \t\t\t\tconst char *pathname, unsigned mode, int stage,\n \t\t\t\tvoid *context)\n {\n-\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\tstruct index_state *istate = context;\n+\treturn read_one_entry_opt(istate, sha1, base->buf, base->len, pathname,\n \t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_JUST_APPEND);\n }\n@@ -144,7 +151,8 @@ static int cmp_cache_name_compare(const void *a_, const void *b_)\n \t\t\t\t  ce2->name, ce2->ce_namelen, ce_stage(ce2));\n }\n \n-int read_tree(struct tree *tree, int stage, struct pathspec *match)\n+int read_tree(struct tree *tree, int stage, struct pathspec *match,\n+\t      struct index_state *istate)\n {\n \tread_tree_fn_t fn = NULL;\n \tint i, err;\n@@ -164,23 +172,23 @@ int read_tree(struct tree *tree, int stage, struct pathspec *match)\n \t * do it the original slow way, otherwise, append and then\n \t * sort at the end.\n \t */\n-\tfor (i = 0; !fn && i < active_nr; i++) {\n-\t\tconst struct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; !fn && i < istate->cache_nr; i++) {\n+\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\tif (ce_stage(ce) == stage)\n \t\t\tfn = read_one_entry;\n \t}\n \n \tif (!fn)\n \t\tfn = read_one_entry_quick;\n-\terr = read_tree_recursive(tree, \"\", 0, stage, match, fn, NULL);\n+\terr = read_tree_recursive(tree, \"\", 0, stage, match, fn, istate);\n \tif (fn == read_one_entry || err)\n \t\treturn err;\n \n \t/*\n \t * Sort the cache entry -- we need to nuke the cache tree, though.\n \t */\n-\tcache_tree_free(&active_cache_tree);\n-\tQSORT(active_cache, active_nr, cmp_cache_name_compare);\n+\tcache_tree_free(&istate->cache_tree);\n+\tQSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);\n \treturn 0;\n }\n \ndiff --git a/tree.h b/tree.h\nindex 0d4734b94..744e6dc2a 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -34,6 +34,7 @@ extern int read_tree_recursive(struct tree *tree,\n \t\t\t       int stage, const struct pathspec *pathspec,\n \t\t\t       read_tree_fn_t fn, void *context);\n \n-extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec);\n+extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec,\n+\t\t     struct index_state *istate);\n \n #endif /* TREE_H */\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321189","messageId":"20170531214417.38857-19-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 18/31] convert: convert convert_to_git to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:04Z","receivedAt":"2017-05-31T21:45:27Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n apply.c         | 2 +-\n builtin/blame.c | 2 +-\n combine-diff.c  | 2 +-\n convert.c       | 7 ++++---\n convert.h       | 8 +++++---\n diff.c          | 6 +++---\n dir.c           | 2 +-\n sha1_file.c     | 4 ++--\n 8 files changed, 18 insertions(+), 15 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 87db9618d..8eca54325 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -2268,7 +2268,7 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)\n \tcase S_IFREG:\n \t\tif (strbuf_read_file(buf, path, st->st_size) != st->st_size)\n \t\t\treturn error(_(\"unable to open or read %s\"), path);\n-\t\tconvert_to_git(path, buf->buf, buf->len, buf, 0);\n+\t\tconvert_to_git(&the_index, path, buf->buf, buf->len, buf, 0);\n \t\treturn 0;\n \tdefault:\n \t\treturn -1;\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex c0ae49298..317d2ec37 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2384,7 +2384,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,\n \t\tif (strbuf_read(&buf, 0, 0) < 0)\n \t\t\tdie_errno(\"failed to read from stdin\");\n \t}\n-\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n+\tconvert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0);\n \torigin->file.ptr = buf.buf;\n \torigin->file.size = buf.len;\n \tpretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 2848034fe..74f723af3 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1053,7 +1053,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\tif (is_file) {\n \t\t\t\tstruct strbuf buf = STRBUF_INIT;\n \n-\t\t\t\tif (convert_to_git(elem->path, result, len, &buf, safe_crlf)) {\n+\t\t\t\tif (convert_to_git(&the_index, elem->path, result, len, &buf, safe_crlf)) {\n \t\t\t\t\tfree(result);\n \t\t\t\t\tresult = strbuf_detach(&buf, &len);\n \t\t\t\t\tresult_size = len;\ndiff --git a/convert.c b/convert.c\nindex 824b606fa..5af6fdf3f 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1085,7 +1085,8 @@ const char *get_convert_attr_ascii(const char *path)\n \treturn \"\";\n }\n \n-int convert_to_git(const char *path, const char *src, size_t len,\n+int convert_to_git(const struct index_state *istate,\n+\t\t   const char *path, const char *src, size_t len,\n                    struct strbuf *dst, enum safe_crlf checksafe)\n {\n \tint ret = 0;\n@@ -1101,7 +1102,7 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\tret |= crlf_to_git(&the_index, path, src, len, dst, ca.crlf_action, checksafe);\n+\tret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, checksafe);\n \tif (ret && dst) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -1172,7 +1173,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n+\treturn ret | convert_to_git(&the_index, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex 3a813a797..60cb41d6a 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -41,15 +41,17 @@ extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n \n /* returns 1 if *dst was used */\n-extern int convert_to_git(const char *path, const char *src, size_t len,\n+extern int convert_to_git(const struct index_state *istate,\n+\t\t\t  const char *path, const char *src, size_t len,\n \t\t\t  struct strbuf *dst, enum safe_crlf checksafe);\n extern int convert_to_working_tree(const char *path, const char *src,\n \t\t\t\t   size_t len, struct strbuf *dst);\n extern int renormalize_buffer(const char *path, const char *src, size_t len,\n \t\t\t      struct strbuf *dst);\n-static inline int would_convert_to_git(const char *path)\n+static inline int would_convert_to_git(const struct index_state *istate,\n+\t\t\t\t       const char *path)\n {\n-\treturn convert_to_git(path, NULL, 0, NULL, 0);\n+\treturn convert_to_git(istate, path, NULL, 0, NULL, 0);\n }\n /* Precondition: would_convert_to_git_filter_fd(path) == true */\n extern void convert_to_git_filter_fd(const struct index_state *istate,\ndiff --git a/diff.c b/diff.c\nindex 2f2467c6d..87ed6d6d3 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2756,7 +2756,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \t * Similarly, if we'd have to convert the file contents anyway, that\n \t * makes the optimization not worthwhile.\n \t */\n-\tif (!want_file && would_convert_to_git(name))\n+\tif (!want_file && would_convert_to_git(&the_index, name))\n \t\treturn 0;\n \n \tlen = strlen(name);\n@@ -2878,7 +2878,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n \t\t * point if the path requires us to run the content\n \t\t * conversion.\n \t\t */\n-\t\tif (size_only && !would_convert_to_git(s->path))\n+\t\tif (size_only && !would_convert_to_git(&the_index, s->path))\n \t\t\treturn 0;\n \n \t\t/*\n@@ -2905,7 +2905,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n \t\t/*\n \t\t * Convert from working tree format to canonical git format\n \t\t */\n-\t\tif (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) {\n+\t\tif (convert_to_git(&the_index, s->path, s->data, s->size, &buf, crlf_warn)) {\n \t\t\tsize_t size = 0;\n \t\t\tmunmap(s->data, s->size);\n \t\t\ts->should_munmap = 0;\ndiff --git a/dir.c b/dir.c\nindex 0c26a53d2..8dc74c5d2 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -796,7 +796,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\t\t (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&\n \t\t\t\t !ce_stage(istate->cache[pos]) &&\n \t\t\t\t ce_uptodate(istate->cache[pos]) &&\n-\t\t\t\t !would_convert_to_git(fname))\n+\t\t\t\t !would_convert_to_git(istate, fname))\n \t\t\t\thashcpy(sha1_stat->sha1,\n \t\t\t\t\tistate->cache[pos]->oid.hash);\n \t\t\telse\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 80e9ef3bb..a900b2804 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -3547,7 +3547,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,\n \t */\n \tif ((type == OBJ_BLOB) && path) {\n \t\tstruct strbuf nbuf = STRBUF_INIT;\n-\t\tif (convert_to_git(path, buf, size, &nbuf,\n+\t\tif (convert_to_git(&the_index, path, buf, size, &nbuf,\n \t\t\t\t   write_object ? safe_crlf : SAFE_CRLF_FALSE)) {\n \t\t\tbuf = strbuf_detach(&nbuf, &size);\n \t\t\tre_allocated = 1;\n@@ -3669,7 +3669,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st,\n \telse if (!S_ISREG(st->st_mode))\n \t\tret = index_pipe(sha1, fd, type, path, flags);\n \telse if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||\n-\t\t (path && would_convert_to_git(path)))\n+\t\t (path && would_convert_to_git(&the_index, path)))\n \t\tret = index_core(sha1, fd, xsize_t(st->st_size), type, path,\n \t\t\t\t flags);\n \telse\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321190","messageId":"20170531214417.38857-29-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 28/31] ls-files: convert show_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:14Z","receivedAt":"2017-05-31T21:45:30Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex e2d8fb7f6..3061af2c5 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -329,7 +329,7 @@ static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n \treturn is_excluded(dir, istate, ce->name, &dtype);\n }\n \n-static void show_files(struct dir_struct *dir)\n+static void show_files(struct index_state *istate, struct dir_struct *dir)\n {\n \tint i;\n \n@@ -337,17 +337,17 @@ static void show_files(struct dir_struct *dir)\n \tif (show_others || show_killed) {\n \t\tif (!show_others)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n-\t\tfill_directory(dir, &the_index, &pathspec);\n+\t\tfill_directory(dir, istate, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(&the_index, dir);\n+\t\t\tshow_other_files(istate, dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(&the_index, dir);\n+\t\t\tshow_killed_files(istate, dir);\n \t}\n \tif (show_cached || show_stage) {\n-\t\tfor (i = 0; i < active_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = active_cache[i];\n+\t\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, &the_index, ce))\n+\t\t\t    !ce_excluded(dir, istate, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n@@ -358,12 +358,12 @@ static void show_files(struct dir_struct *dir)\n \t\t}\n \t}\n \tif (show_deleted || show_modified) {\n-\t\tfor (i = 0; i < active_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = active_cache[i];\n+\t\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\t\tstruct stat st;\n \t\t\tint err;\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, &the_index, ce))\n+\t\t\t    !ce_excluded(dir, istate, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n@@ -372,7 +372,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\terr = lstat(ce->name, &st);\n \t\t\tif (show_deleted && err)\n \t\t\t\tshow_ce_entry(tag_removed, ce);\n-\t\t\tif (show_modified && ce_modified(ce, &st, 0))\n+\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n \t\t\t\tshow_ce_entry(tag_modified, ce);\n \t\t}\n \t}\n@@ -686,7 +686,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n \t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n \t}\n-\tshow_files(&dir);\n+\tshow_files(&the_index, &dir);\n \tif (show_resolve_undo)\n \t\tshow_ru_info(&the_index);\n \n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321191","messageId":"20170531214417.38857-26-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 25/31] ls-files: convert show_ru_info to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:11Z","receivedAt":"2017-05-31T21:45:33Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex d00ca7810..2838e2f75 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -293,14 +293,14 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \tstrbuf_release(&name);\n }\n \n-static void show_ru_info(void)\n+static void show_ru_info(const struct index_state *istate)\n {\n \tstruct string_list_item *item;\n \n-\tif (!the_index.resolve_undo)\n+\tif (!istate->resolve_undo)\n \t\treturn;\n \n-\tfor_each_string_list_item(item, the_index.resolve_undo) {\n+\tfor_each_string_list_item(item, istate->resolve_undo) {\n \t\tconst char *path = item->string;\n \t\tstruct resolve_undo_info *ui = item->util;\n \t\tint i, len;\n@@ -686,7 +686,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t}\n \tshow_files(&dir);\n \tif (show_resolve_undo)\n-\t\tshow_ru_info();\n+\t\tshow_ru_info(&the_index);\n \n \tif (ps_matched) {\n \t\tint bad;\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321192","messageId":"20170531214417.38857-25-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 24/31] ls-files: convert show_other_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:10Z","receivedAt":"2017-05-31T21:45:36Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex f9578cf9f..d00ca7810 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -109,13 +109,14 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \twrite_name(ent->name);\n }\n \n-static void show_other_files(struct dir_struct *dir)\n+static void show_other_files(const struct index_state *istate,\n+\t\t\t     const struct dir_struct *dir)\n {\n \tint i;\n \n \tfor (i = 0; i < dir->nr; i++) {\n \t\tstruct dir_entry *ent = dir->entries[i];\n-\t\tif (!cache_name_is_other(ent->name, ent->len))\n+\t\tif (!index_name_is_other(istate, ent->name, ent->len))\n \t\t\tcontinue;\n \t\tshow_dir_entry(tag_other, ent);\n \t}\n@@ -337,7 +338,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n \t\tfill_directory(dir, &the_index, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(dir);\n+\t\t\tshow_other_files(&the_index, dir);\n \t\tif (show_killed)\n \t\t\tshow_killed_files(&the_index, dir);\n \t}\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321193","messageId":"20170531214417.38857-31-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 30/31] ls-files: factor out tag calculation","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:16Z","receivedAt":"2017-05-31T21:45:37Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 41 +++++++++++++++++++++++++----------------\n 1 file changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 2849c9a65..6a0302a28 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -94,6 +94,30 @@ static void write_name(const char *name)\n \tstrbuf_release(&full_name);\n }\n \n+static const char *get_tag(const struct cache_entry *ce, const char *tag)\n+{\n+\tstatic char alttag[4];\n+\n+\tif (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) {\n+\t\tmemcpy(alttag, tag, 3);\n+\n+\t\tif (isalpha(tag[0])) {\n+\t\t\talttag[0] = tolower(tag[0]);\n+\t\t} else if (tag[0] == '?') {\n+\t\t\talttag[0] = '!';\n+\t\t} else {\n+\t\t\talttag[0] = 'v';\n+\t\t\talttag[1] = tag[0];\n+\t\t\talttag[2] = ' ';\n+\t\t\talttag[3] = 0;\n+\t\t}\n+\n+\t\ttag = alttag;\n+\t}\n+\n+\treturn tag;\n+}\n+\n static void print_debug(const struct cache_entry *ce)\n {\n \tif (debug_mode) {\n@@ -264,22 +288,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t\t  len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n-\t\tif (tag && *tag && show_valid_bit &&\n-\t\t    (ce->ce_flags & CE_VALID)) {\n-\t\t\tstatic char alttag[4];\n-\t\t\tmemcpy(alttag, tag, 3);\n-\t\t\tif (isalpha(tag[0]))\n-\t\t\t\talttag[0] = tolower(tag[0]);\n-\t\t\telse if (tag[0] == '?')\n-\t\t\t\talttag[0] = '!';\n-\t\t\telse {\n-\t\t\t\talttag[0] = 'v';\n-\t\t\t\talttag[1] = tag[0];\n-\t\t\t\talttag[2] = ' ';\n-\t\t\t\talttag[3] = 0;\n-\t\t\t}\n-\t\t\ttag = alttag;\n-\t\t}\n+\t\ttag = get_tag(ce, tag);\n \n \t\tif (!show_stage) {\n \t\t\tfputs(tag, stdout);\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321194","messageId":"20170531214417.38857-30-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 29/31] ls-files: factor out debug info into a function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:15Z","receivedAt":"2017-05-31T21:45:40Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 23 ++++++++++++++---------\n 1 file changed, 14 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 3061af2c5..2849c9a65 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -94,6 +94,19 @@ static void write_name(const char *name)\n \tstrbuf_release(&full_name);\n }\n \n+static void print_debug(const struct cache_entry *ce)\n+{\n+\tif (debug_mode) {\n+\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n+\n+\t\tprintf(\"  ctime: %d:%d\\n\", sd->sd_ctime.sec, sd->sd_ctime.nsec);\n+\t\tprintf(\"  mtime: %d:%d\\n\", sd->sd_mtime.sec, sd->sd_mtime.nsec);\n+\t\tprintf(\"  dev: %d\\tino: %d\\n\", sd->sd_dev, sd->sd_ino);\n+\t\tprintf(\"  uid: %d\\tgid: %d\\n\", sd->sd_uid, sd->sd_gid);\n+\t\tprintf(\"  size: %d\\tflags: %x\\n\", sd->sd_size, ce->ce_flags);\n+\t}\n+}\n+\n static void show_dir_entry(const char *tag, struct dir_entry *ent)\n {\n \tint len = max_prefix_len;\n@@ -279,15 +292,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t}\n \t\twrite_eolinfo(&the_index, ce, ce->name);\n \t\twrite_name(ce->name);\n-\t\tif (debug_mode) {\n-\t\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n-\n-\t\t\tprintf(\"  ctime: %d:%d\\n\", sd->sd_ctime.sec, sd->sd_ctime.nsec);\n-\t\t\tprintf(\"  mtime: %d:%d\\n\", sd->sd_mtime.sec, sd->sd_mtime.nsec);\n-\t\t\tprintf(\"  dev: %d\\tino: %d\\n\", sd->sd_dev, sd->sd_ino);\n-\t\t\tprintf(\"  uid: %d\\tgid: %d\\n\", sd->sd_uid, sd->sd_gid);\n-\t\t\tprintf(\"  size: %d\\tflags: %x\\n\", sd->sd_size, ce->ce_flags);\n-\t\t}\n+\t\tprint_debug(ce);\n \t}\n \n \tstrbuf_release(&name);\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321195","messageId":"20170531214417.38857-32-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 31/31] ls-files: use repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:17Z","receivedAt":"2017-05-31T21:45:45Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert ls-files to use a repository struct and recurse submodules\ninprocess.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c                     | 211 ++++++++++++++-------------------\n git.c                                  |   2 +-\n repo.c                                 |   3 +\n repo.h                                 |   1 +\n t/t3007-ls-files-recurse-submodules.sh |  39 ++++++\n 5 files changed, 135 insertions(+), 121 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 6a0302a28..46962815f 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -5,6 +5,7 @@\n  *\n  * Copyright (C) Linus Torvalds, 2005\n  */\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"config.h\"\n #include \"quote.h\"\n@@ -17,6 +18,7 @@\n #include \"pathspec.h\"\n #include \"run-command.h\"\n #include \"submodule.h\"\n+#include \"repo.h\"\n \n static int abbrev;\n static int show_deleted;\n@@ -32,10 +34,8 @@ static int line_terminator = '\\n';\n static int debug_mode;\n static int show_eol;\n static int recurse_submodules;\n-static struct argv_array submodule_options = ARGV_ARRAY_INIT;\n \n static const char *prefix;\n-static const char *super_prefix;\n static int max_prefix_len;\n static int prefix_len;\n static struct pathspec pathspec;\n@@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,\n \n static void write_name(const char *name)\n {\n-\t/*\n-\t * Prepend the super_prefix to name to construct the full_name to be\n-\t * written.\n-\t */\n-\tstruct strbuf full_name = STRBUF_INIT;\n-\tif (super_prefix) {\n-\t\tstrbuf_addstr(&full_name, super_prefix);\n-\t\tstrbuf_addstr(&full_name, name);\n-\t\tname = full_name.buf;\n-\t}\n-\n \t/*\n \t * With \"--full-name\", prefix_len=0; this caller needs to pass\n \t * an empty string in that case (a NULL is good for \"\").\n \t */\n \twrite_name_quoted_relative(name, prefix_len ? prefix : NULL,\n \t\t\t\t   stdout, line_terminator);\n-\n-\tstrbuf_release(&full_name);\n }\n \n static const char *get_tag(const struct cache_entry *ce, const char *tag)\n@@ -210,101 +197,59 @@ static void show_killed_files(const struct index_state *istate,\n \t}\n }\n \n-/*\n- * Compile an argv_array with all of the options supported by --recurse_submodules\n- */\n-static void compile_submodule_options(const char **argv,\n-\t\t\t\t      const struct dir_struct *dir,\n-\t\t\t\t      int show_tag)\n-{\n-\tif (line_terminator == '\\0')\n-\t\targv_array_push(&submodule_options, \"-z\");\n-\tif (show_tag)\n-\t\targv_array_push(&submodule_options, \"-t\");\n-\tif (show_valid_bit)\n-\t\targv_array_push(&submodule_options, \"-v\");\n-\tif (show_cached)\n-\t\targv_array_push(&submodule_options, \"--cached\");\n-\tif (show_eol)\n-\t\targv_array_push(&submodule_options, \"--eol\");\n-\tif (debug_mode)\n-\t\targv_array_push(&submodule_options, \"--debug\");\n-\n-\t/* Add Pathspecs */\n-\targv_array_push(&submodule_options, \"--\");\n-\tfor (; *argv; argv++)\n-\t\targv_array_push(&submodule_options, *argv);\n-}\n+static void show_files(struct repo *repo, struct dir_struct *dir);\n \n-/**\n- * Recursively call ls-files on a submodule\n- */\n-static void show_gitlink(const struct cache_entry *ce)\n+static void show_submodule(const struct repo *superproject,\n+\t\t\t   struct dir_struct *dir, const char *path)\n {\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n-\tint status;\n-\tchar *dir;\n-\n-\tprepare_submodule_repo_env(&cp.env_array);\n-\targv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);\n-\n-\tif (prefix_len)\n-\t\targv_array_pushf(&cp.env_array, \"%s=%s\",\n-\t\t\t\t GIT_TOPLEVEL_PREFIX_ENVIRONMENT,\n-\t\t\t\t prefix);\n-\targv_array_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t\t super_prefix ? super_prefix : \"\",\n-\t\t\t ce->name);\n-\targv_array_push(&cp.args, \"ls-files\");\n-\targv_array_push(&cp.args, \"--recurse-submodules\");\n-\n-\t/* add supported options */\n-\targv_array_pushv(&cp.args, submodule_options.argv);\n-\n-\tcp.git_cmd = 1;\n-\tdir = mkpathdup(\"%s/%s\", get_git_work_tree(), ce->name);\n-\tcp.dir = dir;\n-\tstatus = run_command(&cp);\n-\tfree(dir);\n-\tif (status)\n-\t\texit(status);\n+\tstruct repo submodule;\n+\tchar *gitdir = mkpathdup(\"%s/%s\", superproject->worktree, path);\n+\trepo_init(&submodule, gitdir);\n+\n+\trepo_read_index(&submodule);\n+\trepo_read_gitmodules(&submodule);\n+\n+\tif (superproject->submodule_prefix)\n+\t\tsubmodule.submodule_prefix = xstrfmt(\"%s%s/\", superproject->submodule_prefix, path);\n+\telse\n+\t\tsubmodule.submodule_prefix = xstrfmt(\"%s/\", path);\n+\tshow_files(&submodule, dir);\n+\n+\trepo_clear(&submodule);\n+\tfree(gitdir);\n }\n \n-static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n+static void show_ce(struct repo *repo, struct dir_struct *dir,\n+\t\t    const struct cache_entry *ce, const char *fullname,\n+\t\t    const char *tag)\n {\n-\tstruct strbuf name = STRBUF_INIT;\n-\tint len = max_prefix_len;\n-\tif (super_prefix)\n-\t\tstrbuf_addstr(&name, super_prefix);\n-\tstrbuf_addstr(&name, ce->name);\n-\n-\tif (len > ce_namelen(ce))\n+\tif (max_prefix_len > strlen(fullname))\n \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n \n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t    submodule_path_match(&pathspec, name.buf, ps_matched)) {\n-\t\tshow_gitlink(ce);\n-\t} else if (match_pathspec(&pathspec, name.buf, name.len,\n-\t\t\t\t  len, ps_matched,\n+\t    submodule_path_match(&pathspec, fullname, ps_matched) &&\n+\t    is_submodule_active(repo, ce->name)) {\n+\t\tshow_submodule(repo, dir, ce->name);\n+\t} else if (match_pathspec(&pathspec, fullname, strlen(fullname),\n+\t\t\t\t  max_prefix_len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n \t\ttag = get_tag(ce, tag);\n \n-\t\tif (!show_stage) {\n-\t\t\tfputs(tag, stdout);\n-\t\t} else {\n+\t\tif (show_stage) {\n \t\t\tprintf(\"%s%06o %s %d\\t\",\n \t\t\t       tag,\n \t\t\t       ce->ce_mode,\n \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n \t\t\t       ce_stage(ce));\n+\t\t} else {\n+\t\t\tfputs(tag, stdout);\n \t\t}\n-\t\twrite_eolinfo(&the_index, ce, ce->name);\n-\t\twrite_name(ce->name);\n+\n+\t\twrite_eolinfo(repo->index, ce, fullname);\n+\t\twrite_name(fullname);\n \t\tprint_debug(ce);\n \t}\n-\n-\tstrbuf_release(&name);\n }\n \n static void show_ru_info(const struct index_state *istate)\n@@ -337,59 +282,80 @@ static void show_ru_info(const struct index_state *istate)\n }\n \n static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n-\t\t       const struct cache_entry *ce)\n+\t\t       const char *fullname, const struct cache_entry *ce)\n {\n \tint dtype = ce_to_dtype(ce);\n-\treturn is_excluded(dir, istate, ce->name, &dtype);\n+\treturn is_excluded(dir, istate, fullname, &dtype);\n }\n \n-static void show_files(struct index_state *istate, struct dir_struct *dir)\n+static void construct_fullname(struct strbuf *out, const struct repo *repo,\n+\t\t\t       const struct cache_entry *ce)\n+{\n+\tstrbuf_reset(out);\n+\tif (repo->submodule_prefix)\n+\t\tstrbuf_addstr(out, repo->submodule_prefix);\n+\tstrbuf_addstr(out, ce->name);\n+\n+}\n+\n+static void show_files(struct repo *repo, struct dir_struct *dir)\n {\n \tint i;\n+\tstruct strbuf fullname = STRBUF_INIT;\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others || show_killed) {\n \t\tif (!show_others)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n-\t\tfill_directory(dir, istate, &pathspec);\n+\t\tfill_directory(dir, repo->index, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(istate, dir);\n+\t\t\tshow_other_files(repo->index, dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(istate, dir);\n+\t\t\tshow_killed_files(repo->index, dir);\n \t}\n \tif (show_cached || show_stage) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-\t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged :\n-\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);\n+\t\t\tshow_ce(repo, dir, ce, fullname.buf,\n+\t\t\t\tce_stage(ce) ? tag_unmerged :\n+\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree :\n+\t\t\t\t tag_cached));\n \t\t}\n \t}\n \tif (show_deleted || show_modified) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n \t\t\tstruct stat st;\n \t\t\tint err;\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n \t\t\tif (ce_skip_worktree(ce))\n \t\t\t\tcontinue;\n-\t\t\terr = lstat(ce->name, &st);\n+\t\t\terr = lstat(fullname.buf, &st);\n \t\t\tif (show_deleted && err)\n-\t\t\t\tshow_ce_entry(tag_removed, ce);\n-\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n-\t\t\t\tshow_ce_entry(tag_modified, ce);\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed);\n+\t\t\tif (show_modified && ie_modified(repo->index, ce, &st, 0))\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified);\n \t\t}\n \t}\n+\n+\tstrbuf_release(&fullname);\n }\n \n /*\n@@ -544,7 +510,7 @@ static int option_parse_exclude_standard(const struct option *opt,\n int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n {\n \tint require_work_tree = 0, show_tag = 0, i;\n-\tconst char *max_prefix;\n+\tchar *max_prefix;\n \tstruct dir_struct dir;\n \tstruct exclude_list *el;\n \tstruct string_list exclude_list = STRING_LIST_INIT_NODUP;\n@@ -614,11 +580,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tprefix = cmd_prefix;\n \tif (prefix)\n \t\tprefix_len = strlen(prefix);\n-\tsuper_prefix = get_super_prefix();\n \tgit_config(git_default_config, NULL);\n \n-\tif (read_cache() < 0)\n-\t\tdie(\"index file corrupt\");\n+\trepo_read_index(&the_repository);\n \n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n \t\t\tls_files_usage, 0);\n@@ -650,12 +614,14 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (require_work_tree && !is_inside_work_tree())\n \t\tsetup_work_tree();\n \n-\tif (recurse_submodules)\n-\t\tcompile_submodule_options(argv, &dir, show_tag);\n+\tif (recurse_submodules) {\n+\t\trepo_read_gitmodules(&the_repository);\n+\t}\n \n \tif (recurse_submodules &&\n \t    (show_stage || show_deleted || show_others || show_unmerged ||\n-\t     show_killed || show_modified || show_resolve_undo || with_tree))\n+\t     show_killed || show_modified || show_resolve_undo || with_tree ||\n+\t     show_eol))\n \t\tdie(\"ls-files --recurse-submodules unsupported mode\");\n \n \tif (recurse_submodules && error_unmatch)\n@@ -669,7 +635,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t/*\n \t * Find common prefix for all pathspec's\n \t * This is used as a performance optimization which unfortunately cannot\n-\t * be done when recursing into submodules\n+\t * be done when recursing into submodules because when a pathspec is\n+\t * given which spans repository boundaries you can't simply remove the\n+\t * submodule entry because the pathspec may match something inside the\n+\t * submodule.\n \t */\n \tif (recurse_submodules)\n \t\tmax_prefix = NULL;\n@@ -677,7 +646,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_index(&the_index, max_prefix, max_prefix_len);\n+\tprune_index(the_repository.index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n@@ -698,11 +667,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n-\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n+\t\toverlay_tree_on_index(the_repository.index, with_tree, max_prefix);\n \t}\n-\tshow_files(&the_index, &dir);\n+\n+\tshow_files(&the_repository, &dir);\n+\n \tif (show_resolve_undo)\n-\t\tshow_ru_info(&the_index);\n+\t\tshow_ru_info(the_repository.index);\n \n \tif (ps_matched) {\n \t\tint bad;\ndiff --git a/git.c b/git.c\nindex 594436e43..16c6e325d 100644\n--- a/git.c\n+++ b/git.c\n@@ -442,7 +442,7 @@ static struct cmd_struct commands[] = {\n \t{ \"init-db\", cmd_init_db },\n \t{ \"interpret-trailers\", cmd_interpret_trailers, RUN_SETUP_GENTLY },\n \t{ \"log\", cmd_log, RUN_SETUP },\n-\t{ \"ls-files\", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"ls-files\", cmd_ls_files, RUN_SETUP },\n \t{ \"ls-remote\", cmd_ls_remote, RUN_SETUP_GENTLY },\n \t{ \"ls-tree\", cmd_ls_tree, RUN_SETUP },\n \t{ \"mailinfo\", cmd_mailinfo, RUN_SETUP_GENTLY },\ndiff --git a/repo.c b/repo.c\nindex 6f7b2015f..01001e577 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -154,6 +154,7 @@ int repo_init(struct repo *repo, const char *gitdir)\n \t}\n \n \trepo_set_gitdir(repo, resolved_gitdir);\n+\trepo_set_worktree(repo, gitdir);\n \n \t/* NEEDSWORK: Verify repository format version */\n \n@@ -169,6 +170,8 @@ void repo_clear(struct repo *repo)\n \trepo_clear_env(repo);\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n+\tfree(repo->submodule_prefix);\n+\trepo->submodule_prefix = NULL;\n \n \tif (repo->config) {\n \t\tgit_configset_clear(repo->config);\ndiff --git a/repo.h b/repo.h\nindex ad0184eaa..cb83f765b 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -14,6 +14,7 @@ struct repo {\n \tchar *graft_file;\n \tchar *namespace;\n \tchar *worktree;\n+\tchar *submodule_prefix;\n \n \t/* Subsystems */\n \t/*\ndiff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh\nindex ebb956fd1..318b5bce7 100755\n--- a/t/t3007-ls-files-recurse-submodules.sh\n+++ b/t/t3007-ls-files-recurse-submodules.sh\n@@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'inactive submodule' '\n+\ttest_when_finished \"git config --bool submodule.submodule.active true\" &&\n+\ttest_when_finished \"git -C submodule config --bool submodule.subsub.active true\" &&\n+\tgit config --bool submodule.submodule.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tgit config --bool submodule.submodule.active \"true\" &&\n+\tgit -C submodule config --bool submodule.subsub.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule/.gitmodules\n+\tsubmodule/c\n+\tsubmodule/f.TXT\n+\tsubmodule/g.txt\n+\tsubmodule/subsub\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success '--recurse-submodules and pathspecs' '\n \tcat >expect <<-\\EOF &&\n \th.txt\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321196","messageId":"20170531214417.38857-24-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 23/31] ls-files: convert show_killed_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:09Z","receivedAt":"2017-05-31T21:45:57Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 21 +++++++++++----------\n 1 file changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex c37e9de11..f9578cf9f 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -121,7 +121,8 @@ static void show_other_files(struct dir_struct *dir)\n \t}\n }\n \n-static void show_killed_files(struct dir_struct *dir)\n+static void show_killed_files(const struct index_state *istate,\n+\t\t\t      const struct dir_struct *dir)\n {\n \tint i;\n \tfor (i = 0; i < dir->nr; i++) {\n@@ -135,29 +136,29 @@ static void show_killed_files(struct dir_struct *dir)\n \t\t\t\t/* If ent->name is prefix of an entry in the\n \t\t\t\t * cache, it will be killed.\n \t\t\t\t */\n-\t\t\t\tpos = cache_name_pos(ent->name, ent->len);\n+\t\t\t\tpos = index_name_pos(istate, ent->name, ent->len);\n \t\t\t\tif (0 <= pos)\n \t\t\t\t\tdie(\"BUG: killed-file %.*s not found\",\n \t\t\t\t\t\tent->len, ent->name);\n \t\t\t\tpos = -pos - 1;\n-\t\t\t\twhile (pos < active_nr &&\n-\t\t\t\t       ce_stage(active_cache[pos]))\n+\t\t\t\twhile (pos < istate->cache_nr &&\n+\t\t\t\t       ce_stage(istate->cache[pos]))\n \t\t\t\t\tpos++; /* skip unmerged */\n-\t\t\t\tif (active_nr <= pos)\n+\t\t\t\tif (istate->cache_nr <= pos)\n \t\t\t\t\tbreak;\n \t\t\t\t/* pos points at a name immediately after\n \t\t\t\t * ent->name in the cache.  Does it expect\n \t\t\t\t * ent->name to be a directory?\n \t\t\t\t */\n-\t\t\t\tlen = ce_namelen(active_cache[pos]);\n+\t\t\t\tlen = ce_namelen(istate->cache[pos]);\n \t\t\t\tif ((ent->len < len) &&\n-\t\t\t\t    !strncmp(active_cache[pos]->name,\n+\t\t\t\t    !strncmp(istate->cache[pos]->name,\n \t\t\t\t\t     ent->name, ent->len) &&\n-\t\t\t\t    active_cache[pos]->name[ent->len] == '/')\n+\t\t\t\t    istate->cache[pos]->name[ent->len] == '/')\n \t\t\t\t\tkilled = 1;\n \t\t\t\tbreak;\n \t\t\t}\n-\t\t\tif (0 <= cache_name_pos(ent->name, sp - ent->name)) {\n+\t\t\tif (0 <= index_name_pos(istate, ent->name, sp - ent->name)) {\n \t\t\t\t/* If any of the leading directories in\n \t\t\t\t * ent->name is registered in the cache,\n \t\t\t\t * ent->name will be killed.\n@@ -338,7 +339,7 @@ static void show_files(struct dir_struct *dir)\n \t\tif (show_others)\n \t\t\tshow_other_files(dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(dir);\n+\t\t\tshow_killed_files(&the_index, dir);\n \t}\n \tif (show_cached || show_stage) {\n \t\tfor (i = 0; i < active_nr; i++) {\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321197","messageId":"20170531214417.38857-28-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 27/31] ls-files: convert prune_cache to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:13Z","receivedAt":"2017-05-31T21:46:02Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 289c6b2a5..e2d8fb7f6 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -381,30 +381,31 @@ static void show_files(struct dir_struct *dir)\n /*\n  * Prune the index to only contain stuff starting with \"prefix\"\n  */\n-static void prune_cache(const char *prefix, size_t prefixlen)\n+static void prune_index(struct index_state *istate,\n+\t\t\tconst char *prefix, size_t prefixlen)\n {\n \tint pos;\n \tunsigned int first, last;\n \n \tif (!prefix)\n \t\treturn;\n-\tpos = cache_name_pos(prefix, prefixlen);\n+\tpos = index_name_pos(istate, prefix, prefixlen);\n \tif (pos < 0)\n \t\tpos = -pos-1;\n \tfirst = pos;\n-\tlast = active_nr;\n+\tlast = istate->cache_nr;\n \twhile (last > first) {\n \t\tint next = (last + first) >> 1;\n-\t\tconst struct cache_entry *ce = active_cache[next];\n+\t\tconst struct cache_entry *ce = istate->cache[next];\n \t\tif (!strncmp(ce->name, prefix, prefixlen)) {\n \t\t\tfirst = next+1;\n \t\t\tcontinue;\n \t\t}\n \t\tlast = next;\n \t}\n-\tmemmove(active_cache, active_cache + pos,\n+\tmemmove(istate->cache, istate->cache + pos,\n \t\t(last - pos) * sizeof(struct cache_entry *));\n-\tactive_nr = last - pos;\n+\tistate->cache_nr = last - pos;\n }\n \n static int get_common_prefix_len(const char *common_prefix)\n@@ -662,7 +663,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_cache(max_prefix, max_prefix_len);\n+\tprune_index(&the_index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321198","messageId":"20170531214417.38857-27-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 26/31] ls-files: convert ce_excluded to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:12Z","receivedAt":"2017-05-31T21:46:04Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 9 +++++----\n 1 file changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 2838e2f75..289c6b2a5 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -322,10 +322,11 @@ static void show_ru_info(const struct index_state *istate)\n \t}\n }\n \n-static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce)\n+static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n+\t\t       const struct cache_entry *ce)\n {\n \tint dtype = ce_to_dtype(ce);\n-\treturn is_excluded(dir, &the_index, ce->name, &dtype);\n+\treturn is_excluded(dir, istate, ce->name, &dtype);\n }\n \n static void show_files(struct dir_struct *dir)\n@@ -346,7 +347,7 @@ static void show_files(struct dir_struct *dir)\n \t\tfor (i = 0; i < active_nr; i++) {\n \t\t\tconst struct cache_entry *ce = active_cache[i];\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, ce))\n+\t\t\t    !ce_excluded(dir, &the_index, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n@@ -362,7 +363,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\tstruct stat st;\n \t\t\tint err;\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, ce))\n+\t\t\t    !ce_excluded(dir, &the_index, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321199","messageId":"20170531214417.38857-18-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 17/31] convert: convert convert_to_git_filter_fd to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:44:03Z","receivedAt":"2017-05-31T21:46:05Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c   | 5 +++--\n convert.h   | 3 ++-\n sha1_file.c | 2 +-\n 3 files changed, 6 insertions(+), 4 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex ff3e72657..824b606fa 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1109,7 +1109,8 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \treturn ret | ident_to_git(path, src, len, dst, ca.ident);\n }\n \n-void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n+void convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t      const char *path, int fd, struct strbuf *dst,\n \t\t\t      enum safe_crlf checksafe)\n {\n \tstruct conv_attrs ca;\n@@ -1121,7 +1122,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n \tif (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))\n \t\tdie(\"%s: clean filter '%s' failed\", path, ca.drv->name);\n \n-\tcrlf_to_git(&the_index, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n+\tcrlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \ndiff --git a/convert.h b/convert.h\nindex 667b7dfe0..3a813a797 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -52,7 +52,8 @@ static inline int would_convert_to_git(const char *path)\n \treturn convert_to_git(path, NULL, 0, NULL, 0);\n }\n /* Precondition: would_convert_to_git_filter_fd(path) == true */\n-extern void convert_to_git_filter_fd(const char *path, int fd,\n+extern void convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t\t     const char *path, int fd,\n \t\t\t\t     struct strbuf *dst,\n \t\t\t\t     enum safe_crlf checksafe);\n extern int would_convert_to_git_filter_fd(const char *path);\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 44561e0b9..80e9ef3bb 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -3581,7 +3581,7 @@ static int index_stream_convert_blob(unsigned char *sha1, int fd,\n \tassert(path);\n \tassert(would_convert_to_git_filter_fd(path));\n \n-\tconvert_to_git_filter_fd(path, fd, &sbuf,\n+\tconvert_to_git_filter_fd(&the_index, path, fd, &sbuf,\n \t\t\t\t write_object ? safe_crlf : SAFE_CRLF_FALSE);\n \n \tif (write_object)\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321200","messageId":"20170531214417.38857-11-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 10/31] config: migrate the_configset to the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:56Z","receivedAt":"2017-05-31T21:46:17Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate the default config to be stored within 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n config.c | 185 ++++++++++++++++++++++++++++++++++++++-------------------------\n config.h |   1 +\n repo.c   |  21 ++++++++\n repo.h   |  11 ++++\n 4 files changed, 146 insertions(+), 72 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex ff09b27b8..930333e89 100644\n--- a/config.c\n+++ b/config.c\n@@ -7,6 +7,7 @@\n  */\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"repo.h\"\n #include \"lockfile.h\"\n #include \"exec_cmd.h\"\n #include \"strbuf.h\"\n@@ -72,13 +73,6 @@ static int core_compression_seen;\n static int pack_compression_seen;\n static int zlib_compression_seen;\n \n-/*\n- * Default config_set that contains key-value pairs from the usual set of config\n- * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG\n- * config file and the global /etc/gitconfig)\n- */\n-static struct config_set the_config_set;\n-\n static int config_file_fgetc(struct config_source *conf)\n {\n \treturn getc_unlocked(conf->u.file);\n@@ -1606,28 +1600,6 @@ int git_config_with_options(config_fn_t fn, void *data,\n \treturn do_git_config_sequence(opts, fn, data);\n }\n \n-static void git_config_raw(config_fn_t fn, void *data)\n-{\n-\tstruct config_options opts = {0};\n-\n-\topts.respect_includes = 1;\n-\tif (have_git_dir())\n-\t\topts.git_dir = get_git_common_dir();\n-\tif (git_config_with_options(fn, data, NULL, &opts) < 0)\n-\t\t/*\n-\t\t * git_config_with_options() normally returns only\n-\t\t * zero, as most errors are fatal, and\n-\t\t * non-fatal potential errors are guarded by \"if\"\n-\t\t * statements that are entered only when no error is\n-\t\t * possible.\n-\t\t *\n-\t\t * If we ever encounter a non-fatal error, it means\n-\t\t * something went really wrong and we should stop\n-\t\t * immediately.\n-\t\t */\n-\t\tdie(_(\"unknown error occurred while reading the configuration files\"));\n-}\n-\n static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)\n {\n \tint i, value_index;\n@@ -1676,14 +1648,6 @@ void read_early_config(config_fn_t cb, void *data)\n \tstrbuf_release(&buf);\n }\n \n-static void git_config_check_init(void);\n-\n-void git_config(config_fn_t fn, void *data)\n-{\n-\tgit_config_check_init();\n-\tconfigset_iter(&the_config_set, fn, data);\n-}\n-\n static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)\n {\n \tstruct config_set_element k;\n@@ -1782,7 +1746,7 @@ void git_configset_clear(struct config_set *cs)\n \tcs->list.items = NULL;\n }\n \n-static int config_set_callback(const char *key, const char *value, void *cb)\n+int config_set_callback(const char *key, const char *value, void *cb)\n {\n \tstruct config_set *cs = cb;\n \tconfigset_add_value(cs, key, value);\n@@ -1893,87 +1857,164 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha\n \t\treturn 1;\n }\n \n-static void git_config_check_init(void)\n+/* Functions use to read configuration from a repository */\n+static void git_config_check_init(struct repo *repository)\n {\n-\tif (the_config_set.hash_initialized)\n+\tif (repository->config && repository->config->hash_initialized)\n \t\treturn;\n-\tgit_configset_init(&the_config_set);\n-\tgit_config_raw(config_set_callback, &the_config_set);\n+\trepo_read_config(repository);\n }\n \n-void git_config_clear(void)\n+static void repo_config_clear(struct repo *repository)\n {\n-\tif (!the_config_set.hash_initialized)\n+\tif (!repository->config || !repository->config->hash_initialized)\n \t\treturn;\n-\tgit_configset_clear(&the_config_set);\n+\tgit_configset_clear(repository->config);\n }\n \n-int git_config_get_value(const char *key, const char **value)\n+static void repo_config(struct repo *repository, config_fn_t fn, void *data)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_value(&the_config_set, key, value);\n+\tgit_config_check_init(repository);\n+\tconfigset_iter(repository->config, fn, data);\n }\n \n-const struct string_list *git_config_get_value_multi(const char *key)\n+static int repo_config_get_value(struct repo *repository,\n+\t\t\t\t const char *key, const char **value)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_value_multi(&the_config_set, key);\n+\tgit_config_check_init(repository);\n+\treturn git_configset_get_value(repository->config, key, value);\n }\n \n-int git_config_get_string_const(const char *key, const char **dest)\n+static const struct string_list *repo_config_get_value_multi(struct repo *repository,\n+\t\t\t\t\t\t\t     const char *key)\n+{\n+\tgit_config_check_init(repository);\n+\treturn git_configset_get_value_multi(repository->config, key);\n+}\n+\n+static int repo_config_get_string_const(struct repo *repository,\n+\t\t\t\t\tconst char *key, const char **dest)\n {\n \tint ret;\n-\tgit_config_check_init();\n-\tret = git_configset_get_string_const(&the_config_set, key, dest);\n+\tgit_config_check_init(repository);\n+\tret = git_configset_get_string_const(repository->config, key, dest);\n \tif (ret < 0)\n \t\tgit_die_config(key, NULL);\n \treturn ret;\n }\n \n+static int repo_config_get_string(struct repo *repository,\n+\t\t\t\t  const char *key, char **dest)\n+{\n+\tgit_config_check_init(repository);\n+\treturn repo_config_get_string_const(repository, key, (const char **)dest);\n+}\n+\n+static int repo_config_get_int(struct repo *repository,\n+\t\t\t       const char *key, int *dest)\n+{\n+\tgit_config_check_init(repository);\n+\treturn git_configset_get_int(repository->config, key, dest);\n+}\n+\n+static int repo_config_get_ulong(struct repo *repository,\n+\t\t\t\tconst char *key, unsigned long *dest)\n+{\n+\tgit_config_check_init(repository);\n+\treturn git_configset_get_ulong(repository->config, key, dest);\n+}\n+\n+static int repo_config_get_bool(struct repo *repository,\n+\t\t\t\tconst char *key, int *dest)\n+{\n+\tgit_config_check_init(repository);\n+\treturn git_configset_get_bool(repository->config, key, dest);\n+}\n+\n+static int repo_config_get_bool_or_int(struct repo *repository,\n+\t\t\t\t       const char *key, int *is_bool, int *dest)\n+{\n+\tgit_config_check_init(repository);\n+\treturn git_configset_get_bool_or_int(repository->config, key, is_bool, dest);\n+}\n+\n+static int repo_config_get_maybe_bool(struct repo *repository,\n+\t\t\t\t      const char *key, int *dest)\n+{\n+\tgit_config_check_init(repository);\n+\treturn git_configset_get_maybe_bool(repository->config, key, dest);\n+}\n+\n+static int repo_config_get_pathname(struct repo *repository,\n+\t\t\t\t    const char *key, const char **dest)\n+{\n+\tint ret;\n+\tgit_config_check_init(repository);\n+\tret = git_configset_get_pathname(repository->config, key, dest);\n+\tif (ret < 0)\n+\t\tgit_die_config(key, NULL);\n+\treturn ret;\n+}\n+\n+/* Functions used historically to read configuration from 'the_repository' */\n+void git_config(config_fn_t fn, void *data)\n+{\n+\trepo_config(&the_repository, fn, data);\n+}\n+\n+void git_config_clear(void)\n+{\n+\trepo_config_clear(&the_repository);\n+}\n+\n+int git_config_get_value(const char *key, const char **value)\n+{\n+\treturn repo_config_get_value(&the_repository, key, value);\n+}\n+\n+const struct string_list *git_config_get_value_multi(const char *key)\n+{\n+\treturn repo_config_get_value_multi(&the_repository, key);\n+}\n+\n+int git_config_get_string_const(const char *key, const char **dest)\n+{\n+\treturn repo_config_get_string_const(&the_repository, key, dest);\n+}\n+\n int git_config_get_string(const char *key, char **dest)\n {\n-\tgit_config_check_init();\n-\treturn git_config_get_string_const(key, (const char **)dest);\n+\treturn repo_config_get_string(&the_repository, key, dest);\n }\n \n int git_config_get_int(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_int(&the_config_set, key, dest);\n+\treturn repo_config_get_int(&the_repository, key, dest);\n }\n \n int git_config_get_ulong(const char *key, unsigned long *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_ulong(&the_config_set, key, dest);\n+\treturn repo_config_get_ulong(&the_repository, key, dest);\n }\n \n int git_config_get_bool(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_bool(&the_config_set, key, dest);\n+\treturn repo_config_get_bool(&the_repository, key, dest);\n }\n \n int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);\n+\treturn repo_config_get_bool_or_int(&the_repository, key, is_bool, dest);\n }\n \n int git_config_get_maybe_bool(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_maybe_bool(&the_config_set, key, dest);\n+\treturn repo_config_get_maybe_bool(&the_repository, key, dest);\n }\n \n int git_config_get_pathname(const char *key, const char **dest)\n {\n-\tint ret;\n-\tgit_config_check_init();\n-\tret = git_configset_get_pathname(&the_config_set, key, dest);\n-\tif (ret < 0)\n-\t\tgit_die_config(key, NULL);\n-\treturn ret;\n+\treturn repo_config_get_pathname(&the_repository, key, dest);\n }\n \n int git_config_get_expiry(const char *key, const char **output)\ndiff --git a/config.h b/config.h\nindex f7f8b66c5..4cd9e2915 100644\n--- a/config.h\n+++ b/config.h\n@@ -149,6 +149,7 @@ struct config_set {\n };\n \n extern void git_configset_init(struct config_set *cs);\n+extern int config_set_callback(const char *key, const char *value, void *cb);\n extern int git_configset_add_file(struct config_set *cs, const char *filename);\n extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);\n extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);\ndiff --git a/repo.c b/repo.c\nindex 789ffdd78..c67cad5a2 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"repo.h\"\n+#include \"config.h\"\n \n /*\n  * This may be the wrong place for this.\n@@ -89,6 +90,20 @@ void repo_set_worktree(struct repo *repo, const char *path)\n \trepo->worktree = real_pathdup(path, 1);\n }\n \n+void repo_read_config(struct repo *repo)\n+{\n+\tstruct config_options opts = { 1, repo->commondir };\n+\n+\tif (!repo->config)\n+\t\trepo->config = xcalloc(1, sizeof(struct config_set));\n+\telse\n+\t\tgit_configset_clear(repo->config);\n+\n+\tgit_configset_init(repo->config);\n+\n+\tgit_config_with_options(config_set_callback, repo->config, NULL, &opts);\n+}\n+\n int repo_init(struct repo *repo, const char *gitdir)\n {\n \tint error = 0;\n@@ -128,4 +143,10 @@ void repo_clear(struct repo *repo)\n \trepo_clear_env(repo);\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n+\n+\tif (repo->config) {\n+\t\tgit_configset_clear(repo->config);\n+\t\tfree(repo->config);\n+\t\trepo->config = NULL;\n+\t}\n }\ndiff --git a/repo.h b/repo.h\nindex 95d021049..284452832 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -1,6 +1,8 @@\n #ifndef REPO_H\n #define REPO_H\n \n+struct config_set;\n+\n struct repo {\n \t/* Environment */\n \tchar *gitdir;\n@@ -11,6 +13,14 @@ struct repo {\n \tchar *namespace;\n \tchar *worktree;\n \n+\t/* Subsystems */\n+\t/*\n+\t * Repository's config which contains key-value pairs from the usual\n+\t * set of config config files (i.e repo specific .git/config, user wide\n+\t * ~/.gitconfig, XDG config file and the global /etc/gitconfig)\n+\t */\n+\tstruct config_set *config;\n+\n \t/* Configurations */\n \tunsigned ignore_env:1;\n \t/* Indicates if a repository has a different 'commondir' from 'gitdir' */\n@@ -21,6 +31,7 @@ extern struct repo the_repository;\n \n extern void repo_set_gitdir(struct repo *repo, const char *path);\n extern void repo_set_worktree(struct repo *repo, const char *path);\n+extern void repo_read_config(struct repo *repo);\n extern int repo_init(struct repo *repo, const char *path);\n extern void repo_clear(struct repo *repo);\n \n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321201","messageId":"20170531214417.38857-5-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 04/31] setup: don't perform lazy initialization of repository state","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:50Z","receivedAt":"2017-05-31T21:46:19Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Under some circumstances (bogus GIT_DIR value or the discovered gitdir\nis '.git') 'setup_git_directory()' won't initialize key repository\nstate.  This leads to inconsistent state after running the setup code.\nTo account for this inconsistent state, lazy initialization is done once\na caller asks for the repository's gitdir or some other piece of\nrepository state.  This is confusing and can be error prone.\n\nInstead let's tighten the expected outcome of 'setup_git_directory()'\nand ensure that it initializes repository state in all cases that would\nhave been handled by lazy initialization.\n\nThis also lets us drop the requirement to have 'have_git_dir()' check if\nthe environment variable GIT_DIR was set as that will be handled by the\nend of the setup code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h       |  2 ++\n environment.c | 17 ++++++++---------\n setup.c       | 14 ++++++++++++++\n 3 files changed, 24 insertions(+), 9 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 272f8e021..d41aab82f 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -462,6 +462,8 @@ static inline enum object_type object_type(unsigned int mode)\n  */\n extern const char * const local_repo_env[];\n \n+extern void setup_git_env(void);\n+\n /*\n  * Returns true iff we have a configured git repository (either via\n  * setup_git_directory, or in the environment via $GIT_DIR).\ndiff --git a/environment.c b/environment.c\nindex d40b21fb7..a73b08f5d 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -160,7 +160,7 @@ static char *git_path_from_env(const char *envvar, const char *git_dir,\n \treturn xstrdup(value);\n }\n \n-static void setup_git_env(void)\n+void setup_git_env(void)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *gitfile;\n@@ -205,28 +205,27 @@ int is_bare_repository(void)\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n-\t\t|| git_dir\n-\t\t|| getenv(GIT_DIR_ENVIRONMENT);\n+\t\t|| git_dir;\n }\n \n const char *get_git_dir(void)\n {\n \tif (!git_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_dir;\n }\n \n const char *get_git_common_dir(void)\n {\n \tif (!git_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_common_dir;\n }\n \n const char *get_git_namespace(void)\n {\n \tif (!namespace)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn namespace;\n }\n \n@@ -276,7 +275,7 @@ const char *get_git_work_tree(void)\n char *get_object_directory(void)\n {\n \tif (!git_object_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_object_dir;\n }\n \n@@ -316,14 +315,14 @@ int odb_pack_keep(const char *name)\n char *get_index_file(void)\n {\n \tif (!git_index_file)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_index_file;\n }\n \n char *get_graft_file(void)\n {\n \tif (!git_graft_file)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_graft_file;\n }\n \ndiff --git a/setup.c b/setup.c\nindex e99a82cbe..b2e05145c 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1063,6 +1063,20 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \tstartup_info->have_repository = !nongit_ok || !*nongit_ok;\n \tstartup_info->prefix = prefix;\n \n+\t/*\n+\t * Not all paths through the setup code will call 'set_git_dir()' (which\n+\t * directly sets up the environment) so in order to guarantee that the\n+\t * environment is in a consistent state after setup, explicitly setup\n+\t * the environment if we have a repository.\n+\t *\n+\t * NEEDSWORK: currently we allow bogus GIT_DIR values to be set in some\n+\t * code paths so we also need to explicitly setup the environment if\n+\t * the user has set GIT_DIR.  It may be beneficial to disallow bogus\n+\t * GIT_DIR values at some point in the future.\n+\t */\n+\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT))\n+\t\tsetup_git_env();\n+\n \tstrbuf_release(&dir);\n \tstrbuf_release(&gitdir);\n \n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321202","messageId":"20170531214417.38857-10-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH 09/31] setup: add comment indicating a hack","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T21:43:55Z","receivedAt":"2017-05-31T21:46:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"'GIT_TOPLEVEL_PREFIX_ENVIRONMENT' was added in (b58a68c1c setup: allow\nfor prefix to be passed to git commands) to aid in fixing a bug where\n'ls-files' and 'grep' were not able to properly recurse when called from\nwithin a subdirectory.  Add a 'NEEDSWORK' comment indicating that this\nenvvar should be removed once 'ls-files' and 'grep' can recurse\nin-process.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n setup.c | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/setup.c b/setup.c\nindex dba3abd00..c3d21345d 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1057,6 +1057,12 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t\tdie(\"BUG: unhandled setup_git_directory_1() result\");\n \t}\n \n+\t/*\n+\t * NEEDSWORK: This was a hack in order to get ls-files and grep to have\n+\t * properly formated output when recursing submodules.  Once ls-files\n+\t * and grep have been changed to perform this recursing in-process this\n+\t * needs to be removed.\n+\t */\n \tenv_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT);\n \tif (env_prefix)\n \t\tprefix = env_prefix;\n-- \n2.13.0.506.g27d5fe0cd-goog\n\n"},{"id":"321215","messageId":"CAGZ79kYMs6XS8kcoWVZDes7W_J1B86dYm-8rhkJPzUmoqjyTng@mail.gmail.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"Re: [PATCH 00/31] repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-31T22:56:14Z","receivedAt":"2017-05-31T22:56:19Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> Given the vast interest expressed when I sent out my RFC series I decided it\n> would be worth it to invest more time to making a repository object a reality.\n>\n> This series is an extension of the last series I sent out (in that ls-files is\n> converted to working on submodules in-process using repository objects instead\n> of spawning a child process to do the work).  The big difference from the RFC\n> series is that I went through and did the work to migrate key repository state\n> from global variables in 'environment.c' to being stored in a repository object\n> itself.  I migrated the bits of state that seemed reasonable for this series,\n> there is still a lot of global state which could be migrated in the future.\n>\n> I do think that we need to be slightly cautious about moving global state into\n> the repository object though, I don't want 'struct repo' to simply become a\n> kitchen sink where everything gets dumped.  But this is just a warning for the\n> future.\n\nOr in other words:\nYou want to have another struct e.g. 'the_command_line_arguments',\nwhich would carry the verbosity/color options for example as they are\nnot related to a repo object, but to the current command being run?\n\n> Since this is a v1 I'm fairly certain that it still has a lot of rough edges\n> (like I think I need to write better commit messages, and we should probably\n> have more comments documenting object fields/contract) but I want to get the\n> review process started sooner rather than later since I'm sure people will have\n> opinions (e.g. should it be called 'struct repo' or 'struct repository'?!).\n\nIMHO this is the most obvious, but bikesheddable part of the series. ;)\nKeep it short as everyone knows what a 'repo' is.\n"},{"id":"321217","messageId":"20170531230122.GA43421@google.com","threadId":"46082","inReplyTo":"CAGZ79kYMs6XS8kcoWVZDes7W_J1B86dYm-8rhkJPzUmoqjyTng@mail.gmail.com","subject":"Re: [PATCH 00/31] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-31T23:01:22Z","receivedAt":"2017-05-31T23:01:31Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 05/31, Stefan Beller wrote:\n> On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> > Given the vast interest expressed when I sent out my RFC series I decided it\n> > would be worth it to invest more time to making a repository object a reality.\n> >\n> > This series is an extension of the last series I sent out (in that ls-files is\n> > converted to working on submodules in-process using repository objects instead\n> > of spawning a child process to do the work).  The big difference from the RFC\n> > series is that I went through and did the work to migrate key repository state\n> > from global variables in 'environment.c' to being stored in a repository object\n> > itself.  I migrated the bits of state that seemed reasonable for this series,\n> > there is still a lot of global state which could be migrated in the future.\n> >\n> > I do think that we need to be slightly cautious about moving global state into\n> > the repository object though, I don't want 'struct repo' to simply become a\n> > kitchen sink where everything gets dumped.  But this is just a warning for the\n> > future.\n> \n> Or in other words:\n> You want to have another struct e.g. 'the_command_line_arguments',\n> which would carry the verbosity/color options for example as they are\n> not related to a repo object, but to the current command being run?\n\nYes exactly.  Library code that needs to operate on a repository would\nthen be able to take arguments like:\n\n  some_library_function(struct repo *repo, struct lib_opts *ops)\n\nMuch like how the grep machinery takes a grep_opts struct.\n\n> \n> > Since this is a v1 I'm fairly certain that it still has a lot of rough edges\n> > (like I think I need to write better commit messages, and we should probably\n> > have more comments documenting object fields/contract) but I want to get the\n> > review process started sooner rather than later since I'm sure people will have\n> > opinions (e.g. should it be called 'struct repo' or 'struct repository'?!).\n> \n> IMHO this is the most obvious, but bikesheddable part of the series. ;)\n\nI know, that's why I mentioned it ;)\n\n> Keep it short as everyone knows what a 'repo' is.\n\n-- \nBrandon Williams\n"},{"id":"321299","messageId":"20170601181059.GB127481@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"Re: [PATCH 00/31] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-01T18:10:59Z","receivedAt":"2017-06-01T18:11:08Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 05/31, Brandon Williams wrote:\n> Given the vast interest expressed when I sent out my RFC series I decided it\n> would be worth it to invest more time to making a repository object a reality.\n> \n> This series is an extension of the last series I sent out (in that ls-files is\n> converted to working on submodules in-process using repository objects instead\n> of spawning a child process to do the work).  The big difference from the RFC\n> series is that I went through and did the work to migrate key repository state\n> from global variables in 'environment.c' to being stored in a repository object\n> itself.  I migrated the bits of state that seemed reasonable for this series,\n> there is still a lot of global state which could be migrated in the future.\n> \n> I do think that we need to be slightly cautious about moving global state into\n> the repository object though, I don't want 'struct repo' to simply become a\n> kitchen sink where everything gets dumped.  But this is just a warning for the\n> future.\n> \n> Since this is a v1 I'm fairly certain that it still has a lot of rough edges\n> (like I think I need to write better commit messages, and we should probably\n> have more comments documenting object fields/contract) but I want to get the\n> review process started sooner rather than later since I'm sure people will have\n> opinions (e.g. should it be called 'struct repo' or 'struct repository'?!).\n> \n> So here it is!  Thank you so much for taking the time review this, any and all\n> comments would be appreciated.\n> \n> - Brandon\n> \n> Patches [01-14] -> Introducing the Repository object and migrating some state\n> \t\t   to be stored in 'the_repository'.\n> \n> Patches [15-31] -> Converting ls-files to use 'struct repo' in order to recurse\n> \t\t   submodules in-process.\n\nFor those who don't like reviewing patches in email form, you can find\nthis series at:\nhttps://github.com/bmwill/git/tree/repository-object \n\n-- \nBrandon Williams\n"},{"id":"321309","messageId":"CAGZ79kZJF9iDsVgyi-hSKb6N8w0uhVCU4W-r89F0eRJPXe_4Og@mail.gmail.com","threadId":"46082","inReplyTo":"20170601181059.GB127481@google.com","subject":"Re: [PATCH 00/31] repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T18:28:46Z","receivedAt":"2017-06-01T18:28:58Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, Jun 1, 2017 at 11:10 AM, Brandon Williams <bmwill@google.com> wrote:\n>\n> For those who don't like reviewing patches in email form, you can find\n> this series at:\n> https://github.com/bmwill/git/tree/repository-object\n\nI was just asking Brandon for a remote to pull these patches from.\n\nAs I was looking at the very first patch, I'd like to lobby for trying out\norigin/sb/diff-color-moved, as it will tell you about code movements. :)\n\nThanks,\nStefan\n"},{"id":"321316","messageId":"CAGZ79kafXpn+BXdMOVOPSX7eaFgcWBUULGR_PBXpMhjKjLEM-A@mail.gmail.com","threadId":"46082","inReplyTo":"20170531214417.38857-5-bmwill@google.com","subject":"Re: [PATCH 04/31] setup: don't perform lazy initialization of repository state","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T19:23:25Z","receivedAt":"2017-06-01T19:23:31Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> Under some circumstances (bogus GIT_DIR value or the discovered gitdir\n> is '.git') 'setup_git_directory()' won't initialize key repository\n> state.  This leads to inconsistent state after running the setup code.\n> To account for this inconsistent state, lazy initialization is done once\n> a caller asks for the repository's gitdir or some other piece of\n> repository state.  This is confusing and can be error prone.\n>\n> Instead let's tighten the expected outcome of 'setup_git_directory()'\n> and ensure that it initializes repository state in all cases that would\n> have been handled by lazy initialization.\n\nLazy init is usually there for a reason. (As in: it took too long to perform\nit at all times, so it has been optimized to only perform the init when needed).\n\nReading the code of setup_git_env, this is the additional cost incurred to us:\n* reading a file ('git_dir' to determine if it is a gitlink or actual directory)\n* reading another file to determine the commondir\n* some environment variable reading (<10).\n  Reading the environment should be fast, though in the implementation\n  of libc that I just looked up, it is still a linear search, so O(n) with n the\n  number of environment variables. (No actual syscalls though.)\n\nI would think that this is ok as it incurs not much cost. Maybe the\nlazyloading implementation was just a habit of the contributors at the time.\n\n\n>  const char *get_git_dir(void)\n>  {\n>         if (!git_dir)\n> -               setup_git_env();\n\nNEEDSWORK: eventually (say after release 2.16)\nwe can remove all these\n\n    if (!git_dir)\n        BUG(...);\n\ncalls. I will read on, as maybe this series touches\nthis further\n"},{"id":"321317","messageId":"CAGZ79kZF3mk40P1rRvV57X=JWveNoCmdvKmkUO=fo8Ts=BkZrA@mail.gmail.com","threadId":"46082","inReplyTo":"20170531214417.38857-6-bmwill@google.com","subject":"Re: [PATCH 05/31] environment: remove namespace_len variable","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T19:28:31Z","receivedAt":"2017-06-01T19:28:37Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> Use 'skip_prefix' instead of 'starts_with' so that we can drop the need\n> to keep around 'namespace_len'.\n\nLooks correct.\n\nPerformance wise:\nThe strip_namespace function is only called from {receive/upload}-pack\nand http-backend, so all network operations, whose actual operations\nshould far outweight the tiny CPU saving that this reverts.\nWe should be fine?\n\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  environment.c | 9 ++++-----\n>  1 file changed, 4 insertions(+), 5 deletions(-)\n>\n> diff --git a/environment.c b/environment.c\n> index a73b08f5d..e035f6372 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -98,7 +98,6 @@ char *git_work_tree_cfg;\n>  static char *work_tree;\n>\n>  static const char *namespace;\n> -static size_t namespace_len;\n>\n>  static const char *super_prefix;\n>\n> @@ -190,7 +189,6 @@ void setup_git_env(void)\n>         git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base\n>                                                           : \"refs/replace/\");\n>         namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));\n> -       namespace_len = strlen(namespace);\n>         shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);\n>         if (shallow_file)\n>                 set_alternate_shallow_file(shallow_file, 0);\n> @@ -231,9 +229,10 @@ const char *get_git_namespace(void)\n>\n>  const char *strip_namespace(const char *namespaced_ref)\n>  {\n> -       if (!starts_with(namespaced_ref, get_git_namespace()))\n> -               return NULL;\n> -       return namespaced_ref + namespace_len;\n> +       const char *out;\n> +       if (skip_prefix(namespaced_ref, get_git_namespace(), &out))\n> +               return out;\n> +       return NULL;\n>  }\n>\n>  const char *get_super_prefix(void)\n> --\n> 2.13.0.506.g27d5fe0cd-goog\n>\n"},{"id":"321320","messageId":"CAGZ79kbqsvuBG21teO2kT=H6G-xP0wJbd0f0BTjd9obRMSaxGQ@mail.gmail.com","threadId":"46082","inReplyTo":"20170531214417.38857-7-bmwill@google.com","subject":"Re: [PATCH 06/31] repo: introduce the repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T19:53:31Z","receivedAt":"2017-06-01T19:53:37Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> Introduce the repository object 'struct repo' which can be used hold all\n> state pertaining to a git repository.\n>\n> The aim of object-ifying the repository is to (1) make the code base\n> more readable and easier to reason about and (2) allow for working on\n> multiple repositories, specifically submodules, within the same process.\n>\n> TODO: Add more motivating points for adding a repository object?\n\nYes please (or delete this line).\nhttps://public-inbox.org/git/alpine.DEB.2.21.1.1705221501540.3610@virtualbox/\n\n> +++ b/repo.c\n> @@ -0,0 +1,124 @@\n> +#include \"cache.h\"\n> +#include \"repo.h\"\n> +\n> +/*\n> + * This may be the wrong place for this.\n> + * It may be better to go in env.c or setup for the time being?\n\nIn env.c we say:\n/*\n * We put all the git config variables in this same object\n * file, so that programs can link against the config parser\n * without having to link against all the rest of git.\n *\n * In particular, no need to bring in libz etc unless needed,\n * even if you might want to know where the git directory etc\n * are.\n */\n\nAnd setup.c only has a few variables that matter there locally.\nSo I would think having 'the_repository' in repo.c is acceptable.\n\n> + */\n> +struct repo the_repository;\n> +\n> +static char *git_path_from_env(const char *envvar, const char *git_dir,\n> +                              const char *path, int fromenv)\n> +{\n> +       if (fromenv) {\n> +               const char *value = getenv(envvar);\n> +               if (value)\n> +                       return xstrdup(value);\n> +       }\n> +\n> +       return xstrfmt(\"%s/%s\", git_dir, path);\n> +}\n> +\n> +static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)\n> +{\n> +       if (fromenv) {\n> +               const char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n> +               if (value) {\n> +                       strbuf_addstr(sb, value);\n> +                       return 1;\n> +               }\n> +       }\n> +\n> +       return get_common_dir_noenv(sb, gitdir);\n> +}\n> +\n> +/* called after setting gitdir */\n> +static void repo_setup_env(struct repo *repo)\n> +{\n> +       struct strbuf sb = STRBUF_INIT;\n> +\n> +       if (!repo->gitdir)\n> +               BUG(\"gitdir wasn't set before setting up the environment\");\n> +\n> +       repo->different_commondir = find_common_dir(&sb, repo->gitdir,\n> +                                                   !repo->ignore_env);\n> +       repo->commondir = strbuf_detach(&sb, NULL);\n> +       repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,\n> +                                           \"objects\", !repo->ignore_env);\n> +       repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,\n> +                                            \"index\", !repo->ignore_env);\n> +       repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,\n> +                                            \"info/grafts\", !repo->ignore_env);\n> +       repo->namespace = expand_namespace(repo->ignore_env ? NULL :\n> +                                          getenv(GIT_NAMESPACE_ENVIRONMENT));\n> +}\n> +\n> +static void repo_clear_env(struct repo *repo)\n> +{\n> +       free(repo->gitdir);\n> +       repo->gitdir = NULL;\n> +       free(repo->commondir);\n> +       repo->commondir = NULL;\n> +       free(repo->objectdir);\n> +       repo->objectdir = NULL;\n> +       free(repo->index_file);\n> +       repo->index_file = NULL;\n> +       free(repo->graft_file);\n> +       repo->graft_file = NULL;\n> +       free(repo->namespace);\n> +       repo->namespace = NULL;\n\nI wonder if we can defer the NULL assignments to\nrepo_clear, where we would just do a\nmemset(repo, 0, sizeof(struct repo));\n\n> +\n> +       repo_set_gitdir(repo, resolved_gitdir);\n> +\n> +       /* NEEDSWORK: Verify repository format version */\n\nCare to elaborate on this? I do not understand why we would want\nto check the format version here?\n\n> +\n> +extern void repo_set_gitdir(struct repo *repo, const char *path);\n> +extern int repo_init(struct repo *repo, const char *path);\n> +extern void repo_clear(struct repo *repo);\n\nThe init and clear method seem obvious to me, but what do we need the\nrepo_set_gitdir for externally? I would assume the repo auto-discovers its\ngitdir on its own?\n"},{"id":"321322","messageId":"CA+P7+xpK8qmdBgvPd4f995=WG1p3Oa8YEXfwvGsNqtZZyFZ8Mw@mail.gmail.com","threadId":"46082","inReplyTo":"CAGZ79kZJF9iDsVgyi-hSKb6N8w0uhVCU4W-r89F0eRJPXe_4Og@mail.gmail.com","subject":"Re: [PATCH 00/31] repository object","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2017-06-01T20:03:31Z","receivedAt":"2017-06-01T20:03:58Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Thu, Jun 1, 2017 at 11:28 AM, Stefan Beller <sbeller@google.com> wrote:\n> On Thu, Jun 1, 2017 at 11:10 AM, Brandon Williams <bmwill@google.com> wrote:\n>>\n>> For those who don't like reviewing patches in email form, you can find\n>> this series at:\n>> https://github.com/bmwill/git/tree/repository-object\n>\n> I was just asking Brandon for a remote to pull these patches from.\n>\n> As I was looking at the very first patch, I'd like to lobby for trying out\n> origin/sb/diff-color-moved, as it will tell you about code movements. :)\n>\n> Thanks,\n> Stefan\n\nYep, I'll be doing so.\n\nThanks,\nJake\n"},{"id":"321323","messageId":"CAGZ79kY4iLWuCrPVA6mo6BbgwoF_-wyP_=ju5Fs0+n8cTifb=Q@mail.gmail.com","threadId":"46082","inReplyTo":"20170531214417.38857-32-bmwill@google.com","subject":"Re: [PATCH 31/31] ls-files: use repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T20:36:24Z","receivedAt":"2017-06-01T20:36:30Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, May 31, 2017 at 2:44 PM, Brandon Williams <bmwill@google.com> wrote:\n> Convert ls-files to use a repository struct and recurse submodules\n> inprocess.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n\n\n> +static void show_submodule(const struct repo *superproject,\n> +                          struct dir_struct *dir, const char *path)\n>  {\n> +       struct repo submodule;\n> +       char *gitdir = mkpathdup(\"%s/%s\", superproject->worktree, path);\n> +       repo_init(&submodule, gitdir);\n> +\n> +       repo_read_index(&submodule);\n> +       repo_read_gitmodules(&submodule);\n> +\n> +       if (superproject->submodule_prefix)\n> +               submodule.submodule_prefix = xstrfmt(\"%s%s/\", superproject->submodule_prefix, path);\n> +       else\n> +               submodule.submodule_prefix = xstrfmt(\"%s/\", path);\n> +       show_files(&submodule, dir);\n> +\n> +       repo_clear(&submodule);\n> +       free(gitdir);\n>  }\n\nI like how it seems easy now to do work in another repository. :)\n\n> -       { \"ls-files\", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n> +       { \"ls-files\", cmd_ls_files, RUN_SETUP },\n\nWith this step, we can get rid of SUPPORT_SUPER_PREFIX eventually.\n\nI do not have comments on the patches in the middle, but they\ncleared up some of the questions that I asked in the early patches.\n\nThanks,\nStefan\n"},{"id":"321328","messageId":"20170601210911.GA159608@google.com","threadId":"46082","inReplyTo":"CAGZ79kZF3mk40P1rRvV57X=JWveNoCmdvKmkUO=fo8Ts=BkZrA@mail.gmail.com","subject":"Re: [PATCH 05/31] environment: remove namespace_len variable","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-01T21:09:11Z","receivedAt":"2017-06-01T21:09:19Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/01, Stefan Beller wrote:\n> On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> > Use 'skip_prefix' instead of 'starts_with' so that we can drop the need\n> > to keep around 'namespace_len'.\n> \n> Looks correct.\n> \n> Performance wise:\n> The strip_namespace function is only called from {receive/upload}-pack\n> and http-backend, so all network operations, whose actual operations\n> should far outweight the tiny CPU saving that this reverts.\n> We should be fine?\n\nActually there should be zero performance degradation with this change\n(maybe a very small improvement) because both functions need to do a\nchar by char comparison, just skip_prefix returns a pointer into the\nstring with the prefix already stripped.  So no need to do a strlen()\ncalculation on 'namespace' as well as no additon operation adding\n'namespace_len' to 'namespaced_ref'.\n\n> \n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  environment.c | 9 ++++-----\n> >  1 file changed, 4 insertions(+), 5 deletions(-)\n> >\n> > diff --git a/environment.c b/environment.c\n> > index a73b08f5d..e035f6372 100644\n> > --- a/environment.c\n> > +++ b/environment.c\n> > @@ -98,7 +98,6 @@ char *git_work_tree_cfg;\n> >  static char *work_tree;\n> >\n> >  static const char *namespace;\n> > -static size_t namespace_len;\n> >\n> >  static const char *super_prefix;\n> >\n> > @@ -190,7 +189,6 @@ void setup_git_env(void)\n> >         git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base\n> >                                                           : \"refs/replace/\");\n> >         namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));\n> > -       namespace_len = strlen(namespace);\n> >         shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);\n> >         if (shallow_file)\n> >                 set_alternate_shallow_file(shallow_file, 0);\n> > @@ -231,9 +229,10 @@ const char *get_git_namespace(void)\n> >\n> >  const char *strip_namespace(const char *namespaced_ref)\n> >  {\n> > -       if (!starts_with(namespaced_ref, get_git_namespace()))\n> > -               return NULL;\n> > -       return namespaced_ref + namespace_len;\n> > +       const char *out;\n> > +       if (skip_prefix(namespaced_ref, get_git_namespace(), &out))\n> > +               return out;\n> > +       return NULL;\n> >  }\n> >\n> >  const char *get_super_prefix(void)\n> > --\n> > 2.13.0.506.g27d5fe0cd-goog\n> >\n\n-- \nBrandon Williams\n"},{"id":"321429","messageId":"20170602183933.pcjfdi4jtkk4epmg@sigill.intra.peff.net","threadId":"46082","inReplyTo":"CAGZ79kafXpn+BXdMOVOPSX7eaFgcWBUULGR_PBXpMhjKjLEM-A@mail.gmail.com","subject":"Re: [PATCH 04/31] setup: don't perform lazy initialization of repository state","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-06-02T18:39:33Z","receivedAt":"2017-06-02T19:39:48Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jun 01, 2017 at 12:23:25PM -0700, Stefan Beller wrote:\n\n> On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> > Under some circumstances (bogus GIT_DIR value or the discovered gitdir\n> > is '.git') 'setup_git_directory()' won't initialize key repository\n> > state.  This leads to inconsistent state after running the setup code.\n> > To account for this inconsistent state, lazy initialization is done once\n> > a caller asks for the repository's gitdir or some other piece of\n> > repository state.  This is confusing and can be error prone.\n> >\n> > Instead let's tighten the expected outcome of 'setup_git_directory()'\n> > and ensure that it initializes repository state in all cases that would\n> > have been handled by lazy initialization.\n> \n> Lazy init is usually there for a reason. (As in: it took too long to perform\n> it at all times, so it has been optimized to only perform the init when needed).\n\nIn the case of setup_git_env(), I think it was less about doing work and\nmore that we didn't want to have to do explicit setup in each program.\nBut over the years we've moved away from that, and in fact if you hit\nthe lazy initialization these days you'll generally BUG() anyway.\n\n_But_ I suspect there are still some cases you'd need to handle. For\ninstance, it's still OK to skip calling setup_git_directory() if you've\ngot $GIT_DIR in the environment (which is why we have have_git_dir()\ninstead of checking startup_info->have_repository).\n\nI think it would be nice to do away with that, too, but we're not quite\nthere yet (and if I am reading this patch correctly, we'd probably hit\nthese BUGs in such cases).\n\n-Peff\n"},{"id":"321540","messageId":"20170605174352.GA40426@google.com","threadId":"46082","inReplyTo":"20170602183933.pcjfdi4jtkk4epmg@sigill.intra.peff.net","subject":"Re: [PATCH 04/31] setup: don't perform lazy initialization of repository state","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-05T17:43:52Z","receivedAt":"2017-06-05T17:44:00Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/02, Jeff King wrote:\n> On Thu, Jun 01, 2017 at 12:23:25PM -0700, Stefan Beller wrote:\n> \n> > On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> > > Under some circumstances (bogus GIT_DIR value or the discovered gitdir\n> > > is '.git') 'setup_git_directory()' won't initialize key repository\n> > > state.  This leads to inconsistent state after running the setup code.\n> > > To account for this inconsistent state, lazy initialization is done once\n> > > a caller asks for the repository's gitdir or some other piece of\n> > > repository state.  This is confusing and can be error prone.\n> > >\n> > > Instead let's tighten the expected outcome of 'setup_git_directory()'\n> > > and ensure that it initializes repository state in all cases that would\n> > > have been handled by lazy initialization.\n> > \n> > Lazy init is usually there for a reason. (As in: it took too long to perform\n> > it at all times, so it has been optimized to only perform the init when needed).\n> \n> In the case of setup_git_env(), I think it was less about doing work and\n> more that we didn't want to have to do explicit setup in each program.\n> But over the years we've moved away from that, and in fact if you hit\n> the lazy initialization these days you'll generally BUG() anyway.\n> \n> _But_ I suspect there are still some cases you'd need to handle. For\n> instance, it's still OK to skip calling setup_git_directory() if you've\n> got $GIT_DIR in the environment (which is why we have have_git_dir()\n> instead of checking startup_info->have_repository).\n\nYes there are a couple places that rely on the lazy initialization but\nthat's not due to setup not being run.  Rather it has to do with GIT_DIR\nbeing set to a bogus directory so when setup is run gently it does\nnothing.  Then at a later point in time the command tries to access\nfiles in the gitdir (which triggers lazy init of the git environment).\n\nSo I think that explicitly doing the 'lazy init' portion (which ensures\nthat the env gets setup even if GIT_DIR is bogus) at the end of setup\nshould be sufficient, least it seems to be so though perhaps we can't\nrely on our tests to tell us that.\n\n> \n> I think it would be nice to do away with that, too, but we're not quite\n> there yet (and if I am reading this patch correctly, we'd probably hit\n> these BUGs in such cases).\n> \n> -Peff\n\n-- \nBrandon Williams\n"},{"id":"321541","messageId":"20170605174632.GB40426@google.com","threadId":"46082","inReplyTo":"CAGZ79kY4iLWuCrPVA6mo6BbgwoF_-wyP_=ju5Fs0+n8cTifb=Q@mail.gmail.com","subject":"Re: [PATCH 31/31] ls-files: use repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-05T17:46:32Z","receivedAt":"2017-06-05T17:46:40Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/01, Stefan Beller wrote:\n> On Wed, May 31, 2017 at 2:44 PM, Brandon Williams <bmwill@google.com> wrote:\n> > Convert ls-files to use a repository struct and recurse submodules\n> > inprocess.\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> \n> \n> > +static void show_submodule(const struct repo *superproject,\n> > +                          struct dir_struct *dir, const char *path)\n> >  {\n> > +       struct repo submodule;\n> > +       char *gitdir = mkpathdup(\"%s/%s\", superproject->worktree, path);\n> > +       repo_init(&submodule, gitdir);\n> > +\n> > +       repo_read_index(&submodule);\n> > +       repo_read_gitmodules(&submodule);\n> > +\n> > +       if (superproject->submodule_prefix)\n> > +               submodule.submodule_prefix = xstrfmt(\"%s%s/\", superproject->submodule_prefix, path);\n> > +       else\n> > +               submodule.submodule_prefix = xstrfmt(\"%s/\", path);\n> > +       show_files(&submodule, dir);\n> > +\n> > +       repo_clear(&submodule);\n> > +       free(gitdir);\n> >  }\n> \n> I like how it seems easy now to do work in another repository. :)\n\nIt really does make working with another repo easy!  No more compiling\nargv options and spawning child processes :D\n\n> \n> > -       { \"ls-files\", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n> > +       { \"ls-files\", cmd_ls_files, RUN_SETUP },\n> \n> With this step, we can get rid of SUPPORT_SUPER_PREFIX eventually.\n\nYes Ideally most of the little hacks I introduced when originally\nteaching ls-files and grep to recurse could be removed.\n\n> \n> I do not have comments on the patches in the middle, but they\n> cleared up some of the questions that I asked in the early patches.\n> \n> Thanks,\n> Stefan\n\n-- \nBrandon Williams\n"},{"id":"321542","messageId":"20170605175344.GC40426@google.com","threadId":"46082","inReplyTo":"CAGZ79kbqsvuBG21teO2kT=H6G-xP0wJbd0f0BTjd9obRMSaxGQ@mail.gmail.com","subject":"Re: [PATCH 06/31] repo: introduce the repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-05T17:53:44Z","receivedAt":"2017-06-05T17:53:52Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/01, Stefan Beller wrote:\n> On Wed, May 31, 2017 at 2:43 PM, Brandon Williams <bmwill@google.com> wrote:\n> > Introduce the repository object 'struct repo' which can be used hold all\n> > state pertaining to a git repository.\n> >\n> > The aim of object-ifying the repository is to (1) make the code base\n> > more readable and easier to reason about and (2) allow for working on\n> > multiple repositories, specifically submodules, within the same process.\n> >\n> > TODO: Add more motivating points for adding a repository object?\n> \n> Yes please (or delete this line).\n> https://public-inbox.org/git/alpine.DEB.2.21.1.1705221501540.3610@virtualbox/\n> \n> > +++ b/repo.c\n> > @@ -0,0 +1,124 @@\n> > +#include \"cache.h\"\n> > +#include \"repo.h\"\n> > +\n> > +/*\n> > + * This may be the wrong place for this.\n> > + * It may be better to go in env.c or setup for the time being?\n> \n> In env.c we say:\n> /*\n>  * We put all the git config variables in this same object\n>  * file, so that programs can link against the config parser\n>  * without having to link against all the rest of git.\n>  *\n>  * In particular, no need to bring in libz etc unless needed,\n>  * even if you might want to know where the git directory etc\n>  * are.\n>  */\n> \n> And setup.c only has a few variables that matter there locally.\n> So I would think having 'the_repository' in repo.c is acceptable.\n\nAnd perhaps (far down the road) 'the_repoository' could be removed such\nthat builtin commands take a pointer to a repo object as a parameter.\n\n> \n> > + */\n> > +struct repo the_repository;\n> > +\n> > +static char *git_path_from_env(const char *envvar, const char *git_dir,\n> > +                              const char *path, int fromenv)\n> > +{\n> > +       if (fromenv) {\n> > +               const char *value = getenv(envvar);\n> > +               if (value)\n> > +                       return xstrdup(value);\n> > +       }\n> > +\n> > +       return xstrfmt(\"%s/%s\", git_dir, path);\n> > +}\n> > +\n> > +static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)\n> > +{\n> > +       if (fromenv) {\n> > +               const char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n> > +               if (value) {\n> > +                       strbuf_addstr(sb, value);\n> > +                       return 1;\n> > +               }\n> > +       }\n> > +\n> > +       return get_common_dir_noenv(sb, gitdir);\n> > +}\n> > +\n> > +/* called after setting gitdir */\n> > +static void repo_setup_env(struct repo *repo)\n> > +{\n> > +       struct strbuf sb = STRBUF_INIT;\n> > +\n> > +       if (!repo->gitdir)\n> > +               BUG(\"gitdir wasn't set before setting up the environment\");\n> > +\n> > +       repo->different_commondir = find_common_dir(&sb, repo->gitdir,\n> > +                                                   !repo->ignore_env);\n> > +       repo->commondir = strbuf_detach(&sb, NULL);\n> > +       repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,\n> > +                                           \"objects\", !repo->ignore_env);\n> > +       repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,\n> > +                                            \"index\", !repo->ignore_env);\n> > +       repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,\n> > +                                            \"info/grafts\", !repo->ignore_env);\n> > +       repo->namespace = expand_namespace(repo->ignore_env ? NULL :\n> > +                                          getenv(GIT_NAMESPACE_ENVIRONMENT));\n> > +}\n> > +\n> > +static void repo_clear_env(struct repo *repo)\n> > +{\n> > +       free(repo->gitdir);\n> > +       repo->gitdir = NULL;\n> > +       free(repo->commondir);\n> > +       repo->commondir = NULL;\n> > +       free(repo->objectdir);\n> > +       repo->objectdir = NULL;\n> > +       free(repo->index_file);\n> > +       repo->index_file = NULL;\n> > +       free(repo->graft_file);\n> > +       repo->graft_file = NULL;\n> > +       free(repo->namespace);\n> > +       repo->namespace = NULL;\n> \n> I wonder if we can defer the NULL assignments to\n> repo_clear, where we would just do a\n> memset(repo, 0, sizeof(struct repo));\n> \n\nYeah perhaps, clearing the env should either be done when setting gitdir\nagain (so setting up the env will happen again and we don't need to\nclear the fields) or clearing the struct as a whole so using memset\nwould work.\n\n> > +\n> > +       repo_set_gitdir(repo, resolved_gitdir);\n> > +\n> > +       /* NEEDSWORK: Verify repository format version */\n> \n> Care to elaborate on this? I do not understand why we would want\n> to check the format version here?\n\nWhen opening up a repository git needs to check if it understands the\nrepository format and all extensions.  If it doesn't git needs to bail\nout and not operate on the repository.  So a part of initializing a repo\nobject would be to verify that it understands the repository format\nversion.\n\n> \n> > +\n> > +extern void repo_set_gitdir(struct repo *repo, const char *path);\n> > +extern int repo_init(struct repo *repo, const char *path);\n> > +extern void repo_clear(struct repo *repo);\n> \n> The init and clear method seem obvious to me, but what do we need the\n> repo_set_gitdir for externally? I would assume the repo auto-discovers its\n> gitdir on its own?\n\nWell I didn't completely overhaul the setup code in this series so I\nreally just hooked into where the setup code already sets the gitdir,\nhence why this function is exposed atm.\n\n-- \nBrandon Williams\n"},{"id":"321544","messageId":"20170605182007.vvpk3ge73lrojxqw@sigill.intra.peff.net","threadId":"46082","inReplyTo":"20170605174352.GA40426@google.com","subject":"Re: [PATCH 04/31] setup: don't perform lazy initialization of repository state","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-06-05T18:20:07Z","receivedAt":"2017-06-05T18:20:13Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 05, 2017 at 10:43:52AM -0700, Brandon Williams wrote:\n\n> > In the case of setup_git_env(), I think it was less about doing work and\n> > more that we didn't want to have to do explicit setup in each program.\n> > But over the years we've moved away from that, and in fact if you hit\n> > the lazy initialization these days you'll generally BUG() anyway.\n> > \n> > _But_ I suspect there are still some cases you'd need to handle. For\n> > instance, it's still OK to skip calling setup_git_directory() if you've\n> > got $GIT_DIR in the environment (which is why we have have_git_dir()\n> > instead of checking startup_info->have_repository).\n> \n> Yes there are a couple places that rely on the lazy initialization but\n> that's not due to setup not being run.  Rather it has to do with GIT_DIR\n> being set to a bogus directory so when setup is run gently it does\n> nothing.  Then at a later point in time the command tries to access\n> files in the gitdir (which triggers lazy init of the git environment).\n> \n> So I think that explicitly doing the 'lazy init' portion (which ensures\n> that the env gets setup even if GIT_DIR is bogus) at the end of setup\n> should be sufficient, least it seems to be so though perhaps we can't\n> rely on our tests to tell us that.\n\nIn have_git_dir() we do:\n\n  int have_git_dir(void)\n  {\n\t  return startup_info->have_repository\n\t\t  || git_dir\n\t\t  || getenv(GIT_DIR_ENVIRONMENT);\n  }\n\nand generally call that right before calling a function that might do\nsetup_git_env(). We can assume that if have_repository is set that we\nhave an actual git_dir (we can check all of the assignment spots and\nverify that they always set it in tandem with the global git_dir).\nAnd obviously if git_dir is set, we're good.\n\nBut if that third condition ever triggers, it's because we're relying on\nthe lazy setup to copy it into git_dir. And if I understand correctly,\nthat would turn into a BUG with your patch.\n\nI guess my question is: does that third condition actually trigger in\npractice? I added those conditions in b9605bc4f (config: only read\n.git/config from configured repos, 2016-09-12). I remember there being\nsome reason for needing those back then, but the commit message doesn't\nsay. But if I remove them and just check have_repository (either on top\nof that commit or on top of the current master) the tests all still\npass.\n\nSo I'm not sure at this point what the case was that motivated it, or if\nit really was just an abundance of caution. But if there is such a case,\nI suspect it's broken by your patch series.\n\nI'm not sure we have a good way to find out, though. Like the current\nBUG() in setup_git_env, I think we'll just have to cook the patches for\na long time, see if anybody triggers it, and deal with it on a case by\ncase basis.\n\nI do kind of wonder if we should simplify have_git_dir(), if those other\nconditions aren't actually triggering.\n\n-Peff\n"},{"id":"321546","messageId":"CAGZ79kb2sC=Bnx5KVeZCbx2yMexVeEtGynte-Tw75w940qww3w@mail.gmail.com","threadId":"46082","inReplyTo":"20170605175344.GC40426@google.com","subject":"Re: [PATCH 06/31] repo: introduce the repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-05T18:31:16Z","receivedAt":"2017-06-05T18:31:24Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":">> > +\n>> > +       repo_set_gitdir(repo, resolved_gitdir);\n>> > +\n>> > +       /* NEEDSWORK: Verify repository format version */\n>>\n>> Care to elaborate on this? I do not understand why we would want\n>> to check the format version here?\n>\n> When opening up a repository git needs to check if it understands the\n> repository format and all extensions.  If it doesn't git needs to bail\n> out and not operate on the repository.  So a part of initializing a repo\n> object would be to verify that it understands the repository format\n> version.\n\nAh yes. Conceptually I understand why and what the repo format\nversion check is. At the time of asking the question I was confused\nwhether this is the right place, but after some thought this is the\nbest place to put it.\n\nAnd this NEEDSWORK is really just telling the reader that it needs to\nbe moved here, not copied. (That was another brain fart I had upon\nreading this comment).\n\nThanks,\nStefan\n"},{"id":"321548","messageId":"20170605184412.GD40426@google.com","threadId":"46082","inReplyTo":"20170605182007.vvpk3ge73lrojxqw@sigill.intra.peff.net","subject":"Re: [PATCH 04/31] setup: don't perform lazy initialization of repository state","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-05T18:44:12Z","receivedAt":"2017-06-05T18:44:20Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/05, Jeff King wrote:\n> On Mon, Jun 05, 2017 at 10:43:52AM -0700, Brandon Williams wrote:\n> \n> > > In the case of setup_git_env(), I think it was less about doing work and\n> > > more that we didn't want to have to do explicit setup in each program.\n> > > But over the years we've moved away from that, and in fact if you hit\n> > > the lazy initialization these days you'll generally BUG() anyway.\n> > > \n> > > _But_ I suspect there are still some cases you'd need to handle. For\n> > > instance, it's still OK to skip calling setup_git_directory() if you've\n> > > got $GIT_DIR in the environment (which is why we have have_git_dir()\n> > > instead of checking startup_info->have_repository).\n> > \n> > Yes there are a couple places that rely on the lazy initialization but\n> > that's not due to setup not being run.  Rather it has to do with GIT_DIR\n> > being set to a bogus directory so when setup is run gently it does\n> > nothing.  Then at a later point in time the command tries to access\n> > files in the gitdir (which triggers lazy init of the git environment).\n> > \n> > So I think that explicitly doing the 'lazy init' portion (which ensures\n> > that the env gets setup even if GIT_DIR is bogus) at the end of setup\n> > should be sufficient, least it seems to be so though perhaps we can't\n> > rely on our tests to tell us that.\n> \n> In have_git_dir() we do:\n> \n>   int have_git_dir(void)\n>   {\n> \t  return startup_info->have_repository\n> \t\t  || git_dir\n> \t\t  || getenv(GIT_DIR_ENVIRONMENT);\n>   }\n> \n> and generally call that right before calling a function that might do\n> setup_git_env(). We can assume that if have_repository is set that we\n> have an actual git_dir (we can check all of the assignment spots and\n> verify that they always set it in tandem with the global git_dir).\n> And obviously if git_dir is set, we're good.\n> \n> But if that third condition ever triggers, it's because we're relying on\n> the lazy setup to copy it into git_dir. And if I understand correctly,\n> that would turn into a BUG with your patch.\n> \n> I guess my question is: does that third condition actually trigger in\n> practice? I added those conditions in b9605bc4f (config: only read\n> .git/config from configured repos, 2016-09-12). I remember there being\n> some reason for needing those back then, but the commit message doesn't\n> say. But if I remove them and just check have_repository (either on top\n> of that commit or on top of the current master) the tests all still\n> pass.\n\nThe only instance I saw the third condition trigger was when GIT_DIR was\nset to a bogus gitdir so when reading the early config a bogus\ngitdir/config file was attempted to be read resulting in a noop.  If\nGIT_DIR is set to a valid gitdir then the other condition in\nread_early_config (which does repository discovery itself) would\ncorrectly catch and read from the repository's config.\n\n> \n> So I'm not sure at this point what the case was that motivated it, or if\n> it really was just an abundance of caution. But if there is such a case,\n> I suspect it's broken by your patch series.\n> \n> I'm not sure we have a good way to find out, though. Like the current\n> BUG() in setup_git_env, I think we'll just have to cook the patches for\n> a long time, see if anybody triggers it, and deal with it on a case by\n> case basis.\n> \n> I do kind of wonder if we should simplify have_git_dir(), if those other\n> conditions aren't actually triggering.\n\nIf this ends up being that big of an issue I'm sure that it would be\neasy to adapt this and revert to doing lazy-init.  I just saw how\nclunky it is and was trying to work to start the process of cleaning it\nup so that the code becomes easier to reason about.  It seemed to make\nthings easier for me to package them in a struct at least (and reason\nabout how the config system would work once stored in a repository\nstruct).\n\n-- \nBrandon Williams\n"},{"id":"321748","messageId":"alpine.DEB.2.21.1.1706081235130.171564@virtualbox","threadId":"46082","inReplyTo":"20170531214417.38857-4-bmwill@google.com","subject":"Re: [PATCH 03/31] config: don't implicitly use gitdir","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-06-08T10:41:06Z","receivedAt":"2017-06-08T10:42:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Brandon,\n\nOn Wed, 31 May 2017, Brandon Williams wrote:\n\n> Commit 2185fde56 (config: handle conditional include when $GIT_DIR is\n> not set up) added a 'git_dir' field to the config_options struct.  Let's\n> use this option field explicitly all the time instead of occasionally\n> falling back to calling 'git_pathdup(\"config\")' to get the path to the\n> local repository configuration.  This allows 'go_git_config_sequence()'\n> to not implicitly rely on global repository state.\n\nOh wow. `git_pathdup()`...\n\nSadly, I lack the time to review the entire patch series, but this here\nchange definitely looks correct to me.\n\nThanks,\nDscho\n"},{"id":"321759","messageId":"20170608163739.GM110638@google.com","threadId":"46082","inReplyTo":"alpine.DEB.2.21.1.1706081235130.171564@virtualbox","subject":"Re: [PATCH 03/31] config: don't implicitly use gitdir","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T16:37:39Z","receivedAt":"2017-06-08T16:37:48Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/08, Johannes Schindelin wrote:\n> Hi Brandon,\n> \n> On Wed, 31 May 2017, Brandon Williams wrote:\n> \n> > Commit 2185fde56 (config: handle conditional include when $GIT_DIR is\n> > not set up) added a 'git_dir' field to the config_options struct.  Let's\n> > use this option field explicitly all the time instead of occasionally\n> > falling back to calling 'git_pathdup(\"config\")' to get the path to the\n> > local repository configuration.  This allows 'go_git_config_sequence()'\n> > to not implicitly rely on global repository state.\n> \n> Oh wow. `git_pathdup()`...\n> \n> Sadly, I lack the time to review the entire patch series, but this here\n> change definitely looks correct to me.\n\nThanks for taking a look.  I understand you don't have time to review\nthe series in whole but I should also mention that patch 04/31 may be\nof interest to you as it deals with setup being slightly more robust and\nsince you've spent a great deal of time in that bit of code any input\nwould be nice.  Last prod I promise ;)\n\n-- \nBrandon Williams\n"},{"id":"321763","messageId":"alpine.DEB.2.21.1.1706082056560.171564@virtualbox","threadId":"46082","inReplyTo":"20170608163739.GM110638@google.com","subject":"Re: [PATCH 03/31] config: don't implicitly use gitdir","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-06-08T18:58:09Z","receivedAt":"2017-06-08T18:58:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Brandon,\n\nOn Thu, 8 Jun 2017, Brandon Williams wrote:\n\n> On 06/08, Johannes Schindelin wrote:\n> > \n> > On Wed, 31 May 2017, Brandon Williams wrote:\n> > \n> > > Commit 2185fde56 (config: handle conditional include when $GIT_DIR is\n> > > not set up) added a 'git_dir' field to the config_options struct.  Let's\n> > > use this option field explicitly all the time instead of occasionally\n> > > falling back to calling 'git_pathdup(\"config\")' to get the path to the\n> > > local repository configuration.  This allows 'go_git_config_sequence()'\n> > > to not implicitly rely on global repository state.\n> > \n> > Oh wow. `git_pathdup()`...\n> > \n> > Sadly, I lack the time to review the entire patch series, but this here\n> > change definitely looks correct to me.\n> \n> Thanks for taking a look.  I understand you don't have time to review\n> the series in whole but I should also mention that patch 04/31 may be\n> of interest to you as it deals with setup being slightly more robust and\n> since you've spent a great deal of time in that bit of code any input\n> would be nice.  Last prod I promise ;)\n\nI had a quick look over the patch and I like the direction.\n\nI also briefly scanned the discussion and have to admit that I am not\nknee-deep in those exceptional code paths that do strange^Wuncommon\nthings, so I feel a bit unqualified to comment about those.\n\nCiao,\nDscho\n"},{"id":"321764","messageId":"20170608191935.GB41637@google.com","threadId":"46082","inReplyTo":"alpine.DEB.2.21.1.1706082056560.171564@virtualbox","subject":"Re: [PATCH 03/31] config: don't implicitly use gitdir","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T19:19:35Z","receivedAt":"2017-06-08T19:19:43Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/08, Johannes Schindelin wrote:\n> Hi Brandon,\n> \n> On Thu, 8 Jun 2017, Brandon Williams wrote:\n> \n> > On 06/08, Johannes Schindelin wrote:\n> > > \n> > > On Wed, 31 May 2017, Brandon Williams wrote:\n> > > \n> > > > Commit 2185fde56 (config: handle conditional include when $GIT_DIR is\n> > > > not set up) added a 'git_dir' field to the config_options struct.  Let's\n> > > > use this option field explicitly all the time instead of occasionally\n> > > > falling back to calling 'git_pathdup(\"config\")' to get the path to the\n> > > > local repository configuration.  This allows 'go_git_config_sequence()'\n> > > > to not implicitly rely on global repository state.\n> > > \n> > > Oh wow. `git_pathdup()`...\n> > > \n> > > Sadly, I lack the time to review the entire patch series, but this here\n> > > change definitely looks correct to me.\n> > \n> > Thanks for taking a look.  I understand you don't have time to review\n> > the series in whole but I should also mention that patch 04/31 may be\n> > of interest to you as it deals with setup being slightly more robust and\n> > since you've spent a great deal of time in that bit of code any input\n> > would be nice.  Last prod I promise ;)\n> \n> I had a quick look over the patch and I like the direction.\n> \n> I also briefly scanned the discussion and have to admit that I am not\n> knee-deep in those exceptional code paths that do strange^Wuncommon\n> things, so I feel a bit unqualified to comment about those.\n\nAll good, thanks for looking!\n\n-- \nBrandon Williams\n"},{"id":"321778","messageId":"20170608234100.188529-2-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 01/32] config: create config.h","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:29Z","receivedAt":"2017-06-08T23:41:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Move all config related declarations from cache.h to a new config.h\nheader file.  This makes cache.h smaller and allows for the opportunity\nin a following patch to only include config.h when needed.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h  | 190 +------------------------------------------------------------\n config.h | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 195 insertions(+), 189 deletions(-)\n create mode 100644 config.h\n\ndiff --git a/cache.h b/cache.h\nindex ae4c45d37..a27fee458 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -11,6 +11,7 @@\n #include \"string-list.h\"\n #include \"pack-revindex.h\"\n #include \"hash.h\"\n+#include \"config.h\"\n \n #ifndef platform_SHA_CTX\n /*\n@@ -1866,188 +1867,9 @@ extern int packed_object_info(struct packed_git *pack, off_t offset, struct obje\n /* Dumb servers support */\n extern int update_server_info(int);\n \n-/* git_config_parse_key() returns these negated: */\n-#define CONFIG_INVALID_KEY 1\n-#define CONFIG_NO_SECTION_OR_NAME 2\n-/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */\n-#define CONFIG_NO_LOCK -1\n-#define CONFIG_INVALID_FILE 3\n-#define CONFIG_NO_WRITE 4\n-#define CONFIG_NOTHING_SET 5\n-#define CONFIG_INVALID_PATTERN 6\n-#define CONFIG_GENERIC_ERROR 7\n-\n-#define CONFIG_REGEX_NONE ((void *)1)\n-\n-struct git_config_source {\n-\tunsigned int use_stdin:1;\n-\tconst char *file;\n-\tconst char *blob;\n-};\n-\n-enum config_origin_type {\n-\tCONFIG_ORIGIN_BLOB,\n-\tCONFIG_ORIGIN_FILE,\n-\tCONFIG_ORIGIN_STDIN,\n-\tCONFIG_ORIGIN_SUBMODULE_BLOB,\n-\tCONFIG_ORIGIN_CMDLINE\n-};\n-\n-struct config_options {\n-\tunsigned int respect_includes : 1;\n-\tconst char *git_dir;\n-};\n-\n-typedef int (*config_fn_t)(const char *, const char *, void *);\n-extern int git_default_config(const char *, const char *, void *);\n-extern int git_config_from_file(config_fn_t fn, const char *, void *);\n-extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,\n-\t\t\t\t\tconst char *name, const char *buf, size_t len, void *data);\n-extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,\n-\t\t\t\t     const unsigned char *sha1, void *data);\n-extern void git_config_push_parameter(const char *text);\n-extern int git_config_from_parameters(config_fn_t fn, void *data);\n-extern void read_early_config(config_fn_t cb, void *data);\n-extern void git_config(config_fn_t fn, void *);\n-extern int git_config_with_options(config_fn_t fn, void *,\n-\t\t\t\t   struct git_config_source *config_source,\n-\t\t\t\t   const struct config_options *opts);\n-extern int git_parse_ulong(const char *, unsigned long *);\n-extern int git_parse_maybe_bool(const char *);\n-extern int git_config_int(const char *, const char *);\n-extern int64_t git_config_int64(const char *, const char *);\n-extern unsigned long git_config_ulong(const char *, const char *);\n-extern ssize_t git_config_ssize_t(const char *, const char *);\n-extern int git_config_bool_or_int(const char *, const char *, int *);\n-extern int git_config_bool(const char *, const char *);\n-extern int git_config_maybe_bool(const char *, const char *);\n-extern int git_config_string(const char **, const char *, const char *);\n-extern int git_config_pathname(const char **, const char *, const char *);\n-extern int git_config_set_in_file_gently(const char *, const char *, const char *);\n-extern void git_config_set_in_file(const char *, const char *, const char *);\n-extern int git_config_set_gently(const char *, const char *);\n-extern void git_config_set(const char *, const char *);\n-extern int git_config_parse_key(const char *, char **, int *);\n-extern int git_config_key_is_valid(const char *key);\n-extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);\n-extern void git_config_set_multivar(const char *, const char *, const char *, int);\n-extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);\n-extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);\n-extern int git_config_rename_section(const char *, const char *);\n-extern int git_config_rename_section_in_file(const char *, const char *, const char *);\n-extern const char *git_etc_gitconfig(void);\n-extern int git_env_bool(const char *, int);\n-extern unsigned long git_env_ulong(const char *, unsigned long);\n-extern int git_config_system(void);\n-extern int config_error_nonbool(const char *);\n-#if defined(__GNUC__)\n-#define config_error_nonbool(s) (config_error_nonbool(s), const_error())\n-#endif\n extern const char *get_log_output_encoding(void);\n extern const char *get_commit_output_encoding(void);\n \n-extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);\n-\n-enum config_scope {\n-\tCONFIG_SCOPE_UNKNOWN = 0,\n-\tCONFIG_SCOPE_SYSTEM,\n-\tCONFIG_SCOPE_GLOBAL,\n-\tCONFIG_SCOPE_REPO,\n-\tCONFIG_SCOPE_CMDLINE,\n-};\n-\n-extern enum config_scope current_config_scope(void);\n-extern const char *current_config_origin_type(void);\n-extern const char *current_config_name(void);\n-\n-struct config_include_data {\n-\tint depth;\n-\tconfig_fn_t fn;\n-\tvoid *data;\n-\tconst struct config_options *opts;\n-};\n-#define CONFIG_INCLUDE_INIT { 0 }\n-extern int git_config_include(const char *name, const char *value, void *data);\n-\n-/*\n- * Match and parse a config key of the form:\n- *\n- *   section.(subsection.)?key\n- *\n- * (i.e., what gets handed to a config_fn_t). The caller provides the section;\n- * we return -1 if it does not match, 0 otherwise. The subsection and key\n- * out-parameters are filled by the function (and *subsection is NULL if it is\n- * missing).\n- *\n- * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if\n- * there is no subsection at all.\n- */\n-extern int parse_config_key(const char *var,\n-\t\t\t    const char *section,\n-\t\t\t    const char **subsection, int *subsection_len,\n-\t\t\t    const char **key);\n-\n-struct config_set_element {\n-\tstruct hashmap_entry ent;\n-\tchar *key;\n-\tstruct string_list value_list;\n-};\n-\n-struct configset_list_item {\n-\tstruct config_set_element *e;\n-\tint value_index;\n-};\n-\n-/*\n- * the contents of the list are ordered according to their\n- * position in the config files and order of parsing the files.\n- * (i.e. key-value pair at the last position of .git/config will\n- * be at the last item of the list)\n- */\n-struct configset_list {\n-\tstruct configset_list_item *items;\n-\tunsigned int nr, alloc;\n-};\n-\n-struct config_set {\n-\tstruct hashmap config_hash;\n-\tint hash_initialized;\n-\tstruct configset_list list;\n-};\n-\n-extern void git_configset_init(struct config_set *cs);\n-extern int git_configset_add_file(struct config_set *cs, const char *filename);\n-extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);\n-extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);\n-extern void git_configset_clear(struct config_set *cs);\n-extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);\n-extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);\n-extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);\n-extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);\n-extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);\n-extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);\n-extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);\n-extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);\n-\n-extern int git_config_get_value(const char *key, const char **value);\n-extern const struct string_list *git_config_get_value_multi(const char *key);\n-extern void git_config_clear(void);\n-extern void git_config_iter(config_fn_t fn, void *data);\n-extern int git_config_get_string_const(const char *key, const char **dest);\n-extern int git_config_get_string(const char *key, char **dest);\n-extern int git_config_get_int(const char *key, int *dest);\n-extern int git_config_get_ulong(const char *key, unsigned long *dest);\n-extern int git_config_get_bool(const char *key, int *dest);\n-extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);\n-extern int git_config_get_maybe_bool(const char *key, int *dest);\n-extern int git_config_get_pathname(const char *key, const char **dest);\n-extern int git_config_get_untracked_cache(void);\n-extern int git_config_get_split_index(void);\n-extern int git_config_get_max_percent_split_change(void);\n-\n-/* This dies if the configured or default date is in the future */\n-extern int git_config_get_expiry(const char *key, const char **output);\n-\n /*\n  * This is a hack for test programs like test-dump-untracked-cache to\n  * ensure that they do not modify the untracked cache when reading it.\n@@ -2055,16 +1877,6 @@ extern int git_config_get_expiry(const char *key, const char **output);\n  */\n extern int ignore_untracked_cache_config;\n \n-struct key_value_info {\n-\tconst char *filename;\n-\tint linenr;\n-\tenum config_origin_type origin_type;\n-\tenum config_scope scope;\n-};\n-\n-extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));\n-extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);\n-\n extern int committer_ident_sufficiently_given(void);\n extern int author_ident_sufficiently_given(void);\n \ndiff --git a/config.h b/config.h\nnew file mode 100644\nindex 000000000..f7f8b66c5\n--- /dev/null\n+++ b/config.h\n@@ -0,0 +1,194 @@\n+#ifndef CONFIG_H\n+#define CONFIG_H\n+\n+/* git_config_parse_key() returns these negated: */\n+#define CONFIG_INVALID_KEY 1\n+#define CONFIG_NO_SECTION_OR_NAME 2\n+/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */\n+#define CONFIG_NO_LOCK -1\n+#define CONFIG_INVALID_FILE 3\n+#define CONFIG_NO_WRITE 4\n+#define CONFIG_NOTHING_SET 5\n+#define CONFIG_INVALID_PATTERN 6\n+#define CONFIG_GENERIC_ERROR 7\n+\n+#define CONFIG_REGEX_NONE ((void *)1)\n+\n+struct git_config_source {\n+\tunsigned int use_stdin:1;\n+\tconst char *file;\n+\tconst char *blob;\n+};\n+\n+enum config_origin_type {\n+\tCONFIG_ORIGIN_BLOB,\n+\tCONFIG_ORIGIN_FILE,\n+\tCONFIG_ORIGIN_STDIN,\n+\tCONFIG_ORIGIN_SUBMODULE_BLOB,\n+\tCONFIG_ORIGIN_CMDLINE\n+};\n+\n+struct config_options {\n+\tunsigned int respect_includes : 1;\n+\tconst char *git_dir;\n+};\n+\n+typedef int (*config_fn_t)(const char *, const char *, void *);\n+extern int git_default_config(const char *, const char *, void *);\n+extern int git_config_from_file(config_fn_t fn, const char *, void *);\n+extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,\n+\t\t\t\t\tconst char *name, const char *buf, size_t len, void *data);\n+extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,\n+\t\t\t\t     const unsigned char *sha1, void *data);\n+extern void git_config_push_parameter(const char *text);\n+extern int git_config_from_parameters(config_fn_t fn, void *data);\n+extern void read_early_config(config_fn_t cb, void *data);\n+extern void git_config(config_fn_t fn, void *);\n+extern int git_config_with_options(config_fn_t fn, void *,\n+\t\t\t\t   struct git_config_source *config_source,\n+\t\t\t\t   const struct config_options *opts);\n+extern int git_parse_ulong(const char *, unsigned long *);\n+extern int git_parse_maybe_bool(const char *);\n+extern int git_config_int(const char *, const char *);\n+extern int64_t git_config_int64(const char *, const char *);\n+extern unsigned long git_config_ulong(const char *, const char *);\n+extern ssize_t git_config_ssize_t(const char *, const char *);\n+extern int git_config_bool_or_int(const char *, const char *, int *);\n+extern int git_config_bool(const char *, const char *);\n+extern int git_config_maybe_bool(const char *, const char *);\n+extern int git_config_string(const char **, const char *, const char *);\n+extern int git_config_pathname(const char **, const char *, const char *);\n+extern int git_config_set_in_file_gently(const char *, const char *, const char *);\n+extern void git_config_set_in_file(const char *, const char *, const char *);\n+extern int git_config_set_gently(const char *, const char *);\n+extern void git_config_set(const char *, const char *);\n+extern int git_config_parse_key(const char *, char **, int *);\n+extern int git_config_key_is_valid(const char *key);\n+extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);\n+extern void git_config_set_multivar(const char *, const char *, const char *, int);\n+extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);\n+extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);\n+extern int git_config_rename_section(const char *, const char *);\n+extern int git_config_rename_section_in_file(const char *, const char *, const char *);\n+extern const char *git_etc_gitconfig(void);\n+extern int git_env_bool(const char *, int);\n+extern unsigned long git_env_ulong(const char *, unsigned long);\n+extern int git_config_system(void);\n+extern int config_error_nonbool(const char *);\n+#if defined(__GNUC__)\n+#define config_error_nonbool(s) (config_error_nonbool(s), const_error())\n+#endif\n+\n+extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);\n+\n+enum config_scope {\n+\tCONFIG_SCOPE_UNKNOWN = 0,\n+\tCONFIG_SCOPE_SYSTEM,\n+\tCONFIG_SCOPE_GLOBAL,\n+\tCONFIG_SCOPE_REPO,\n+\tCONFIG_SCOPE_CMDLINE,\n+};\n+\n+extern enum config_scope current_config_scope(void);\n+extern const char *current_config_origin_type(void);\n+extern const char *current_config_name(void);\n+\n+struct config_include_data {\n+\tint depth;\n+\tconfig_fn_t fn;\n+\tvoid *data;\n+\tconst struct config_options *opts;\n+};\n+#define CONFIG_INCLUDE_INIT { 0 }\n+extern int git_config_include(const char *name, const char *value, void *data);\n+\n+/*\n+ * Match and parse a config key of the form:\n+ *\n+ *   section.(subsection.)?key\n+ *\n+ * (i.e., what gets handed to a config_fn_t). The caller provides the section;\n+ * we return -1 if it does not match, 0 otherwise. The subsection and key\n+ * out-parameters are filled by the function (and *subsection is NULL if it is\n+ * missing).\n+ *\n+ * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if\n+ * there is no subsection at all.\n+ */\n+extern int parse_config_key(const char *var,\n+\t\t\t    const char *section,\n+\t\t\t    const char **subsection, int *subsection_len,\n+\t\t\t    const char **key);\n+\n+struct config_set_element {\n+\tstruct hashmap_entry ent;\n+\tchar *key;\n+\tstruct string_list value_list;\n+};\n+\n+struct configset_list_item {\n+\tstruct config_set_element *e;\n+\tint value_index;\n+};\n+\n+/*\n+ * the contents of the list are ordered according to their\n+ * position in the config files and order of parsing the files.\n+ * (i.e. key-value pair at the last position of .git/config will\n+ * be at the last item of the list)\n+ */\n+struct configset_list {\n+\tstruct configset_list_item *items;\n+\tunsigned int nr, alloc;\n+};\n+\n+struct config_set {\n+\tstruct hashmap config_hash;\n+\tint hash_initialized;\n+\tstruct configset_list list;\n+};\n+\n+extern void git_configset_init(struct config_set *cs);\n+extern int git_configset_add_file(struct config_set *cs, const char *filename);\n+extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);\n+extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);\n+extern void git_configset_clear(struct config_set *cs);\n+extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);\n+extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);\n+extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);\n+extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);\n+extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);\n+extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);\n+extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);\n+extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);\n+\n+extern int git_config_get_value(const char *key, const char **value);\n+extern const struct string_list *git_config_get_value_multi(const char *key);\n+extern void git_config_clear(void);\n+extern void git_config_iter(config_fn_t fn, void *data);\n+extern int git_config_get_string_const(const char *key, const char **dest);\n+extern int git_config_get_string(const char *key, char **dest);\n+extern int git_config_get_int(const char *key, int *dest);\n+extern int git_config_get_ulong(const char *key, unsigned long *dest);\n+extern int git_config_get_bool(const char *key, int *dest);\n+extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);\n+extern int git_config_get_maybe_bool(const char *key, int *dest);\n+extern int git_config_get_pathname(const char *key, const char **dest);\n+extern int git_config_get_untracked_cache(void);\n+extern int git_config_get_split_index(void);\n+extern int git_config_get_max_percent_split_change(void);\n+\n+/* This dies if the configured or default date is in the future */\n+extern int git_config_get_expiry(const char *key, const char **output);\n+\n+struct key_value_info {\n+\tconst char *filename;\n+\tint linenr;\n+\tenum config_origin_type origin_type;\n+\tenum config_scope scope;\n+};\n+\n+extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));\n+extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);\n+\n+#endif /* CONFIG_H */\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321779","messageId":"20170608234100.188529-3-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 02/32] config: remove git_config_iter","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:30Z","receivedAt":"2017-06-08T23:41:24Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Since there is no implementation of the function 'git_config_iter' lets\nstop exporting it and remove the prototype from config.h.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n config.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/config.h b/config.h\nindex f7f8b66c5..c70599bd5 100644\n--- a/config.h\n+++ b/config.h\n@@ -165,7 +165,6 @@ extern int git_configset_get_pathname(struct config_set *cs, const char *key, co\n extern int git_config_get_value(const char *key, const char **value);\n extern const struct string_list *git_config_get_value_multi(const char *key);\n extern void git_config_clear(void);\n-extern void git_config_iter(config_fn_t fn, void *data);\n extern int git_config_get_string_const(const char *key, const char **dest);\n extern int git_config_get_string(const char *key, char **dest);\n extern int git_config_get_int(const char *key, int *dest);\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321780","messageId":"20170608234100.188529-1-bmwill@google.com","threadId":"46082","inReplyTo":"20170531214417.38857-1-bmwill@google.com","subject":"[PATCH v2 00/32] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:28Z","receivedAt":"2017-06-08T23:41:26Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"When I sent out my RFC series there seemed to be a lot of interest but I\nhaven't seen many people jump to review this series.  Despite lack of review I\nwanted to get out another version which includes some changes to fix things\nthat were bugging me about the series.  Hopfully this v2 will prod some more\npeople to take a look.\n\nThe meat of the series is really from 04-15 and patch 32 which converts\nls-files to recurse using a repository object.  So if you're pressed for time\nyou can focus on those patches.\n\nYou can find this series at: https://github.com/bmwill/git/tree/repository-object\n\nWhat's different in v2:\n* 'struct repo' has been renamed 'struct repository'.  Really just an aesthetic\n  change and it looks more \"official\" without having a shortened name.\n* Better commit messages on a few of the patches which were soarly lacking.\n* I found that 'git_config_iter' was being exported without an implementation\n  so I added a patch to remove it.\n* repo_init is a bit cleaner and is written in such a way to not call 'die()',\n  instead it returns a non-zero return value upon failure.\n\nThanks for your help!\n\nBrandon Williams (32):\n  config: create config.h\n  config: remove git_config_iter\n  config: don't include config.h by default\n  config: don't implicitly use gitdir\n  setup: don't perform lazy initialization of repository state\n  environment: remove namespace_len variable\n  repository: introduce the repository object\n  environment: place key repository state in the_repository\n  environment: store worktree in the_repository\n  setup: add comment indicating a hack\n  config: read config from a repository object\n  repository: add index_state to struct repo\n  submodule-config: store the_submodule_cache in the_repository\n  submodule: add repo_read_gitmodules\n  submodule: convert is_submodule_initialized to work on a repository\n  convert: convert get_cached_convert_stats_ascii to take an index\n  convert: convert crlf_to_git to take an index\n  convert: convert convert_to_git_filter_fd to take an index\n  convert: convert convert_to_git to take an index\n  convert: convert renormalize_buffer to take an index\n  tree: convert read_tree to take an index parameter\n  ls-files: convert overlay_tree_on_cache to take an index\n  ls-files: convert write_eolinfo to take an index\n  ls-files: convert show_killed_files to take an index\n  ls-files: convert show_other_files to take an index\n  ls-files: convert show_ru_info to take an index\n  ls-files: convert ce_excluded to take an index\n  ls-files: convert prune_cache to take an index\n  ls-files: convert show_files to take an index\n  ls-files: factor out debug info into a function\n  ls-files: factor out tag calculation\n  ls-files: use repository object\n\n Makefile                               |   1 +\n advice.c                               |   1 +\n alias.c                                |   1 +\n apply.c                                |   3 +-\n archive-tar.c                          |   1 +\n archive-zip.c                          |   1 +\n archive.c                              |   1 +\n attr.c                                 |   1 +\n bisect.c                               |   1 +\n branch.c                               |   1 +\n builtin/add.c                          |   1 +\n builtin/am.c                           |   1 +\n builtin/blame.c                        |   3 +-\n builtin/branch.c                       |   1 +\n builtin/cat-file.c                     |   1 +\n builtin/check-attr.c                   |   1 +\n builtin/check-ignore.c                 |   1 +\n builtin/check-mailmap.c                |   1 +\n builtin/checkout-index.c               |   1 +\n builtin/checkout.c                     |   1 +\n builtin/clean.c                        |   1 +\n builtin/clone.c                        |   1 +\n builtin/column.c                       |   1 +\n builtin/commit-tree.c                  |   1 +\n builtin/commit.c                       |   4 +-\n builtin/config.c                       |   3 +\n builtin/count-objects.c                |   1 +\n builtin/describe.c                     |   1 +\n builtin/diff-files.c                   |   1 +\n builtin/diff-index.c                   |   1 +\n builtin/diff-tree.c                    |   1 +\n builtin/diff.c                         |   1 +\n builtin/difftool.c                     |   1 +\n builtin/fast-export.c                  |   1 +\n builtin/fetch.c                        |   1 +\n builtin/fmt-merge-msg.c                |   1 +\n builtin/for-each-ref.c                 |   1 +\n builtin/fsck.c                         |   1 +\n builtin/gc.c                           |   1 +\n builtin/grep.c                         |   4 +-\n builtin/hash-object.c                  |   1 +\n builtin/help.c                         |   1 +\n builtin/index-pack.c                   |   1 +\n builtin/init-db.c                      |   1 +\n builtin/log.c                          |   1 +\n builtin/ls-files.c                     | 330 ++++++++++++++++-----------------\n builtin/ls-tree.c                      |   1 +\n builtin/merge-base.c                   |   1 +\n builtin/merge-file.c                   |   1 +\n builtin/merge.c                        |   1 +\n builtin/mv.c                           |   1 +\n builtin/name-rev.c                     |   1 +\n builtin/notes.c                        |   1 +\n builtin/pack-objects.c                 |   1 +\n builtin/patch-id.c                     |   1 +\n builtin/pull.c                         |   1 +\n builtin/push.c                         |   1 +\n builtin/read-tree.c                    |   1 +\n builtin/rebase--helper.c               |   1 +\n builtin/receive-pack.c                 |   1 +\n builtin/reflog.c                       |   1 +\n builtin/remote.c                       |   1 +\n builtin/repack.c                       |   1 +\n builtin/replace.c                      |   1 +\n builtin/rerere.c                       |   1 +\n builtin/reset.c                        |   1 +\n builtin/rev-list.c                     |   1 +\n builtin/rev-parse.c                    |   1 +\n builtin/revert.c                       |   1 +\n builtin/rm.c                           |   1 +\n builtin/send-pack.c                    |   1 +\n builtin/shortlog.c                     |   1 +\n builtin/show-branch.c                  |   1 +\n builtin/stripspace.c                   |   1 +\n builtin/submodule--helper.c            |  10 +-\n builtin/symbolic-ref.c                 |   1 +\n builtin/tag.c                          |   1 +\n builtin/unpack-file.c                  |   1 +\n builtin/unpack-objects.c               |   1 +\n builtin/update-index.c                 |   1 +\n builtin/update-ref.c                   |   1 +\n builtin/update-server-info.c           |   1 +\n builtin/var.c                          |   1 +\n builtin/verify-commit.c                |   1 +\n builtin/verify-pack.c                  |   1 +\n builtin/verify-tag.c                   |   1 +\n builtin/worktree.c                     |   1 +\n builtin/write-tree.c                   |   1 +\n cache.h                                | 196 +-------------------\n color.c                                |   1 +\n column.c                               |   1 +\n combine-diff.c                         |   2 +-\n config.c                               | 210 ++++++++++++++-------\n config.h                               | 217 ++++++++++++++++++++++\n connect.c                              |   1 +\n convert.c                              |  32 ++--\n convert.h                              |  19 +-\n credential-cache--daemon.c             |   1 +\n credential.c                           |   1 +\n daemon.c                               |   1 +\n diff.c                                 |   7 +-\n dir.c                                  |   3 +-\n environment.c                          | 101 ++++------\n fast-import.c                          |   1 +\n fetch-pack.c                           |   1 +\n git.c                                  |   3 +-\n gpg-interface.c                        |   1 +\n graph.c                                |   1 +\n grep.c                                 |   1 +\n help.c                                 |   1 +\n http-backend.c                         |   1 +\n http-fetch.c                           |   1 +\n http.c                                 |   1 +\n ident.c                                |   1 +\n imap-send.c                            |   1 +\n ll-merge.c                             |   3 +-\n log-tree.c                             |   1 +\n mailinfo.c                             |   1 +\n merge-recursive.c                      |   5 +-\n notes-utils.c                          |   1 +\n notes.c                                |   1 +\n pager.c                                |   1 +\n parse-options.c                        |   1 +\n path.c                                 |  11 +-\n pathspec.c                             |   1 +\n pretty.c                               |   1 +\n prompt.c                               |   1 +\n read-cache.c                           |   1 +\n refs.c                                 |   1 +\n refs/files-backend.c                   |   1 +\n remote-curl.c                          |   1 +\n remote.c                               |   1 +\n repository.c                           | 216 +++++++++++++++++++++\n repository.h                           |  45 +++++\n rerere.c                               |   1 +\n send-pack.c                            |   1 +\n sequencer.c                            |   1 +\n setup.c                                |  34 ++++\n sha1_file.c                            |   7 +-\n sha1_name.c                            |   1 +\n submodule-config.c                     |  71 +++++--\n submodule-config.h                     |  10 +\n submodule.c                            |  36 ++--\n submodule.h                            |   4 +-\n t/helper/test-config.c                 |   1 +\n t/helper/test-submodule-config.c       |   1 +\n t/t3007-ls-files-recurse-submodules.sh |  39 ++++\n trailer.c                              |   1 +\n transport.c                            |   1 +\n tree.c                                 |  28 ++-\n tree.h                                 |   3 +-\n unpack-trees.c                         |   1 +\n upload-pack.c                          |   1 +\n userdiff.c                             |   1 +\n versioncmp.c                           |   1 +\n wrapper.c                              |   1 +\n xdiff-interface.c                      |   1 +\n 157 files changed, 1199 insertions(+), 586 deletions(-)\n create mode 100644 config.h\n create mode 100644 repository.c\n create mode 100644 repository.h\n\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321781","messageId":"20170608234100.188529-5-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 04/32] config: don't implicitly use gitdir","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:32Z","receivedAt":"2017-06-08T23:41:28Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Commit 2185fde56 (config: handle conditional include when $GIT_DIR is\nnot set up) added a 'git_dir' field to the config_options struct.  Let's\nuse this option field explicitly all the time instead of occasionally\nfalling back to calling 'git_pathdup(\"config\")' to get the path to the\nlocal repository configuration.  This allows 'do_git_config_sequence()'\nto not implicitly rely on global repository state.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/config.c | 2 ++\n config.c         | 4 ++--\n 2 files changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 753c40a5c..90f49a6ee 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -539,6 +539,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t\tconfig_options.respect_includes = !given_config_source.file;\n \telse\n \t\tconfig_options.respect_includes = respect_includes_opt;\n+\tif (have_git_dir())\n+\t\tconfig_options.git_dir = get_git_common_dir();\n \n \tif (end_null) {\n \t\tterm = '\\0';\ndiff --git a/config.c b/config.c\nindex 2390f98e3..ff09b27b8 100644\n--- a/config.c\n+++ b/config.c\n@@ -1548,8 +1548,6 @@ static int do_git_config_sequence(const struct config_options *opts,\n \n \tif (opts->git_dir)\n \t\trepo_config = mkpathdup(\"%s/config\", opts->git_dir);\n-\telse if (have_git_dir())\n-\t\trepo_config = git_pathdup(\"config\");\n \telse\n \t\trepo_config = NULL;\n \n@@ -1613,6 +1611,8 @@ static void git_config_raw(config_fn_t fn, void *data)\n \tstruct config_options opts = {0};\n \n \topts.respect_includes = 1;\n+\tif (have_git_dir())\n+\t\topts.git_dir = get_git_common_dir();\n \tif (git_config_with_options(fn, data, NULL, &opts) < 0)\n \t\t/*\n \t\t * git_config_with_options() normally returns only\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321782","messageId":"20170608234100.188529-4-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 03/32] config: don't include config.h by default","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:31Z","receivedAt":"2017-06-08T23:41:31Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Stop including config.h by default in cache.h.  Instead only include\nconfig.h in those files which require use of the config system.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n advice.c                         | 1 +\n alias.c                          | 1 +\n apply.c                          | 1 +\n archive-tar.c                    | 1 +\n archive-zip.c                    | 1 +\n archive.c                        | 1 +\n attr.c                           | 1 +\n bisect.c                         | 1 +\n branch.c                         | 1 +\n builtin/add.c                    | 1 +\n builtin/am.c                     | 1 +\n builtin/blame.c                  | 1 +\n builtin/branch.c                 | 1 +\n builtin/cat-file.c               | 1 +\n builtin/check-attr.c             | 1 +\n builtin/check-ignore.c           | 1 +\n builtin/check-mailmap.c          | 1 +\n builtin/checkout-index.c         | 1 +\n builtin/checkout.c               | 1 +\n builtin/clean.c                  | 1 +\n builtin/clone.c                  | 1 +\n builtin/column.c                 | 1 +\n builtin/commit-tree.c            | 1 +\n builtin/commit.c                 | 1 +\n builtin/config.c                 | 1 +\n builtin/count-objects.c          | 1 +\n builtin/describe.c               | 1 +\n builtin/diff-files.c             | 1 +\n builtin/diff-index.c             | 1 +\n builtin/diff-tree.c              | 1 +\n builtin/diff.c                   | 1 +\n builtin/difftool.c               | 1 +\n builtin/fast-export.c            | 1 +\n builtin/fetch.c                  | 1 +\n builtin/fmt-merge-msg.c          | 1 +\n builtin/for-each-ref.c           | 1 +\n builtin/fsck.c                   | 1 +\n builtin/gc.c                     | 1 +\n builtin/grep.c                   | 1 +\n builtin/hash-object.c            | 1 +\n builtin/help.c                   | 1 +\n builtin/index-pack.c             | 1 +\n builtin/init-db.c                | 1 +\n builtin/log.c                    | 1 +\n builtin/ls-files.c               | 1 +\n builtin/ls-tree.c                | 1 +\n builtin/merge-base.c             | 1 +\n builtin/merge-file.c             | 1 +\n builtin/merge.c                  | 1 +\n builtin/mv.c                     | 1 +\n builtin/name-rev.c               | 1 +\n builtin/notes.c                  | 1 +\n builtin/pack-objects.c           | 1 +\n builtin/patch-id.c               | 1 +\n builtin/pull.c                   | 1 +\n builtin/push.c                   | 1 +\n builtin/read-tree.c              | 1 +\n builtin/rebase--helper.c         | 1 +\n builtin/receive-pack.c           | 1 +\n builtin/reflog.c                 | 1 +\n builtin/remote.c                 | 1 +\n builtin/repack.c                 | 1 +\n builtin/replace.c                | 1 +\n builtin/rerere.c                 | 1 +\n builtin/reset.c                  | 1 +\n builtin/rev-list.c               | 1 +\n builtin/rev-parse.c              | 1 +\n builtin/revert.c                 | 1 +\n builtin/rm.c                     | 1 +\n builtin/send-pack.c              | 1 +\n builtin/shortlog.c               | 1 +\n builtin/show-branch.c            | 1 +\n builtin/stripspace.c             | 1 +\n builtin/submodule--helper.c      | 1 +\n builtin/symbolic-ref.c           | 1 +\n builtin/tag.c                    | 1 +\n builtin/unpack-file.c            | 1 +\n builtin/unpack-objects.c         | 1 +\n builtin/update-index.c           | 1 +\n builtin/update-ref.c             | 1 +\n builtin/update-server-info.c     | 1 +\n builtin/var.c                    | 1 +\n builtin/verify-commit.c          | 1 +\n builtin/verify-pack.c            | 1 +\n builtin/verify-tag.c             | 1 +\n builtin/worktree.c               | 1 +\n builtin/write-tree.c             | 1 +\n cache.h                          | 1 -\n color.c                          | 1 +\n column.c                         | 1 +\n config.c                         | 1 +\n connect.c                        | 1 +\n convert.c                        | 1 +\n credential-cache--daemon.c       | 1 +\n credential.c                     | 1 +\n daemon.c                         | 1 +\n diff.c                           | 1 +\n dir.c                            | 1 +\n environment.c                    | 1 +\n fast-import.c                    | 1 +\n fetch-pack.c                     | 1 +\n git.c                            | 1 +\n gpg-interface.c                  | 1 +\n graph.c                          | 1 +\n grep.c                           | 1 +\n help.c                           | 1 +\n http-backend.c                   | 1 +\n http-fetch.c                     | 1 +\n http.c                           | 1 +\n ident.c                          | 1 +\n imap-send.c                      | 1 +\n ll-merge.c                       | 1 +\n log-tree.c                       | 1 +\n mailinfo.c                       | 1 +\n merge-recursive.c                | 1 +\n notes-utils.c                    | 1 +\n notes.c                          | 1 +\n pager.c                          | 1 +\n parse-options.c                  | 1 +\n pathspec.c                       | 1 +\n pretty.c                         | 1 +\n prompt.c                         | 1 +\n read-cache.c                     | 1 +\n refs.c                           | 1 +\n refs/files-backend.c             | 1 +\n remote-curl.c                    | 1 +\n remote.c                         | 1 +\n rerere.c                         | 1 +\n send-pack.c                      | 1 +\n sequencer.c                      | 1 +\n setup.c                          | 1 +\n sha1_file.c                      | 1 +\n sha1_name.c                      | 1 +\n submodule-config.c               | 1 +\n submodule.c                      | 1 +\n t/helper/test-config.c           | 1 +\n t/helper/test-submodule-config.c | 1 +\n trailer.c                        | 1 +\n transport.c                      | 1 +\n unpack-trees.c                   | 1 +\n upload-pack.c                    | 1 +\n userdiff.c                       | 1 +\n versioncmp.c                     | 1 +\n wrapper.c                        | 1 +\n xdiff-interface.c                | 1 +\n 145 files changed, 144 insertions(+), 1 deletion(-)\n\ndiff --git a/advice.c b/advice.c\nindex b84ae4960..3fa04fca0 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n \n int advice_push_update_rejected = 1;\n int advice_push_non_ff_current = 1;\ndiff --git a/alias.c b/alias.c\nindex 3b90397a9..052f34136 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n \n char *alias_lookup(const char *alias)\n {\ndiff --git a/apply.c b/apply.c\nindex c49cef063..87db9618d 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -8,6 +8,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"blob.h\"\n #include \"delta.h\"\n #include \"diff.h\"\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 073e60ebd..c6ed96ee7 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -2,6 +2,7 @@\n  * Copyright (c) 2005, 2006 Rene Scharfe\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tar.h\"\n #include \"archive.h\"\n #include \"streaming.h\"\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 27563e9e2..e8913e5a2 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -2,6 +2,7 @@\n  * Copyright (c) 2006 Rene Scharfe\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"archive.h\"\n #include \"streaming.h\"\n #include \"utf8.h\"\ndiff --git a/archive.c b/archive.c\nindex b15a922da..60b3035a7 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"commit.h\"\n #include \"tree-walk.h\"\ndiff --git a/attr.c b/attr.c\nindex 7e2134471..9f8b02936 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -9,6 +9,7 @@\n \n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"exec_cmd.h\"\n #include \"attr.h\"\n #include \"dir.h\"\ndiff --git a/bisect.c b/bisect.c\nindex d88f9bc3d..c2acb9455 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n #include \"revision.h\"\ndiff --git a/branch.c b/branch.c\nindex 985316eb7..a8a548ccf 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"branch.h\"\n #include \"refs.h\"\n #include \"remote.h\"\ndiff --git a/builtin/add.c b/builtin/add.c\nindex d9a2491e4..f2415e99f 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Linus Torvalds\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 0f63dcab1..0b6b1265d 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -4,6 +4,7 @@\n  * Based on git-am.sh by Junio C Hamano.\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 1043e5376..c0ae49298 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -6,6 +6,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\n #include \"blob.h\"\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 83fcda43d..c958e9325 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -6,6 +6,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"color.h\"\n #include \"refs.h\"\n #include \"commit.h\"\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 9af863e79..7bc45f600 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n #include \"userdiff.h\"\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 4d01ca0c8..91444dc04 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"attr.h\"\n #include \"quote.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex c7b8c0889..3e280b9c7 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"quote.h\"\n #include \"pathspec.h\"\ndiff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c\nindex cf0f54f6b..cdce144f3 100644\n--- a/builtin/check-mailmap.c\n+++ b/builtin/check-mailmap.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"mailmap.h\"\n #include \"parse-options.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex 07631d0c9..39c8be05d 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -5,6 +5,7 @@\n  *\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"quote.h\"\n #include \"cache-tree.h\"\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex a6b2af39d..45fab5a4d 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 329b68c40..09adf0551 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -8,6 +8,7 @@\n \n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 743f16ae2..4922a5496 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -9,6 +9,7 @@\n  */\n \n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"fetch-pack.h\"\ndiff --git a/builtin/column.c b/builtin/column.c\nindex 33314b4d7..0c3223d64 100644\n--- a/builtin/column.c\n+++ b/builtin/column.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"parse-options.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/commit-tree.c b/builtin/commit-tree.c\nindex f39c2b273..a4a923d7c 100644\n--- a/builtin/commit-tree.c\n+++ b/builtin/commit-tree.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"tree.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex da1ba4c86..805da4915 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -6,6 +6,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"cache-tree.h\"\n #include \"color.h\"\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 7f6c25d4d..753c40a5c 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"color.h\"\n #include \"parse-options.h\"\n #include \"urlmatch.h\"\ndiff --git a/builtin/count-objects.c b/builtin/count-objects.c\nindex acb05940f..1d82e61f2 100644\n--- a/builtin/count-objects.c\n+++ b/builtin/count-objects.c\n@@ -5,6 +5,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 893c8789f..70eb14460 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"commit.h\"\n #include \"tag.h\"\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 15c61fd8d..29d3e4f41 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n #include \"revision.h\"\ndiff --git a/builtin/diff-index.c b/builtin/diff-index.c\nindex 1af373d00..e3d418361 100644\n--- a/builtin/diff-index.c\n+++ b/builtin/diff-index.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n #include \"revision.h\"\ndiff --git a/builtin/diff-tree.c b/builtin/diff-tree.c\nindex 5ea1c1431..9af942b6b 100644\n--- a/builtin/diff-tree.c\n+++ b/builtin/diff-tree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n #include \"log-tree.h\"\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 8c03ddaf5..b85af112a 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -4,6 +4,7 @@\n  * Copyright (c) 2006 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"color.h\"\n #include \"commit.h\"\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex b9a892f26..9199227f6 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -12,6 +12,7 @@\n  * Copyright (C) 2016 Johannes Schindelin\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"run-command.h\"\n #include \"exec_cmd.h\"\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 24e29ad7e..0dfd980dd 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -5,6 +5,7 @@\n  */\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"commit.h\"\n #include \"object.h\"\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex d4d573b98..284595911 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -2,6 +2,7 @@\n  * \"git fetch\"\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"commit.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c\nindex 70137b0b7..10cbb4341 100644\n--- a/builtin/fmt-merge-msg.c\n+++ b/builtin/fmt-merge-msg.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"commit.h\"\n #include \"diff.h\"\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex eca365bf8..52be99cba 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"object.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex cb2ba6cd1..90593491e 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"tree.h\"\n #include \"blob.h\"\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex f484eda43..bd91f136f 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -11,6 +11,7 @@\n  */\n \n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"tempfile.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex c6c26e9b9..0f4a1e5a3 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -4,6 +4,7 @@\n  * Copyright (c) 2006 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"blob.h\"\n #include \"tree.h\"\n #include \"commit.h\"\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex bbeaf20bc..d04baf999 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -5,6 +5,7 @@\n  * Copyright (C) Junio C Hamano, 2005\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"blob.h\"\n #include \"quote.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 49f7a07f8..334a8494a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -2,6 +2,7 @@\n  * Builtin help command\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 04b9dcaf0..edc1a91d8 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"delta.h\"\n #include \"pack.h\"\n #include \"csum-file.h\"\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex 8a6acb0ec..47823f9aa 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\ndiff --git a/builtin/log.c b/builtin/log.c\nindex a440601ef..72a9fd968 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -5,6 +5,7 @@\n  *\t\t 2006 Junio Hamano\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"color.h\"\n #include \"commit.h\"\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex b376afc31..c4357dc30 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -6,6 +6,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"quote.h\"\n #include \"dir.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex ee7b293b1..ef965408e 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"blob.h\"\n #include \"tree.h\"\n #include \"commit.h\"\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex 0c36a70ad..6dbd167d3 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"diff.h\"\ndiff --git a/builtin/merge-file.c b/builtin/merge-file.c\nindex 47dde7c39..b08803e61 100644\n--- a/builtin/merge-file.c\n+++ b/builtin/merge-file.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"xdiff/xdiff.h\"\n #include \"xdiff-interface.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex a4a098f40..2512370c1 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -7,6 +7,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"builtin.h\"\n #include \"lockfile.h\"\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 61d20037a..dcf6736b5 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Johannes Schindelin\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"pathspec.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 7fc7e66e8..e21715f1d 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"tag.h\"\n #include \"refs.h\"\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex f2847c41e..231ad1f01 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -8,6 +8,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"notes.h\"\n #include \"blob.h\"\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 80439047a..9fe1fa8e1 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"attr.h\"\n #include \"object.h\"\n #include \"blob.h\"\ndiff --git a/builtin/patch-id.c b/builtin/patch-id.c\nindex 81552e02e..970d0d30b 100644\n--- a/builtin/patch-id.c\n+++ b/builtin/patch-id.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n \n static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)\n {\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex 318c273eb..af325d9fc 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -6,6 +6,7 @@\n  * Fetch one or more remote refs and merge it/them into the current HEAD.\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n #include \"exec_cmd.h\"\ndiff --git a/builtin/push.c b/builtin/push.c\nindex a597759d8..76aa713d2 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -2,6 +2,7 @@\n  * \"git push\"\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"run-command.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex 78d319365..6eb2a0e57 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -5,6 +5,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"object.h\"\n #include \"tree.h\"\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex ca1ebb2fa..c82b4dce6 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex b1706a573..71c0c768d 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"pack.h\"\n #include \"refs.h\"\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 920c16dac..44cdc2dbd 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"commit.h\"\n #include \"refs.h\"\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex addf97ad2..a470ed7c6 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"transport.h\"\n #include \"remote.h\"\ndiff --git a/builtin/repack.c b/builtin/repack.c\nindex 38ba4ef82..f17a68a17 100644\n--- a/builtin/repack.c\n+++ b/builtin/repack.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\n #include \"run-command.h\"\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex c921bc976..80a15cf35 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -9,6 +9,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/rerere.c b/builtin/rerere.c\nindex 1bf72423b..ffb66e290 100644\n--- a/builtin/rerere.c\n+++ b/builtin/rerere.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 430602d10..d0b604103 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -8,6 +8,7 @@\n  * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"tag.h\"\n #include \"object.h\"\ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex 718c6059c..f8e2b7bf5 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n #include \"revision.h\"\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex efdc14473..c78b7b33d 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"quote.h\"\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 345d9586a..16028b9ea 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n #include \"diff.h\"\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex 7c323d012..824d1de9e 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds 2006\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"cache-tree.h\"\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex b8e2e74fe..633e0c3cd 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\ndiff --git a/builtin/shortlog.c b/builtin/shortlog.c\nindex 7cff1839f..43c4799ea 100644\n--- a/builtin/shortlog.c\n+++ b/builtin/shortlog.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n #include \"string-list.h\"\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 4a6cc6f49..e4cf1b5bb 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 1e62a008c..bdf032886 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"strbuf.h\"\n \ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 8cc648d85..4dcbfb952 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"parse-options.h\"\n #include \"quote.h\"\n #include \"pathspec.h\"\ndiff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c\nindex 70addef15..df75cb9d4 100644\n--- a/builtin/symbolic-ref.c\n+++ b/builtin/symbolic-ref.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"cache.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1f74a56db..01154ea8d 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -7,6 +7,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"refs.h\"\n #include \"tag.h\"\ndiff --git a/builtin/unpack-file.c b/builtin/unpack-file.c\nindex 6fc6bcdf7..73f133419 100644\n--- a/builtin/unpack-file.c\n+++ b/builtin/unpack-file.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n \n static char *create_temp_file(unsigned char *sha1)\n {\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 8bc999776..193f8b9d5 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"object.h\"\n #include \"delta.h\"\n #include \"pack.h\"\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex ebfc09faa..0a4c23648 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"quote.h\"\n #include \"cache-tree.h\"\ndiff --git a/builtin/update-ref.c b/builtin/update-ref.c\nindex 0b2ecf41a..40ccfc193 100644\n--- a/builtin/update-ref.c\n+++ b/builtin/update-ref.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/update-server-info.c b/builtin/update-server-info.c\nindex 6c8cc3edc..873070e51 100644\n--- a/builtin/update-server-info.c\n+++ b/builtin/update-server-info.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n \ndiff --git a/builtin/var.c b/builtin/var.c\nindex aedbb53a2..6c6f46b4a 100644\n--- a/builtin/var.c\n+++ b/builtin/var.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) Eric Biederman, 2005\n  */\n #include \"builtin.h\"\n+#include \"config.h\"\n \n static const char var_usage[] = \"git var (-l | <variable>)\";\n \ndiff --git a/builtin/verify-commit.c b/builtin/verify-commit.c\nindex 05b734e6d..ba38ac9b1 100644\n--- a/builtin/verify-commit.c\n+++ b/builtin/verify-commit.c\n@@ -6,6 +6,7 @@\n  * Based on git-verify-tag\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"commit.h\"\n #include \"run-command.h\"\ndiff --git a/builtin/verify-pack.c b/builtin/verify-pack.c\nindex c94e15693..c2a1a5c50 100644\n--- a/builtin/verify-pack.c\n+++ b/builtin/verify-pack.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"run-command.h\"\n #include \"parse-options.h\"\n \ndiff --git a/builtin/verify-tag.c b/builtin/verify-tag.c\nindex 5199553d9..f9a5f7535 100644\n--- a/builtin/verify-tag.c\n+++ b/builtin/verify-tag.c\n@@ -6,6 +6,7 @@\n  * Based on git-verify-tag.sh\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"tag.h\"\n #include \"run-command.h\"\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 793306ea5..0c5476ee9 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\ndiff --git a/builtin/write-tree.c b/builtin/write-tree.c\nindex 084c0df78..bd0a78aa3 100644\n--- a/builtin/write-tree.c\n+++ b/builtin/write-tree.c\n@@ -5,6 +5,7 @@\n  */\n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tree.h\"\n #include \"cache-tree.h\"\n #include \"parse-options.h\"\ndiff --git a/cache.h b/cache.h\nindex a27fee458..272f8e021 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -11,7 +11,6 @@\n #include \"string-list.h\"\n #include \"pack-revindex.h\"\n #include \"hash.h\"\n-#include \"config.h\"\n \n #ifndef platform_SHA_CTX\n /*\ndiff --git a/color.c b/color.c\nindex dee61557e..31b6207a0 100644\n--- a/color.c\n+++ b/color.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"color.h\"\n \n static int git_use_color_default = GIT_COLOR_AUTO;\ndiff --git a/column.c b/column.c\nindex d55ead18e..ff7bdab1a 100644\n--- a/column.c\n+++ b/column.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"column.h\"\n #include \"string-list.h\"\n #include \"parse-options.h\"\ndiff --git a/config.c b/config.c\nindex 146cb3452..2390f98e3 100644\n--- a/config.c\n+++ b/config.c\n@@ -6,6 +6,7 @@\n  *\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"exec_cmd.h\"\n #include \"strbuf.h\"\ndiff --git a/connect.c b/connect.c\nindex cd21a1b6f..efddb30ea 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"pkt-line.h\"\n #include \"quote.h\"\n #include \"refs.h\"\ndiff --git a/convert.c b/convert.c\nindex f1e168bc3..5f4a4b1f5 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"attr.h\"\n #include \"run-command.h\"\n #include \"quote.h\"\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex f3814cc47..0d5c62509 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tempfile.h\"\n #include \"credential.h\"\n #include \"unix-socket.h\"\ndiff --git a/credential.c b/credential.c\nindex aa996669f..67a523353 100644\n--- a/credential.c\n+++ b/credential.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"credential.h\"\n #include \"string-list.h\"\n #include \"run-command.h\"\ndiff --git a/daemon.c b/daemon.c\nindex ac7181a48..30747075f 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"pkt-line.h\"\n #include \"run-command.h\"\n #include \"strbuf.h\"\ndiff --git a/diff.c b/diff.c\nindex f3546536b..2f2467c6d 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2,6 +2,7 @@\n  * Copyright (C) 2005 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tempfile.h\"\n #include \"quote.h\"\n #include \"diff.h\"\ndiff --git a/dir.c b/dir.c\nindex 3f3167e55..0c26a53d2 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -9,6 +9,7 @@\n  */\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"attr.h\"\n #include \"refs.h\"\ndiff --git a/environment.c b/environment.c\nindex aa478e71d..d40b21fb7 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,7 @@\n  * are.\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"fmt-merge-msg.h\"\n #include \"commit.h\"\ndiff --git a/fast-import.c b/fast-import.c\nindex e69d21968..2881d4898 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -154,6 +154,7 @@ Format of STDIN stream:\n \n #include \"builtin.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"object.h\"\n #include \"blob.h\"\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex cd86865be..fbbc99c88 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\ndiff --git a/git.c b/git.c\nindex 8ff44f081..594436e43 100644\n--- a/git.c\n+++ b/git.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"exec_cmd.h\"\n #include \"help.h\"\n #include \"run-command.h\"\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex e44cc27da..8ab32df45 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"run-command.h\"\n #include \"strbuf.h\"\n #include \"gpg-interface.h\"\ndiff --git a/graph.c b/graph.c\nindex 8b9049dd2..e7e20650d 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"color.h\"\n #include \"graph.h\"\ndiff --git a/grep.c b/grep.c\nindex 47cee4506..d5211fc5a 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"grep.h\"\n #include \"userdiff.h\"\n #include \"xdiff-interface.h\"\ndiff --git a/help.c b/help.c\nindex db7f3d79a..5d44f811a 100644\n--- a/help.c\n+++ b/help.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"run-command.h\"\ndiff --git a/http-backend.c b/http-backend.c\nindex ba5ff1aa2..519025d2c 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\n #include \"object.h\"\ndiff --git a/http-fetch.c b/http-fetch.c\nindex 3b556d661..8af380050 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"exec_cmd.h\"\n #include \"http.h\"\n #include \"walker.h\"\ndiff --git a/http.c b/http.c\nindex d2e11ec6f..013bb0cc6 100644\n--- a/http.c\n+++ b/http.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"http.h\"\n+#include \"config.h\"\n #include \"pack.h\"\n #include \"sideband.h\"\n #include \"run-command.h\"\ndiff --git a/ident.c b/ident.c\nindex bea871c8e..d41fc9119 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -6,6 +6,7 @@\n  * Copyright (C) 2005 Linus Torvalds\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n \n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\ndiff --git a/imap-send.c b/imap-send.c\nindex 857591660..59e9b12d2 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -23,6 +23,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"credential.h\"\n #include \"exec_cmd.h\"\n #include \"run-command.h\"\ndiff --git a/ll-merge.c b/ll-merge.c\nindex ac0d4a5d7..24ff94e1d 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -5,6 +5,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"attr.h\"\n #include \"xdiff-interface.h\"\n #include \"run-command.h\"\ndiff --git a/log-tree.c b/log-tree.c\nindex a4ec11c2b..7e1dfd749 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n #include \"tag.h\"\ndiff --git a/mailinfo.c b/mailinfo.c\nindex f92cb9f72..f59162453 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"utf8.h\"\n #include \"strbuf.h\"\n #include \"mailinfo.h\"\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex ae5238d82..c2494f34f 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -4,6 +4,7 @@\n  * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"advice.h\"\n #include \"lockfile.h\"\n #include \"cache-tree.h\"\ndiff --git a/notes-utils.c b/notes-utils.c\nindex 325ff3daa..ebde2273c 100644\n--- a/notes-utils.c\n+++ b/notes-utils.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"notes-utils.h\"\ndiff --git a/notes.c b/notes.c\nindex 542563b28..dbcfef4d7 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"notes.h\"\n #include \"blob.h\"\n #include \"tree.h\"\ndiff --git a/pager.c b/pager.c\nindex c113d898a..4dd9e1b26 100644\n--- a/pager.c\n+++ b/pager.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n \ndiff --git a/parse-options.c b/parse-options.c\nindex a23a1e67f..cbf84a604 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -1,6 +1,7 @@\n #include \"git-compat-util.h\"\n #include \"parse-options.h\"\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"color.h\"\n #include \"utf8.h\"\ndiff --git a/pathspec.c b/pathspec.c\nindex 828405021..ecc5331c2 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -1,5 +1,6 @@\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"pathspec.h\"\n #include \"attr.h\"\ndiff --git a/pretty.c b/pretty.c\nindex 09701bd2f..9c9f81b5b 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"utf8.h\"\n #include \"diff.h\"\ndiff --git a/prompt.c b/prompt.c\nindex 75406390c..6d5885d00 100644\n--- a/prompt.c\n+++ b/prompt.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"run-command.h\"\n #include \"strbuf.h\"\n #include \"prompt.h\"\ndiff --git a/read-cache.c b/read-cache.c\nindex 92eb15c00..2650ad98a 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -5,6 +5,7 @@\n  */\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tempfile.h\"\n #include \"lockfile.h\"\n #include \"cache-tree.h\"\ndiff --git a/refs.c b/refs.c\nindex 8af9641aa..7dfdc08bf 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -3,6 +3,7 @@\n  */\n \n #include \"cache.h\"\n+#include \"config.h\"\n #include \"hashmap.h\"\n #include \"lockfile.h\"\n #include \"iterator.h\"\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex cb1f528cb..f88b94484 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1,4 +1,5 @@\n #include \"../cache.h\"\n+#include \"../config.h\"\n #include \"../refs.h\"\n #include \"refs-internal.h\"\n #include \"ref-cache.h\"\ndiff --git a/remote-curl.c b/remote-curl.c\nindex ece45993d..0053b0954 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"remote.h\"\n #include \"strbuf.h\"\n #include \"walker.h\"\ndiff --git a/remote.c b/remote.c\nindex fdc52d802..a84e68767 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"remote.h\"\n #include \"refs.h\"\n #include \"commit.h\"\ndiff --git a/rerere.c b/rerere.c\nindex 3bd55caf3..344d6aa81 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"string-list.h\"\n #include \"rerere.h\"\ndiff --git a/send-pack.c b/send-pack.c\nindex 78bb34ebe..ed3cee321 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"config.h\"\n #include \"commit.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\ndiff --git a/sequencer.c b/sequencer.c\nindex a23b948ac..b9962dc89 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"lockfile.h\"\n #include \"sequencer.h\"\n #include \"dir.h\"\ndiff --git a/setup.c b/setup.c\nindex e3f7699a9..e99a82cbe 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"string-list.h\"\n \ndiff --git a/sha1_file.c b/sha1_file.c\nindex 59a4ed2ed..44561e0b9 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -7,6 +7,7 @@\n  * creation etc.\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"string-list.h\"\n #include \"lockfile.h\"\n #include \"delta.h\"\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 389276e9d..0ad85ec54 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"tag.h\"\n #include \"commit.h\"\n #include \"tree.h\"\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4f58491dd..d8f8d5ea3 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n #include \"strbuf.h\"\ndiff --git a/submodule.c b/submodule.c\nindex bf5a93d16..95328de61 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n #include \"dir.h\"\ndiff --git a/t/helper/test-config.c b/t/helper/test-config.c\nindex 8e3ed6a76..1a7b8bd3d 100644\n--- a/t/helper/test-config.c\n+++ b/t/helper/test-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"string-list.h\"\n \n /*\ndiff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c\nindex 2f144d539..c6c57bba0 100644\n--- a/t/helper/test-submodule-config.c\n+++ b/t/helper/test-submodule-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n \ndiff --git a/trailer.c b/trailer.c\nindex 11f0b9fb4..751b56c00 100644\n--- a/trailer.c\n+++ b/trailer.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"string-list.h\"\n #include \"run-command.h\"\n #include \"commit.h\"\ndiff --git a/transport.c b/transport.c\nindex 9bfcf870f..b9995306f 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"transport.h\"\n #include \"run-command.h\"\n #include \"pkt-line.h\"\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex d38c37e38..dd535bc84 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1,5 +1,6 @@\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"dir.h\"\n #include \"tree.h\"\n #include \"tree-walk.h\"\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 5330c02c1..7efff2fbf 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\n #include \"sideband.h\"\ndiff --git a/userdiff.c b/userdiff.c\nindex 8b732e40b..2c1502f71 100644\n--- a/userdiff.c\n+++ b/userdiff.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"userdiff.h\"\n #include \"attr.h\"\n \ndiff --git a/versioncmp.c b/versioncmp.c\nindex 9f81dc106..069ee94a4 100644\n--- a/versioncmp.c\n+++ b/versioncmp.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"string-list.h\"\n \n /*\ndiff --git a/wrapper.c b/wrapper.c\nindex d83741770..487a9f753 100644\n--- a/wrapper.c\n+++ b/wrapper.c\n@@ -2,6 +2,7 @@\n  * Various trivial helper wrappers around standard functions\n  */\n #include \"cache.h\"\n+#include \"config.h\"\n \n static void do_nothing(size_t size)\n {\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex 060038c2d..5ac07d734 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"xdiff-interface.h\"\n #include \"xdiff/xtypes.h\"\n #include \"xdiff/xdiffi.h\"\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321783","messageId":"20170608234100.188529-6-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 05/32] setup: don't perform lazy initialization of repository state","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:33Z","receivedAt":"2017-06-08T23:41:36Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Under some circumstances (bogus GIT_DIR value or the discovered gitdir\nis '.git') 'setup_git_directory()' won't initialize key repository\nstate.  This leads to inconsistent state after running the setup code.\nTo account for this inconsistent state, lazy initialization is done once\na caller asks for the repository's gitdir or some other piece of\nrepository state.  This is confusing and can be error prone.\n\nInstead let's tighten the expected outcome of 'setup_git_directory()'\nand ensure that it initializes repository state in all cases that would\nhave been handled by lazy initialization.\n\nThis also lets us drop the requirement to have 'have_git_dir()' check if\nthe environment variable GIT_DIR was set as that will be handled by the\nend of the setup code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h       |  2 ++\n environment.c | 17 ++++++++---------\n setup.c       | 14 ++++++++++++++\n 3 files changed, 24 insertions(+), 9 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 272f8e021..d41aab82f 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -462,6 +462,8 @@ static inline enum object_type object_type(unsigned int mode)\n  */\n extern const char * const local_repo_env[];\n \n+extern void setup_git_env(void);\n+\n /*\n  * Returns true iff we have a configured git repository (either via\n  * setup_git_directory, or in the environment via $GIT_DIR).\ndiff --git a/environment.c b/environment.c\nindex d40b21fb7..a73b08f5d 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -160,7 +160,7 @@ static char *git_path_from_env(const char *envvar, const char *git_dir,\n \treturn xstrdup(value);\n }\n \n-static void setup_git_env(void)\n+void setup_git_env(void)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *gitfile;\n@@ -205,28 +205,27 @@ int is_bare_repository(void)\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n-\t\t|| git_dir\n-\t\t|| getenv(GIT_DIR_ENVIRONMENT);\n+\t\t|| git_dir;\n }\n \n const char *get_git_dir(void)\n {\n \tif (!git_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_dir;\n }\n \n const char *get_git_common_dir(void)\n {\n \tif (!git_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_common_dir;\n }\n \n const char *get_git_namespace(void)\n {\n \tif (!namespace)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn namespace;\n }\n \n@@ -276,7 +275,7 @@ const char *get_git_work_tree(void)\n char *get_object_directory(void)\n {\n \tif (!git_object_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_object_dir;\n }\n \n@@ -316,14 +315,14 @@ int odb_pack_keep(const char *name)\n char *get_index_file(void)\n {\n \tif (!git_index_file)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_index_file;\n }\n \n char *get_graft_file(void)\n {\n \tif (!git_graft_file)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_graft_file;\n }\n \ndiff --git a/setup.c b/setup.c\nindex e99a82cbe..b2e05145c 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1063,6 +1063,20 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \tstartup_info->have_repository = !nongit_ok || !*nongit_ok;\n \tstartup_info->prefix = prefix;\n \n+\t/*\n+\t * Not all paths through the setup code will call 'set_git_dir()' (which\n+\t * directly sets up the environment) so in order to guarantee that the\n+\t * environment is in a consistent state after setup, explicitly setup\n+\t * the environment if we have a repository.\n+\t *\n+\t * NEEDSWORK: currently we allow bogus GIT_DIR values to be set in some\n+\t * code paths so we also need to explicitly setup the environment if\n+\t * the user has set GIT_DIR.  It may be beneficial to disallow bogus\n+\t * GIT_DIR values at some point in the future.\n+\t */\n+\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT))\n+\t\tsetup_git_env();\n+\n \tstrbuf_release(&dir);\n \tstrbuf_release(&gitdir);\n \n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321784","messageId":"20170608234100.188529-8-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 07/32] repository: introduce the repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:35Z","receivedAt":"2017-06-08T23:41:38Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce the repository object 'struct repository' which can be used to\nhold all state pertaining to a git repository.\n\nSome of the benefits of object-ifying a repository are:\n\n  1. Make the code base more readable and easier to reason about.\n\n  2. Allow for working on multiple repositories, specifically\n     submodules, within the same process.  Currently the process for\n     working on a submodule involves setting up an argv_array of options\n     for a particular command and then launching a child process to\n     execute the command in the context of the submodule.  This is\n     clunky and can require lots of little hacks in order to ensure\n     correctness.  Ideally it would be nice to simply pass a repository\n     and an options struct to a command.\n\n  3. Eliminating reliance on global state will make it easier to\n     enable the use of threading to improve performance.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Makefile      |   1 +\n cache.h       |   1 +\n environment.c |   2 +-\n repository.c  | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n repository.h  |  25 +++++++++\n 5 files changed, 199 insertions(+), 1 deletion(-)\n create mode 100644 repository.c\n create mode 100644 repository.h\n\ndiff --git a/Makefile b/Makefile\nindex 2ed6db728..ac82d93f6 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -821,6 +821,7 @@ LIB_OBJS += refs/ref-cache.o\n LIB_OBJS += ref-filter.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\n+LIB_OBJS += repository.o\n LIB_OBJS += rerere.o\n LIB_OBJS += resolve-undo.o\n LIB_OBJS += revision.o\ndiff --git a/cache.h b/cache.h\nindex d41aab82f..c0b4c8d83 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -483,6 +483,7 @@ extern char *get_graft_file(void);\n extern int set_git_dir(const char *path);\n extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n extern int get_common_dir(struct strbuf *sb, const char *gitdir);\n+extern char *expand_namespace(const char *raw_namespace);\n extern const char *get_git_namespace(void);\n extern const char *strip_namespace(const char *namespaced_ref);\n extern const char *get_super_prefix(void);\ndiff --git a/environment.c b/environment.c\nindex e035f6372..77900b31a 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -127,7 +127,7 @@ const char * const local_repo_env[] = {\n \tNULL\n };\n \n-static char *expand_namespace(const char *raw_namespace)\n+char *expand_namespace(const char *raw_namespace)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct strbuf **components, **c;\ndiff --git a/repository.c b/repository.c\nnew file mode 100644\nindex 000000000..e952238d1\n--- /dev/null\n+++ b/repository.c\n@@ -0,0 +1,171 @@\n+#include \"cache.h\"\n+#include \"repository.h\"\n+\n+/* The main repository */\n+static struct repository the_repo;\n+struct repository *the_repository = &the_repo;\n+\n+static char *git_path_from_env(const char *envvar, const char *git_dir,\n+\t\t\t       const char *path, int fromenv)\n+{\n+\tif (fromenv) {\n+\t\tconst char *value = getenv(envvar);\n+\t\tif (value)\n+\t\t\treturn xstrdup(value);\n+\t}\n+\n+\treturn xstrfmt(\"%s/%s\", git_dir, path);\n+}\n+\n+static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)\n+{\n+\tif (fromenv) {\n+\t\tconst char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n+\t\tif (value) {\n+\t\t\tstrbuf_addstr(sb, value);\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\n+\treturn get_common_dir_noenv(sb, gitdir);\n+}\n+\n+/* called after setting gitdir */\n+static void repo_setup_env(struct repository *repo)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tif (!repo->gitdir)\n+\t\tBUG(\"gitdir wasn't set before setting up the environment\");\n+\n+\trepo->different_commondir = find_common_dir(&sb, repo->gitdir,\n+\t\t\t\t\t\t    !repo->ignore_env);\n+\trepo->commondir = strbuf_detach(&sb, NULL);\n+\trepo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,\n+\t\t\t\t\t    \"objects\", !repo->ignore_env);\n+\trepo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,\n+\t\t\t\t\t     \"index\", !repo->ignore_env);\n+\trepo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,\n+\t\t\t\t\t     \"info/grafts\", !repo->ignore_env);\n+\trepo->namespace = expand_namespace(repo->ignore_env ? NULL :\n+\t\t\t\t\t   getenv(GIT_NAMESPACE_ENVIRONMENT));\n+}\n+\n+void repo_set_gitdir(struct repository *repo, const char *path)\n+{\n+\tconst char *gitfile = read_gitfile(path);\n+\n+\t/*\n+\t * NEEDSWORK: Eventually we want to be able to free gitdir and the rest\n+\t * of the environment before reinitializing it again, but we have some\n+\t * crazy code paths where we try to set gitdir with the current gitdir\n+\t * and we don't want to free gitdir before copying the passed in value.\n+\t */\n+\trepo->gitdir = xstrdup(gitfile ? gitfile : path);\n+\n+\trepo_setup_env(repo);\n+}\n+\n+/*\n+ * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.\n+ * Return 0 upon success and a non-zero value upon failure.\n+ */\n+static int repo_init_gitdir(struct repository *repo, const char *gitdir)\n+{\n+\tint ret = 0;\n+\tint error = 0;\n+\tchar *abspath = NULL;\n+\tchar *suspect = NULL;\n+\tconst char *resolved_gitdir;\n+\n+\tabspath = real_pathdup(gitdir, 0);\n+\tif (!abspath) {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\t/* First assume 'gitdir' references the gitdir directly */\n+\tresolved_gitdir = resolve_gitdir_gently(abspath, &error);\n+\t/* otherwise; try 'gitdir'.git */\n+\tif (!resolved_gitdir) {\n+\t\tsuspect = xstrfmt(\"%s/.git\", abspath);\n+\t\tresolved_gitdir = resolve_gitdir_gently(suspect, &error);\n+\t\tif (!resolved_gitdir) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\t}\n+\n+\trepo_set_gitdir(repo, resolved_gitdir);\n+\n+out:\n+\tfree(abspath);\n+\tfree(suspect);\n+\treturn ret;\n+}\n+\n+static int verify_repo_format(struct repository_format *format,\n+\t\t\t      const char *commondir)\n+{\n+\tint ret = 0;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tstrbuf_addf(&sb, \"%s/config\", commondir);\n+\tread_repository_format(format, sb.buf);\n+\tstrbuf_reset(&sb);\n+\n+\tif (verify_repository_format(format, &sb) < 0) {\n+\t\twarning(\"%s\", sb.buf);\n+\t\tret = -1;\n+\t}\n+\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n+/*\n+ * Initialize 'repo' based on the provided 'gitdir'.\n+ * Return 0 upon success and a non-zero value upon failure.\n+ */\n+int repo_init(struct repository *repo, const char *gitdir)\n+{\n+\tstruct repository_format format;\n+\tmemset(repo, 0, sizeof(*repo));\n+\n+\trepo->ignore_env = 1;\n+\n+\tif (repo_init_gitdir(repo, gitdir))\n+\t\tgoto error;\n+\n+\tif (verify_repo_format(&format, repo->commondir))\n+\t\tgoto error;\n+\n+\treturn 0;\n+\n+error:\n+\trepo_clear(repo);\n+\treturn -1;\n+}\n+\n+static void repo_clear_env(struct repository *repo)\n+{\n+\tfree(repo->gitdir);\n+\trepo->gitdir = NULL;\n+\tfree(repo->commondir);\n+\trepo->commondir = NULL;\n+\tfree(repo->objectdir);\n+\trepo->objectdir = NULL;\n+\tfree(repo->index_file);\n+\trepo->index_file = NULL;\n+\tfree(repo->graft_file);\n+\trepo->graft_file = NULL;\n+\tfree(repo->namespace);\n+\trepo->namespace = NULL;\n+}\n+\n+void repo_clear(struct repository *repo)\n+{\n+\trepo_clear_env(repo);\n+\n+\tmemset(repo, 0, sizeof(*repo));\n+}\ndiff --git a/repository.h b/repository.h\nnew file mode 100644\nindex 000000000..174ab0f2d\n--- /dev/null\n+++ b/repository.h\n@@ -0,0 +1,25 @@\n+#ifndef REPOSITORY_H\n+#define REPOSITORY_H\n+\n+struct repository {\n+\t/* Environment */\n+\tchar *gitdir;\n+\tchar *commondir;\n+\tchar *objectdir;\n+\tchar *index_file;\n+\tchar *graft_file;\n+\tchar *namespace;\n+\n+\t/* Configurations */\n+\tunsigned ignore_env:1;\n+\t/* Indicates if a repository has a different 'commondir' from 'gitdir' */\n+\tunsigned different_commondir:1;\n+};\n+\n+extern struct repository *the_repository;\n+\n+extern void repo_set_gitdir(struct repository *repo, const char *path);\n+extern int repo_init(struct repository *repo, const char *path);\n+extern void repo_clear(struct repository *repo);\n+\n+#endif /* REPOSITORY_H */\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321785","messageId":"20170608234100.188529-11-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 10/32] setup: add comment indicating a hack","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:38Z","receivedAt":"2017-06-08T23:41:39Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"'GIT_TOPLEVEL_PREFIX_ENVIRONMENT' was added in (b58a68c1c setup: allow\nfor prefix to be passed to git commands) to aid in fixing a bug where\n'ls-files' and 'grep' were not able to properly recurse when called from\nwithin a subdirectory.  Add a 'NEEDSWORK' comment indicating that this\nenvvar should be removed once 'ls-files' and 'grep' can recurse\nin-process.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n setup.c | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/setup.c b/setup.c\nindex 884a74a54..aca1cf5d3 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1057,6 +1057,12 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t\tdie(\"BUG: unhandled setup_git_directory_1() result\");\n \t}\n \n+\t/*\n+\t * NEEDSWORK: This was a hack in order to get ls-files and grep to have\n+\t * properly formated output when recursing submodules.  Once ls-files\n+\t * and grep have been changed to perform this recursing in-process this\n+\t * needs to be removed.\n+\t */\n \tenv_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT);\n \tif (env_prefix)\n \t\tprefix = env_prefix;\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321786","messageId":"20170608234100.188529-7-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 06/32] environment: remove namespace_len variable","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:34Z","receivedAt":"2017-06-08T23:41:43Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Use 'skip_prefix' instead of 'starts_with' so that we can drop the need\nto keep around 'namespace_len'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n environment.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex a73b08f5d..e035f6372 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -98,7 +98,6 @@ char *git_work_tree_cfg;\n static char *work_tree;\n \n static const char *namespace;\n-static size_t namespace_len;\n \n static const char *super_prefix;\n \n@@ -190,7 +189,6 @@ void setup_git_env(void)\n \tgit_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base\n \t\t\t\t\t\t\t  : \"refs/replace/\");\n \tnamespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));\n-\tnamespace_len = strlen(namespace);\n \tshallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);\n \tif (shallow_file)\n \t\tset_alternate_shallow_file(shallow_file, 0);\n@@ -231,9 +229,10 @@ const char *get_git_namespace(void)\n \n const char *strip_namespace(const char *namespaced_ref)\n {\n-\tif (!starts_with(namespaced_ref, get_git_namespace()))\n-\t\treturn NULL;\n-\treturn namespaced_ref + namespace_len;\n+\tconst char *out;\n+\tif (skip_prefix(namespaced_ref, get_git_namespace(), &out))\n+\t\treturn out;\n+\treturn NULL;\n }\n \n const char *get_super_prefix(void)\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321787","messageId":"20170608234100.188529-10-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 09/32] environment: store worktree in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:37Z","receivedAt":"2017-06-08T23:41:46Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate 'work_tree' to be stored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n environment.c |  9 ++++-----\n repository.c  | 12 ++++++++++++\n repository.h  |  3 +++\n 3 files changed, 19 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex fb52c0daf..e390a6627 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -96,7 +96,6 @@ int ignore_untracked_cache_config;\n \n /* This is set by setup_git_dir_gently() and/or git_default_config() */\n char *git_work_tree_cfg;\n-static char *work_tree;\n \n static const char *super_prefix;\n \n@@ -220,19 +219,19 @@ void set_git_work_tree(const char *new_work_tree)\n {\n \tif (git_work_tree_initialized) {\n \t\tnew_work_tree = real_path(new_work_tree);\n-\t\tif (strcmp(new_work_tree, work_tree))\n+\t\tif (strcmp(new_work_tree, the_repository->worktree))\n \t\t\tdie(\"internal error: work tree has already been set\\n\"\n \t\t\t    \"Current worktree: %s\\nNew worktree: %s\",\n-\t\t\t    work_tree, new_work_tree);\n+\t\t\t    the_repository->worktree, new_work_tree);\n \t\treturn;\n \t}\n \tgit_work_tree_initialized = 1;\n-\twork_tree = real_pathdup(new_work_tree, 1);\n+\trepo_set_worktree(the_repository, new_work_tree);\n }\n \n const char *get_git_work_tree(void)\n {\n-\treturn work_tree;\n+\treturn the_repository->worktree;\n }\n \n char *get_object_directory(void)\ndiff --git a/repository.c b/repository.c\nindex e952238d1..1b48cc816 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -104,6 +104,16 @@ static int repo_init_gitdir(struct repository *repo, const char *gitdir)\n \treturn ret;\n }\n \n+void repo_set_worktree(struct repository *repo, const char *path)\n+{\n+\trepo->worktree = real_pathdup(path, 1);\n+}\n+\n+char *repo_worktree_path(struct repository *repo, const char *path)\n+{\n+\treturn xstrfmt(\"%s/%s\", repo->worktree, path);\n+}\n+\n static int verify_repo_format(struct repository_format *format,\n \t\t\t      const char *commondir)\n {\n@@ -166,6 +176,8 @@ static void repo_clear_env(struct repository *repo)\n void repo_clear(struct repository *repo)\n {\n \trepo_clear_env(repo);\n+\tfree(repo->worktree);\n+\trepo->worktree = NULL;\n \n \tmemset(repo, 0, sizeof(*repo));\n }\ndiff --git a/repository.h b/repository.h\nindex 174ab0f2d..a1163ae91 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -9,6 +9,7 @@ struct repository {\n \tchar *index_file;\n \tchar *graft_file;\n \tchar *namespace;\n+\tchar *worktree;\n \n \t/* Configurations */\n \tunsigned ignore_env:1;\n@@ -19,6 +20,8 @@ struct repository {\n extern struct repository *the_repository;\n \n extern void repo_set_gitdir(struct repository *repo, const char *path);\n+extern void repo_set_worktree(struct repository *repo, const char *path);\n+extern char *repo_worktree_path(struct repository *repo, const char *path);\n extern int repo_init(struct repository *repo, const char *path);\n extern void repo_clear(struct repository *repo);\n \n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321788","messageId":"20170608234100.188529-17-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 16/32] convert: convert get_cached_convert_stats_ascii to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:44Z","receivedAt":"2017-06-08T23:41:48Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 3 ++-\n convert.c          | 5 +++--\n convert.h          | 5 ++++-\n 3 files changed, 9 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex c4357dc30..f16ce0053 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -64,7 +64,8 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path)\n \t\tconst char *w_txt = \"\";\n \t\tconst char *a_txt = get_convert_attr_ascii(path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n-\t\t\ti_txt = get_cached_convert_stats_ascii(ce->name);\n+\t\t\ti_txt = get_cached_convert_stats_ascii(&the_index,\n+\t\t\t\t\t\t\t       ce->name);\n \t\tif (!lstat(path, &st) && S_ISREG(st.st_mode))\n \t\t\tw_txt = get_wt_convert_stats_ascii(path);\n \t\tprintf(\"i/%-5s w/%-5s attr/%-17s\\t\", i_txt, w_txt, a_txt);\ndiff --git a/convert.c b/convert.c\nindex 5f4a4b1f5..574003023 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -135,11 +135,12 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n-const char *get_cached_convert_stats_ascii(const char *path)\n+const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n+\t\t\t\t\t   const char *path)\n {\n \tconst char *ret;\n \tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n+\tvoid *data = read_blob_data_from_index(istate, path, &sz);\n \tret = gather_convert_stats_ascii(data, sz);\n \tfree(data);\n \treturn ret;\ndiff --git a/convert.h b/convert.h\nindex 82871a11d..667b7dfe0 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -4,6 +4,8 @@\n #ifndef CONVERT_H\n #define CONVERT_H\n \n+struct index_state;\n+\n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\n \tSAFE_CRLF_FAIL = 1,\n@@ -33,7 +35,8 @@ enum eol {\n };\n \n extern enum eol core_eol;\n-extern const char *get_cached_convert_stats_ascii(const char *path);\n+extern const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n+\t\t\t\t\t\t  const char *path);\n extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n \n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321789","messageId":"20170608234100.188529-15-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 14/32] submodule: add repo_read_gitmodules","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:42Z","receivedAt":"2017-06-08T23:41:51Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach the repo object to be able to populate the submodule_cache by\nreading the repository's gitmodules file.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n submodule.c | 15 +++++++++++++++\n submodule.h |  2 ++\n 2 files changed, 17 insertions(+)\n\ndiff --git a/submodule.c b/submodule.c\nindex 95328de61..65f60ab57 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n@@ -202,6 +203,20 @@ void gitmodules_config(void)\n \t}\n }\n \n+static int gitmodules_cb(const char *var, const char *value, void *data)\n+{\n+\tstruct repository *repo = data;\n+\treturn submodule_config_option(repo, var, value);\n+}\n+\n+void repo_read_gitmodules(struct repository *repo)\n+{\n+\tchar *gitmodules_path = repo_worktree_path(repo, \".gitmodules\");\n+\n+\tgit_config_from_file(gitmodules_cb, gitmodules_path, repo);\n+\tfree(gitmodules_path);\n+}\n+\n void gitmodules_config_sha1(const unsigned char *commit_sha1)\n {\n \tstruct strbuf rev = STRBUF_INIT;\ndiff --git a/submodule.h b/submodule.h\nindex 8fb0f2549..ec6ea8dfd 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -1,6 +1,7 @@\n #ifndef SUBMODULE_H\n #define SUBMODULE_H\n \n+struct repository;\n struct diff_options;\n struct argv_array;\n struct oid_array;\n@@ -40,6 +41,7 @@ extern void set_diffopt_flags_from_submodule_config(struct diff_options *,\n \t\tconst char *path);\n extern int submodule_config(const char *var, const char *value, void *cb);\n extern void gitmodules_config(void);\n+extern void repo_read_gitmodules(struct repository *repo);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n extern int is_submodule_initialized(const char *path);\n /*\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321790","messageId":"20170608234100.188529-20-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 19/32] convert: convert convert_to_git to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:47Z","receivedAt":"2017-06-08T23:41:53Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n apply.c         | 2 +-\n builtin/blame.c | 2 +-\n combine-diff.c  | 2 +-\n convert.c       | 7 ++++---\n convert.h       | 8 +++++---\n diff.c          | 6 +++---\n dir.c           | 2 +-\n sha1_file.c     | 4 ++--\n 8 files changed, 18 insertions(+), 15 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 87db9618d..8eca54325 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -2268,7 +2268,7 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)\n \tcase S_IFREG:\n \t\tif (strbuf_read_file(buf, path, st->st_size) != st->st_size)\n \t\t\treturn error(_(\"unable to open or read %s\"), path);\n-\t\tconvert_to_git(path, buf->buf, buf->len, buf, 0);\n+\t\tconvert_to_git(&the_index, path, buf->buf, buf->len, buf, 0);\n \t\treturn 0;\n \tdefault:\n \t\treturn -1;\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex c0ae49298..317d2ec37 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2384,7 +2384,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,\n \t\tif (strbuf_read(&buf, 0, 0) < 0)\n \t\t\tdie_errno(\"failed to read from stdin\");\n \t}\n-\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n+\tconvert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0);\n \torigin->file.ptr = buf.buf;\n \torigin->file.size = buf.len;\n \tpretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 2848034fe..74f723af3 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1053,7 +1053,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\tif (is_file) {\n \t\t\t\tstruct strbuf buf = STRBUF_INIT;\n \n-\t\t\t\tif (convert_to_git(elem->path, result, len, &buf, safe_crlf)) {\n+\t\t\t\tif (convert_to_git(&the_index, elem->path, result, len, &buf, safe_crlf)) {\n \t\t\t\t\tfree(result);\n \t\t\t\t\tresult = strbuf_detach(&buf, &len);\n \t\t\t\t\tresult_size = len;\ndiff --git a/convert.c b/convert.c\nindex 824b606fa..5af6fdf3f 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1085,7 +1085,8 @@ const char *get_convert_attr_ascii(const char *path)\n \treturn \"\";\n }\n \n-int convert_to_git(const char *path, const char *src, size_t len,\n+int convert_to_git(const struct index_state *istate,\n+\t\t   const char *path, const char *src, size_t len,\n                    struct strbuf *dst, enum safe_crlf checksafe)\n {\n \tint ret = 0;\n@@ -1101,7 +1102,7 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\tret |= crlf_to_git(&the_index, path, src, len, dst, ca.crlf_action, checksafe);\n+\tret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, checksafe);\n \tif (ret && dst) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -1172,7 +1173,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n+\treturn ret | convert_to_git(&the_index, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex 3a813a797..60cb41d6a 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -41,15 +41,17 @@ extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n \n /* returns 1 if *dst was used */\n-extern int convert_to_git(const char *path, const char *src, size_t len,\n+extern int convert_to_git(const struct index_state *istate,\n+\t\t\t  const char *path, const char *src, size_t len,\n \t\t\t  struct strbuf *dst, enum safe_crlf checksafe);\n extern int convert_to_working_tree(const char *path, const char *src,\n \t\t\t\t   size_t len, struct strbuf *dst);\n extern int renormalize_buffer(const char *path, const char *src, size_t len,\n \t\t\t      struct strbuf *dst);\n-static inline int would_convert_to_git(const char *path)\n+static inline int would_convert_to_git(const struct index_state *istate,\n+\t\t\t\t       const char *path)\n {\n-\treturn convert_to_git(path, NULL, 0, NULL, 0);\n+\treturn convert_to_git(istate, path, NULL, 0, NULL, 0);\n }\n /* Precondition: would_convert_to_git_filter_fd(path) == true */\n extern void convert_to_git_filter_fd(const struct index_state *istate,\ndiff --git a/diff.c b/diff.c\nindex 2f2467c6d..87ed6d6d3 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2756,7 +2756,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \t * Similarly, if we'd have to convert the file contents anyway, that\n \t * makes the optimization not worthwhile.\n \t */\n-\tif (!want_file && would_convert_to_git(name))\n+\tif (!want_file && would_convert_to_git(&the_index, name))\n \t\treturn 0;\n \n \tlen = strlen(name);\n@@ -2878,7 +2878,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n \t\t * point if the path requires us to run the content\n \t\t * conversion.\n \t\t */\n-\t\tif (size_only && !would_convert_to_git(s->path))\n+\t\tif (size_only && !would_convert_to_git(&the_index, s->path))\n \t\t\treturn 0;\n \n \t\t/*\n@@ -2905,7 +2905,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n \t\t/*\n \t\t * Convert from working tree format to canonical git format\n \t\t */\n-\t\tif (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) {\n+\t\tif (convert_to_git(&the_index, s->path, s->data, s->size, &buf, crlf_warn)) {\n \t\t\tsize_t size = 0;\n \t\t\tmunmap(s->data, s->size);\n \t\t\ts->should_munmap = 0;\ndiff --git a/dir.c b/dir.c\nindex 0c26a53d2..8dc74c5d2 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -796,7 +796,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\t\t (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&\n \t\t\t\t !ce_stage(istate->cache[pos]) &&\n \t\t\t\t ce_uptodate(istate->cache[pos]) &&\n-\t\t\t\t !would_convert_to_git(fname))\n+\t\t\t\t !would_convert_to_git(istate, fname))\n \t\t\t\thashcpy(sha1_stat->sha1,\n \t\t\t\t\tistate->cache[pos]->oid.hash);\n \t\t\telse\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 80e9ef3bb..a900b2804 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -3547,7 +3547,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,\n \t */\n \tif ((type == OBJ_BLOB) && path) {\n \t\tstruct strbuf nbuf = STRBUF_INIT;\n-\t\tif (convert_to_git(path, buf, size, &nbuf,\n+\t\tif (convert_to_git(&the_index, path, buf, size, &nbuf,\n \t\t\t\t   write_object ? safe_crlf : SAFE_CRLF_FALSE)) {\n \t\t\tbuf = strbuf_detach(&nbuf, &size);\n \t\t\tre_allocated = 1;\n@@ -3669,7 +3669,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st,\n \telse if (!S_ISREG(st->st_mode))\n \t\tret = index_pipe(sha1, fd, type, path, flags);\n \telse if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||\n-\t\t (path && would_convert_to_git(path)))\n+\t\t (path && would_convert_to_git(&the_index, path)))\n \t\tret = index_core(sha1, fd, xsize_t(st->st_size), type, path,\n \t\t\t\t flags);\n \telse\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321791","messageId":"20170608234100.188529-23-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 22/32] ls-files: convert overlay_tree_on_cache to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:50Z","receivedAt":"2017-06-08T23:41:59Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/commit.c   |  3 ++-\n builtin/ls-files.c | 15 ++++++++-------\n cache.h            |  3 ++-\n 3 files changed, 12 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 805da4915..3d98084fb 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -254,7 +254,8 @@ static int list_paths(struct string_list *list, const char *with_tree,\n \n \tif (with_tree) {\n \t\tchar *max_prefix = common_prefix(pattern);\n-\t\toverlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix);\n+\t\toverlay_tree_on_index(&the_index, with_tree,\n+\t\t\t\t      max_prefix ? max_prefix : prefix);\n \t\tfree(max_prefix);\n \t}\n \ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 620487a77..a5ceeb052 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -432,7 +432,8 @@ static int get_common_prefix_len(const char *common_prefix)\n  * that were given from the command line.  We are not\n  * going to write this index out.\n  */\n-void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n+void overlay_tree_on_index(struct index_state *istate,\n+\t\t\t   const char *tree_name, const char *prefix)\n {\n \tstruct tree *tree;\n \tstruct object_id oid;\n@@ -447,8 +448,8 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\tdie(\"bad tree-ish %s\", tree_name);\n \n \t/* Hoist the unmerged entries up to stage #3 to make room */\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n \t\tce->ce_flags |= CE_STAGEMASK;\n@@ -461,11 +462,11 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\t\t       PATHSPEC_PREFER_CWD, prefix, matchbuf);\n \t} else\n \t\tmemset(&pathspec, 0, sizeof(pathspec));\n-\tif (read_tree(tree, 1, &pathspec, &the_index))\n+\tif (read_tree(tree, 1, &pathspec, istate))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \t\tswitch (ce_stage(ce)) {\n \t\tcase 0:\n \t\t\tlast_stage0 = ce;\n@@ -680,7 +681,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n-\t\toverlay_tree_on_cache(with_tree, max_prefix);\n+\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n \t}\n \tshow_files(&dir);\n \tif (show_resolve_undo)\ndiff --git a/cache.h b/cache.h\nindex 02ab5f801..73724a3ad 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1993,7 +1993,8 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule);\n #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)\n \n /* ls-files */\n-void overlay_tree_on_cache(const char *tree_name, const char *prefix);\n+void overlay_tree_on_index(struct index_state *istate,\n+\t\t\t   const char *tree_name, const char *prefix);\n \n char *alias_lookup(const char *alias);\n int split_cmdline(char *cmdline, const char ***argv);\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321792","messageId":"20170608234100.188529-24-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 23/32] ls-files: convert write_eolinfo to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:51Z","receivedAt":"2017-06-08T23:42:00Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 13 ++++++-------\n 1 file changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex a5ceeb052..c37e9de11 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -54,17 +54,16 @@ static const char *tag_modified = \"\";\n static const char *tag_skip_worktree = \"\";\n static const char *tag_resolve_undo = \"\";\n \n-static void write_eolinfo(const struct cache_entry *ce, const char *path)\n+static void write_eolinfo(const struct index_state *istate,\n+\t\t\t  const struct cache_entry *ce, const char *path)\n {\n-\tif (!show_eol)\n-\t\treturn;\n-\telse {\n+\tif (show_eol) {\n \t\tstruct stat st;\n \t\tconst char *i_txt = \"\";\n \t\tconst char *w_txt = \"\";\n \t\tconst char *a_txt = get_convert_attr_ascii(path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n-\t\t\ti_txt = get_cached_convert_stats_ascii(&the_index,\n+\t\t\ti_txt = get_cached_convert_stats_ascii(istate,\n \t\t\t\t\t\t\t       ce->name);\n \t\tif (!lstat(path, &st) && S_ISREG(st.st_mode))\n \t\t\tw_txt = get_wt_convert_stats_ascii(path);\n@@ -106,7 +105,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \t\treturn;\n \n \tfputs(tag, stdout);\n-\twrite_eolinfo(NULL, ent->name);\n+\twrite_eolinfo(NULL, NULL, ent->name);\n \twrite_name(ent->name);\n }\n \n@@ -276,7 +275,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n \t\t\t       ce_stage(ce));\n \t\t}\n-\t\twrite_eolinfo(ce, ce->name);\n+\t\twrite_eolinfo(&the_index, ce, ce->name);\n \t\twrite_name(ce->name);\n \t\tif (debug_mode) {\n \t\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321793","messageId":"20170608234100.188529-21-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 20/32] convert: convert renormalize_buffer to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:48Z","receivedAt":"2017-06-08T23:42:03Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c         | 6 ++++--\n convert.h         | 3 ++-\n ll-merge.c        | 2 +-\n merge-recursive.c | 4 ++--\n 4 files changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex 5af6fdf3f..7d2a519da 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"config.h\"\n #include \"attr.h\"\n@@ -1166,14 +1167,15 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc\n \treturn convert_to_working_tree_internal(path, src, len, dst, 0);\n }\n \n-int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)\n+int renormalize_buffer(const struct index_state *istate, const char *path,\n+\t\t       const char *src, size_t len, struct strbuf *dst)\n {\n \tint ret = convert_to_working_tree_internal(path, src, len, dst, 1);\n \tif (ret) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(&the_index, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n+\treturn ret | convert_to_git(istate, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex 60cb41d6a..cecf59d1a 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -46,7 +46,8 @@ extern int convert_to_git(const struct index_state *istate,\n \t\t\t  struct strbuf *dst, enum safe_crlf checksafe);\n extern int convert_to_working_tree(const char *path, const char *src,\n \t\t\t\t   size_t len, struct strbuf *dst);\n-extern int renormalize_buffer(const char *path, const char *src, size_t len,\n+extern int renormalize_buffer(const struct index_state *istate,\n+\t\t\t      const char *path, const char *src, size_t len,\n \t\t\t      struct strbuf *dst);\n static inline int would_convert_to_git(const struct index_state *istate,\n \t\t\t\t       const char *path)\ndiff --git a/ll-merge.c b/ll-merge.c\nindex 24ff94e1d..b9576efe9 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -340,7 +340,7 @@ static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr\n static void normalize_file(mmfile_t *mm, const char *path)\n {\n \tstruct strbuf strbuf = STRBUF_INIT;\n-\tif (renormalize_buffer(path, mm->ptr, mm->size, &strbuf)) {\n+\tif (renormalize_buffer(&the_index, path, mm->ptr, mm->size, &strbuf)) {\n \t\tfree(mm->ptr);\n \t\tmm->size = strbuf.len;\n \t\tmm->ptr = strbuf_detach(&strbuf, NULL);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex c2494f34f..a4b3858d0 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -1640,8 +1640,8 @@ static int blob_unchanged(struct merge_options *opt,\n \t * performed.  Comparison can be skipped if both files are\n \t * unchanged since their sha1s have already been compared.\n \t */\n-\tif (renormalize_buffer(path, o.buf, o.len, &o) |\n-\t    renormalize_buffer(path, a.buf, a.len, &a))\n+\tif (renormalize_buffer(&the_index, path, o.buf, o.len, &o) |\n+\t    renormalize_buffer(&the_index, path, a.buf, a.len, &a))\n \t\tret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));\n \n error_return:\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321794","messageId":"20170608234100.188529-16-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 15/32] submodule: convert is_submodule_initialized to work on a repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:43Z","receivedAt":"2017-06-08T23:42:05Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'is_submodule_initialized()' to take a repository object and\nwhile we're at it, lets rename the function to 'is_submodule_active()'\nand remove the NEEDSWORK comment.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/grep.c              |  3 ++-\n builtin/submodule--helper.c |  9 +++++----\n submodule.c                 | 20 ++++++++------------\n submodule.h                 |  2 +-\n 4 files changed, 16 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0f4a1e5a3..c2473c281 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -4,6 +4,7 @@\n  * Copyright (c) 2006 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"blob.h\"\n #include \"tree.h\"\n@@ -626,7 +627,7 @@ static int grep_submodule_launch(struct grep_opt *opt,\n static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1,\n \t\t\t  const char *filename, const char *path)\n {\n-\tif (!is_submodule_initialized(path))\n+\tif (!is_submodule_active(the_repository, path))\n \t\treturn 0;\n \tif (!is_submodule_populated_gently(path, NULL)) {\n \t\t/*\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4dcbfb952..2cd6047ef 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"repository.h\"\n #include \"cache.h\"\n #include \"config.h\"\n #include \"parse-options.h\"\n@@ -280,7 +281,7 @@ static void module_list_active(struct module_list *list)\n \tfor (i = 0; i < list->nr; i++) {\n \t\tconst struct cache_entry *ce = list->entries[i];\n \n-\t\tif (!is_submodule_initialized(ce->name))\n+\t\tif (!is_submodule_active(the_repository, ce->name))\n \t\t\tcontinue;\n \n \t\tALLOC_GROW(active_modules.entries,\n@@ -362,7 +363,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t *\n \t * Set active flag for the submodule being initialized\n \t */\n-\tif (!is_submodule_initialized(path)) {\n+\tif (!is_submodule_active(the_repository, path)) {\n \t\tstrbuf_reset(&sb);\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n@@ -817,7 +818,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \t}\n \n \t/* Check if the submodule has been initialized. */\n-\tif (!is_submodule_initialized(ce->name)) {\n+\tif (!is_submodule_active(the_repository, ce->name)) {\n \t\tnext_submodule_warn_missing(suc, out, displaypath);\n \t\tgoto cleanup;\n \t}\n@@ -1193,7 +1194,7 @@ static int is_active(int argc, const char **argv, const char *prefix)\n \n \tgitmodules_config();\n \n-\treturn !is_submodule_initialized(argv[1]);\n+\treturn !is_submodule_active(the_repository, argv[1]);\n }\n \n #define SUPPORT_SUPER_PREFIX (1<<0)\ndiff --git a/submodule.c b/submodule.c\nindex 65f60ab57..7ec13253e 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -230,21 +230,17 @@ void gitmodules_config_sha1(const unsigned char *commit_sha1)\n }\n \n /*\n- * NEEDSWORK: With the addition of different configuration options to determine\n- * if a submodule is of interests, the validity of this function's name comes\n- * into question.  Once the dust has settled and more concrete terminology is\n- * decided upon, come up with a more proper name for this function.  One\n- * potential candidate could be 'is_submodule_active()'.\n- *\n  * Determine if a submodule has been initialized at a given 'path'\n  */\n-int is_submodule_initialized(const char *path)\n+int is_submodule_active(struct repository *repo, const char *path)\n {\n \tint ret = 0;\n \tchar *key = NULL;\n \tchar *value = NULL;\n \tconst struct string_list *sl;\n-\tconst struct submodule *module = submodule_from_path(null_sha1, path);\n+\tconst struct submodule *module;\n+\n+\tmodule = submodule_from_cache(repo, null_sha1, path);\n \n \t/* early return if there isn't a path->module mapping */\n \tif (!module)\n@@ -252,14 +248,14 @@ int is_submodule_initialized(const char *path)\n \n \t/* submodule.<name>.active is set */\n \tkey = xstrfmt(\"submodule.%s.active\", module->name);\n-\tif (!git_config_get_bool(key, &ret)) {\n+\tif (!repo_config_get_bool(repo, key, &ret)) {\n \t\tfree(key);\n \t\treturn ret;\n \t}\n \tfree(key);\n \n \t/* submodule.active is set */\n-\tsl = git_config_get_value_multi(\"submodule.active\");\n+\tsl = repo_config_get_value_multi(repo, \"submodule.active\");\n \tif (sl) {\n \t\tstruct pathspec ps;\n \t\tstruct argv_array args = ARGV_ARRAY_INIT;\n@@ -279,7 +275,7 @@ int is_submodule_initialized(const char *path)\n \n \t/* fallback to checking if the URL is set */\n \tkey = xstrfmt(\"submodule.%s.url\", module->name);\n-\tret = !git_config_get_string(key, &value);\n+\tret = !repo_config_get_string(repo, key, &value);\n \n \tfree(value);\n \tfree(key);\n@@ -1484,7 +1480,7 @@ int submodule_move_head(const char *path,\n \tconst struct submodule *sub;\n \tint *error_code_ptr, error_code;\n \n-\tif (!is_submodule_initialized(path))\n+\tif (!is_submodule_active(the_repository, path))\n \t\treturn 0;\n \n \tif (flags & SUBMODULE_MOVE_HEAD_FORCE)\ndiff --git a/submodule.h b/submodule.h\nindex ec6ea8dfd..af8eada23 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -43,7 +43,7 @@ extern int submodule_config(const char *var, const char *value, void *cb);\n extern void gitmodules_config(void);\n extern void repo_read_gitmodules(struct repository *repo);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n-extern int is_submodule_initialized(const char *path);\n+extern int is_submodule_active(struct repository *repo, const char *path);\n /*\n  * Determine if a submodule has been populated at a given 'path' by checking if\n  * the <path>/.git resolves to a valid git repository.\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321795","messageId":"20170608234100.188529-26-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 25/32] ls-files: convert show_other_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:53Z","receivedAt":"2017-06-08T23:42:09Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex f9578cf9f..d00ca7810 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -109,13 +109,14 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \twrite_name(ent->name);\n }\n \n-static void show_other_files(struct dir_struct *dir)\n+static void show_other_files(const struct index_state *istate,\n+\t\t\t     const struct dir_struct *dir)\n {\n \tint i;\n \n \tfor (i = 0; i < dir->nr; i++) {\n \t\tstruct dir_entry *ent = dir->entries[i];\n-\t\tif (!cache_name_is_other(ent->name, ent->len))\n+\t\tif (!index_name_is_other(istate, ent->name, ent->len))\n \t\t\tcontinue;\n \t\tshow_dir_entry(tag_other, ent);\n \t}\n@@ -337,7 +338,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n \t\tfill_directory(dir, &the_index, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(dir);\n+\t\t\tshow_other_files(&the_index, dir);\n \t\tif (show_killed)\n \t\t\tshow_killed_files(&the_index, dir);\n \t}\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321796","messageId":"20170608234100.188529-22-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 21/32] tree: convert read_tree to take an index parameter","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:49Z","receivedAt":"2017-06-08T23:42:12Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c |  2 +-\n tree.c             | 28 ++++++++++++++++++----------\n tree.h             |  3 ++-\n 3 files changed, 21 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex f16ce0053..620487a77 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -461,7 +461,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\t\t       PATHSPEC_PREFER_CWD, prefix, matchbuf);\n \t} else\n \t\tmemset(&pathspec, 0, sizeof(pathspec));\n-\tif (read_tree(tree, 1, &pathspec))\n+\tif (read_tree(tree, 1, &pathspec, &the_index))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \n \tfor (i = 0; i < active_nr; i++) {\ndiff --git a/tree.c b/tree.c\nindex 603b29ee8..dd69423d9 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"cache-tree.h\"\n #include \"tree.h\"\n@@ -8,7 +9,11 @@\n \n const char *tree_type = \"tree\";\n \n-static int read_one_entry_opt(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, int opt)\n+static int read_one_entry_opt(struct index_state *istate,\n+\t\t\t      const unsigned char *sha1,\n+\t\t\t      const char *base, int baselen,\n+\t\t\t      const char *pathname,\n+\t\t\t      unsigned mode, int stage, int opt)\n {\n \tint len;\n \tunsigned int size;\n@@ -27,14 +32,15 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b\n \tmemcpy(ce->name, base, baselen);\n \tmemcpy(ce->name + baselen, pathname, len+1);\n \thashcpy(ce->oid.hash, sha1);\n-\treturn add_cache_entry(ce, opt);\n+\treturn add_index_entry(istate, ce, opt);\n }\n \n static int read_one_entry(const unsigned char *sha1, struct strbuf *base,\n \t\t\t  const char *pathname, unsigned mode, int stage,\n \t\t\t  void *context)\n {\n-\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\tstruct index_state *istate = context;\n+\treturn read_one_entry_opt(istate, sha1, base->buf, base->len, pathname,\n \t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);\n }\n@@ -47,7 +53,8 @@ static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,\n \t\t\t\tconst char *pathname, unsigned mode, int stage,\n \t\t\t\tvoid *context)\n {\n-\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\tstruct index_state *istate = context;\n+\treturn read_one_entry_opt(istate, sha1, base->buf, base->len, pathname,\n \t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_JUST_APPEND);\n }\n@@ -144,7 +151,8 @@ static int cmp_cache_name_compare(const void *a_, const void *b_)\n \t\t\t\t  ce2->name, ce2->ce_namelen, ce_stage(ce2));\n }\n \n-int read_tree(struct tree *tree, int stage, struct pathspec *match)\n+int read_tree(struct tree *tree, int stage, struct pathspec *match,\n+\t      struct index_state *istate)\n {\n \tread_tree_fn_t fn = NULL;\n \tint i, err;\n@@ -164,23 +172,23 @@ int read_tree(struct tree *tree, int stage, struct pathspec *match)\n \t * do it the original slow way, otherwise, append and then\n \t * sort at the end.\n \t */\n-\tfor (i = 0; !fn && i < active_nr; i++) {\n-\t\tconst struct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; !fn && i < istate->cache_nr; i++) {\n+\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\tif (ce_stage(ce) == stage)\n \t\t\tfn = read_one_entry;\n \t}\n \n \tif (!fn)\n \t\tfn = read_one_entry_quick;\n-\terr = read_tree_recursive(tree, \"\", 0, stage, match, fn, NULL);\n+\terr = read_tree_recursive(tree, \"\", 0, stage, match, fn, istate);\n \tif (fn == read_one_entry || err)\n \t\treturn err;\n \n \t/*\n \t * Sort the cache entry -- we need to nuke the cache tree, though.\n \t */\n-\tcache_tree_free(&active_cache_tree);\n-\tQSORT(active_cache, active_nr, cmp_cache_name_compare);\n+\tcache_tree_free(&istate->cache_tree);\n+\tQSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);\n \treturn 0;\n }\n \ndiff --git a/tree.h b/tree.h\nindex 0d4734b94..744e6dc2a 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -34,6 +34,7 @@ extern int read_tree_recursive(struct tree *tree,\n \t\t\t       int stage, const struct pathspec *pathspec,\n \t\t\t       read_tree_fn_t fn, void *context);\n \n-extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec);\n+extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec,\n+\t\t     struct index_state *istate);\n \n #endif /* TREE_H */\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321797","messageId":"20170608234100.188529-31-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 30/32] ls-files: factor out debug info into a function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:58Z","receivedAt":"2017-06-08T23:42:14Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 23 ++++++++++++++---------\n 1 file changed, 14 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 3061af2c5..2849c9a65 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -94,6 +94,19 @@ static void write_name(const char *name)\n \tstrbuf_release(&full_name);\n }\n \n+static void print_debug(const struct cache_entry *ce)\n+{\n+\tif (debug_mode) {\n+\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n+\n+\t\tprintf(\"  ctime: %d:%d\\n\", sd->sd_ctime.sec, sd->sd_ctime.nsec);\n+\t\tprintf(\"  mtime: %d:%d\\n\", sd->sd_mtime.sec, sd->sd_mtime.nsec);\n+\t\tprintf(\"  dev: %d\\tino: %d\\n\", sd->sd_dev, sd->sd_ino);\n+\t\tprintf(\"  uid: %d\\tgid: %d\\n\", sd->sd_uid, sd->sd_gid);\n+\t\tprintf(\"  size: %d\\tflags: %x\\n\", sd->sd_size, ce->ce_flags);\n+\t}\n+}\n+\n static void show_dir_entry(const char *tag, struct dir_entry *ent)\n {\n \tint len = max_prefix_len;\n@@ -279,15 +292,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t}\n \t\twrite_eolinfo(&the_index, ce, ce->name);\n \t\twrite_name(ce->name);\n-\t\tif (debug_mode) {\n-\t\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n-\n-\t\t\tprintf(\"  ctime: %d:%d\\n\", sd->sd_ctime.sec, sd->sd_ctime.nsec);\n-\t\t\tprintf(\"  mtime: %d:%d\\n\", sd->sd_mtime.sec, sd->sd_mtime.nsec);\n-\t\t\tprintf(\"  dev: %d\\tino: %d\\n\", sd->sd_dev, sd->sd_ino);\n-\t\t\tprintf(\"  uid: %d\\tgid: %d\\n\", sd->sd_uid, sd->sd_gid);\n-\t\t\tprintf(\"  size: %d\\tflags: %x\\n\", sd->sd_size, ce->ce_flags);\n-\t\t}\n+\t\tprint_debug(ce);\n \t}\n \n \tstrbuf_release(&name);\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321798","messageId":"20170608234100.188529-28-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 27/32] ls-files: convert ce_excluded to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:55Z","receivedAt":"2017-06-08T23:42:18Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 9 +++++----\n 1 file changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 2838e2f75..289c6b2a5 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -322,10 +322,11 @@ static void show_ru_info(const struct index_state *istate)\n \t}\n }\n \n-static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce)\n+static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n+\t\t       const struct cache_entry *ce)\n {\n \tint dtype = ce_to_dtype(ce);\n-\treturn is_excluded(dir, &the_index, ce->name, &dtype);\n+\treturn is_excluded(dir, istate, ce->name, &dtype);\n }\n \n static void show_files(struct dir_struct *dir)\n@@ -346,7 +347,7 @@ static void show_files(struct dir_struct *dir)\n \t\tfor (i = 0; i < active_nr; i++) {\n \t\t\tconst struct cache_entry *ce = active_cache[i];\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, ce))\n+\t\t\t    !ce_excluded(dir, &the_index, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n@@ -362,7 +363,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\tstruct stat st;\n \t\t\tint err;\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, ce))\n+\t\t\t    !ce_excluded(dir, &the_index, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321799","messageId":"20170608234100.188529-33-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 32/32] ls-files: use repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:41:00Z","receivedAt":"2017-06-08T23:42:20Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert ls-files to use a repository struct and recurse submodules\ninprocess.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c                     | 198 ++++++++++++++-------------------\n git.c                                  |   2 +-\n repository.c                           |   4 +\n repository.h                           |   1 +\n t/t3007-ls-files-recurse-submodules.sh |  39 +++++++\n 5 files changed, 129 insertions(+), 115 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 6a0302a28..503fed5a1 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -5,7 +5,9 @@\n  *\n  * Copyright (C) Linus Torvalds, 2005\n  */\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"quote.h\"\n #include \"dir.h\"\n@@ -32,10 +34,8 @@ static int line_terminator = '\\n';\n static int debug_mode;\n static int show_eol;\n static int recurse_submodules;\n-static struct argv_array submodule_options = ARGV_ARRAY_INIT;\n \n static const char *prefix;\n-static const char *super_prefix;\n static int max_prefix_len;\n static int prefix_len;\n static struct pathspec pathspec;\n@@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,\n \n static void write_name(const char *name)\n {\n-\t/*\n-\t * Prepend the super_prefix to name to construct the full_name to be\n-\t * written.\n-\t */\n-\tstruct strbuf full_name = STRBUF_INIT;\n-\tif (super_prefix) {\n-\t\tstrbuf_addstr(&full_name, super_prefix);\n-\t\tstrbuf_addstr(&full_name, name);\n-\t\tname = full_name.buf;\n-\t}\n-\n \t/*\n \t * With \"--full-name\", prefix_len=0; this caller needs to pass\n \t * an empty string in that case (a NULL is good for \"\").\n \t */\n \twrite_name_quoted_relative(name, prefix_len ? prefix : NULL,\n \t\t\t\t   stdout, line_terminator);\n-\n-\tstrbuf_release(&full_name);\n }\n \n static const char *get_tag(const struct cache_entry *ce, const char *tag)\n@@ -210,82 +197,41 @@ static void show_killed_files(const struct index_state *istate,\n \t}\n }\n \n-/*\n- * Compile an argv_array with all of the options supported by --recurse_submodules\n- */\n-static void compile_submodule_options(const char **argv,\n-\t\t\t\t      const struct dir_struct *dir,\n-\t\t\t\t      int show_tag)\n-{\n-\tif (line_terminator == '\\0')\n-\t\targv_array_push(&submodule_options, \"-z\");\n-\tif (show_tag)\n-\t\targv_array_push(&submodule_options, \"-t\");\n-\tif (show_valid_bit)\n-\t\targv_array_push(&submodule_options, \"-v\");\n-\tif (show_cached)\n-\t\targv_array_push(&submodule_options, \"--cached\");\n-\tif (show_eol)\n-\t\targv_array_push(&submodule_options, \"--eol\");\n-\tif (debug_mode)\n-\t\targv_array_push(&submodule_options, \"--debug\");\n-\n-\t/* Add Pathspecs */\n-\targv_array_push(&submodule_options, \"--\");\n-\tfor (; *argv; argv++)\n-\t\targv_array_push(&submodule_options, *argv);\n-}\n+static void show_files(struct repository *repo, struct dir_struct *dir);\n \n-/**\n- * Recursively call ls-files on a submodule\n- */\n-static void show_gitlink(const struct cache_entry *ce)\n+static void show_submodule(const struct repository *superproject,\n+\t\t\t   struct dir_struct *dir, const char *path)\n {\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n-\tint status;\n-\tchar *dir;\n-\n-\tprepare_submodule_repo_env(&cp.env_array);\n-\targv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);\n-\n-\tif (prefix_len)\n-\t\targv_array_pushf(&cp.env_array, \"%s=%s\",\n-\t\t\t\t GIT_TOPLEVEL_PREFIX_ENVIRONMENT,\n-\t\t\t\t prefix);\n-\targv_array_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t\t super_prefix ? super_prefix : \"\",\n-\t\t\t ce->name);\n-\targv_array_push(&cp.args, \"ls-files\");\n-\targv_array_push(&cp.args, \"--recurse-submodules\");\n-\n-\t/* add supported options */\n-\targv_array_pushv(&cp.args, submodule_options.argv);\n-\n-\tcp.git_cmd = 1;\n-\tdir = mkpathdup(\"%s/%s\", get_git_work_tree(), ce->name);\n-\tcp.dir = dir;\n-\tstatus = run_command(&cp);\n-\tfree(dir);\n-\tif (status)\n-\t\texit(status);\n+\tstruct repository submodule;\n+\tchar *gitdir = mkpathdup(\"%s/%s\", superproject->worktree, path);\n+\trepo_init(&submodule, gitdir);\n+\n+\trepo_read_index(&submodule);\n+\trepo_read_gitmodules(&submodule);\n+\n+\tif (superproject->submodule_prefix)\n+\t\tsubmodule.submodule_prefix = xstrfmt(\"%s%s/\", superproject->submodule_prefix, path);\n+\telse\n+\t\tsubmodule.submodule_prefix = xstrfmt(\"%s/\", path);\n+\tshow_files(&submodule, dir);\n+\n+\trepo_clear(&submodule);\n+\tfree(gitdir);\n }\n \n-static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n+static void show_ce(struct repository *repo, struct dir_struct *dir,\n+\t\t    const struct cache_entry *ce, const char *fullname,\n+\t\t    const char *tag)\n {\n-\tstruct strbuf name = STRBUF_INIT;\n-\tint len = max_prefix_len;\n-\tif (super_prefix)\n-\t\tstrbuf_addstr(&name, super_prefix);\n-\tstrbuf_addstr(&name, ce->name);\n-\n-\tif (len > ce_namelen(ce))\n+\tif (max_prefix_len > strlen(fullname))\n \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n \n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t    submodule_path_match(&pathspec, name.buf, ps_matched)) {\n-\t\tshow_gitlink(ce);\n-\t} else if (match_pathspec(&pathspec, name.buf, name.len,\n-\t\t\t\t  len, ps_matched,\n+\t    submodule_path_match(&pathspec, fullname, ps_matched) &&\n+\t    is_submodule_active(repo, ce->name)) {\n+\t\tshow_submodule(repo, dir, ce->name);\n+\t} else if (match_pathspec(&pathspec, fullname, strlen(fullname),\n+\t\t\t\t  max_prefix_len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n \t\ttag = get_tag(ce, tag);\n@@ -299,12 +245,11 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n \t\t\t       ce_stage(ce));\n \t\t}\n-\t\twrite_eolinfo(&the_index, ce, ce->name);\n-\t\twrite_name(ce->name);\n+\n+\t\twrite_eolinfo(repo->index, ce, fullname);\n+\t\twrite_name(fullname);\n \t\tprint_debug(ce);\n \t}\n-\n-\tstrbuf_release(&name);\n }\n \n static void show_ru_info(const struct index_state *istate)\n@@ -337,59 +282,79 @@ static void show_ru_info(const struct index_state *istate)\n }\n \n static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n-\t\t       const struct cache_entry *ce)\n+\t\t       const char *fullname, const struct cache_entry *ce)\n {\n \tint dtype = ce_to_dtype(ce);\n-\treturn is_excluded(dir, istate, ce->name, &dtype);\n+\treturn is_excluded(dir, istate, fullname, &dtype);\n+}\n+\n+static void construct_fullname(struct strbuf *out, const struct repository *repo,\n+\t\t\t       const struct cache_entry *ce)\n+{\n+\tstrbuf_reset(out);\n+\tif (repo->submodule_prefix)\n+\t\tstrbuf_addstr(out, repo->submodule_prefix);\n+\tstrbuf_addstr(out, ce->name);\n }\n \n-static void show_files(struct index_state *istate, struct dir_struct *dir)\n+static void show_files(struct repository *repo, struct dir_struct *dir)\n {\n \tint i;\n+\tstruct strbuf fullname = STRBUF_INIT;\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others || show_killed) {\n \t\tif (!show_others)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n-\t\tfill_directory(dir, istate, &pathspec);\n+\t\tfill_directory(dir, repo->index, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(istate, dir);\n+\t\t\tshow_other_files(repo->index, dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(istate, dir);\n+\t\t\tshow_killed_files(repo->index, dir);\n \t}\n \tif (show_cached || show_stage) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-\t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged :\n-\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);\n+\t\t\tshow_ce(repo, dir, ce, fullname.buf,\n+\t\t\t\tce_stage(ce) ? tag_unmerged :\n+\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree :\n+\t\t\t\t tag_cached));\n \t\t}\n \t}\n \tif (show_deleted || show_modified) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n \t\t\tstruct stat st;\n \t\t\tint err;\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n \t\t\tif (ce_skip_worktree(ce))\n \t\t\t\tcontinue;\n-\t\t\terr = lstat(ce->name, &st);\n+\t\t\terr = lstat(fullname.buf, &st);\n \t\t\tif (show_deleted && err)\n-\t\t\t\tshow_ce_entry(tag_removed, ce);\n-\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n-\t\t\t\tshow_ce_entry(tag_modified, ce);\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed);\n+\t\t\tif (show_modified && ie_modified(repo->index, ce, &st, 0))\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified);\n \t\t}\n \t}\n+\n+\tstrbuf_release(&fullname);\n }\n \n /*\n@@ -614,10 +579,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tprefix = cmd_prefix;\n \tif (prefix)\n \t\tprefix_len = strlen(prefix);\n-\tsuper_prefix = get_super_prefix();\n \tgit_config(git_default_config, NULL);\n \n-\tif (read_cache() < 0)\n+\tif (repo_read_index(the_repository))\n \t\tdie(\"index file corrupt\");\n \n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n@@ -650,8 +614,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (require_work_tree && !is_inside_work_tree())\n \t\tsetup_work_tree();\n \n-\tif (recurse_submodules)\n-\t\tcompile_submodule_options(argv, &dir, show_tag);\n+\tif (recurse_submodules) {\n+\t\trepo_read_gitmodules(the_repository);\n+\t}\n \n \tif (recurse_submodules &&\n \t    (show_stage || show_deleted || show_others || show_unmerged ||\n@@ -669,7 +634,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t/*\n \t * Find common prefix for all pathspec's\n \t * This is used as a performance optimization which unfortunately cannot\n-\t * be done when recursing into submodules\n+\t * be done when recursing into submodules because when a pathspec is\n+\t * given which spans repository boundaries you can't simply remove the\n+\t * submodule entry because the pathspec may match something inside the\n+\t * submodule.\n \t */\n \tif (recurse_submodules)\n \t\tmax_prefix = NULL;\n@@ -677,7 +645,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_index(&the_index, max_prefix, max_prefix_len);\n+\tprune_index(the_repository->index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n@@ -698,11 +666,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n-\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n+\t\toverlay_tree_on_index(the_repository->index, with_tree, max_prefix);\n \t}\n-\tshow_files(&the_index, &dir);\n+\n+\tshow_files(the_repository, &dir);\n+\n \tif (show_resolve_undo)\n-\t\tshow_ru_info(&the_index);\n+\t\tshow_ru_info(the_repository->index);\n \n \tif (ps_matched) {\n \t\tint bad;\ndiff --git a/git.c b/git.c\nindex 594436e43..16c6e325d 100644\n--- a/git.c\n+++ b/git.c\n@@ -442,7 +442,7 @@ static struct cmd_struct commands[] = {\n \t{ \"init-db\", cmd_init_db },\n \t{ \"interpret-trailers\", cmd_interpret_trailers, RUN_SETUP_GENTLY },\n \t{ \"log\", cmd_log, RUN_SETUP },\n-\t{ \"ls-files\", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"ls-files\", cmd_ls_files, RUN_SETUP },\n \t{ \"ls-remote\", cmd_ls_remote, RUN_SETUP_GENTLY },\n \t{ \"ls-tree\", cmd_ls_tree, RUN_SETUP },\n \t{ \"mailinfo\", cmd_mailinfo, RUN_SETUP_GENTLY },\ndiff --git a/repository.c b/repository.c\nindex 98a851d20..9f899a34a 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -152,6 +152,8 @@ int repo_init(struct repository *repo, const char *gitdir)\n \tif (verify_repo_format(&format, repo->commondir))\n \t\tgoto error;\n \n+\trepo_set_worktree(repo, gitdir);\n+\n \treturn 0;\n \n error:\n@@ -180,6 +182,8 @@ void repo_clear(struct repository *repo)\n \trepo_clear_env(repo);\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n+\tfree(repo->submodule_prefix);\n+\trepo->submodule_prefix = NULL;\n \n \tif (repo->config) {\n \t\tgit_configset_clear(repo->config);\ndiff --git a/repository.h b/repository.h\nindex d9f1f721b..eea9a88aa 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -14,6 +14,7 @@ struct repository {\n \tchar *graft_file;\n \tchar *namespace;\n \tchar *worktree;\n+\tchar *submodule_prefix;\n \n \t/* Subsystems */\n \t/*\ndiff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh\nindex ebb956fd1..318b5bce7 100755\n--- a/t/t3007-ls-files-recurse-submodules.sh\n+++ b/t/t3007-ls-files-recurse-submodules.sh\n@@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'inactive submodule' '\n+\ttest_when_finished \"git config --bool submodule.submodule.active true\" &&\n+\ttest_when_finished \"git -C submodule config --bool submodule.subsub.active true\" &&\n+\tgit config --bool submodule.submodule.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tgit config --bool submodule.submodule.active \"true\" &&\n+\tgit -C submodule config --bool submodule.subsub.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule/.gitmodules\n+\tsubmodule/c\n+\tsubmodule/f.TXT\n+\tsubmodule/g.txt\n+\tsubmodule/subsub\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success '--recurse-submodules and pathspecs' '\n \tcat >expect <<-\\EOF &&\n \th.txt\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321800","messageId":"20170608234100.188529-30-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 29/32] ls-files: convert show_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:57Z","receivedAt":"2017-06-08T23:42:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex e2d8fb7f6..3061af2c5 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -329,7 +329,7 @@ static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n \treturn is_excluded(dir, istate, ce->name, &dtype);\n }\n \n-static void show_files(struct dir_struct *dir)\n+static void show_files(struct index_state *istate, struct dir_struct *dir)\n {\n \tint i;\n \n@@ -337,17 +337,17 @@ static void show_files(struct dir_struct *dir)\n \tif (show_others || show_killed) {\n \t\tif (!show_others)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n-\t\tfill_directory(dir, &the_index, &pathspec);\n+\t\tfill_directory(dir, istate, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(&the_index, dir);\n+\t\t\tshow_other_files(istate, dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(&the_index, dir);\n+\t\t\tshow_killed_files(istate, dir);\n \t}\n \tif (show_cached || show_stage) {\n-\t\tfor (i = 0; i < active_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = active_cache[i];\n+\t\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, &the_index, ce))\n+\t\t\t    !ce_excluded(dir, istate, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n@@ -358,12 +358,12 @@ static void show_files(struct dir_struct *dir)\n \t\t}\n \t}\n \tif (show_deleted || show_modified) {\n-\t\tfor (i = 0; i < active_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = active_cache[i];\n+\t\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\t\tstruct stat st;\n \t\t\tint err;\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, &the_index, ce))\n+\t\t\t    !ce_excluded(dir, istate, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n@@ -372,7 +372,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\terr = lstat(ce->name, &st);\n \t\t\tif (show_deleted && err)\n \t\t\t\tshow_ce_entry(tag_removed, ce);\n-\t\t\tif (show_modified && ce_modified(ce, &st, 0))\n+\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n \t\t\t\tshow_ce_entry(tag_modified, ce);\n \t\t}\n \t}\n@@ -686,7 +686,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n \t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n \t}\n-\tshow_files(&dir);\n+\tshow_files(&the_index, &dir);\n \tif (show_resolve_undo)\n \t\tshow_ru_info(&the_index);\n \n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321801","messageId":"20170608234100.188529-25-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 24/32] ls-files: convert show_killed_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:52Z","receivedAt":"2017-06-08T23:42:24Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 21 +++++++++++----------\n 1 file changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex c37e9de11..f9578cf9f 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -121,7 +121,8 @@ static void show_other_files(struct dir_struct *dir)\n \t}\n }\n \n-static void show_killed_files(struct dir_struct *dir)\n+static void show_killed_files(const struct index_state *istate,\n+\t\t\t      const struct dir_struct *dir)\n {\n \tint i;\n \tfor (i = 0; i < dir->nr; i++) {\n@@ -135,29 +136,29 @@ static void show_killed_files(struct dir_struct *dir)\n \t\t\t\t/* If ent->name is prefix of an entry in the\n \t\t\t\t * cache, it will be killed.\n \t\t\t\t */\n-\t\t\t\tpos = cache_name_pos(ent->name, ent->len);\n+\t\t\t\tpos = index_name_pos(istate, ent->name, ent->len);\n \t\t\t\tif (0 <= pos)\n \t\t\t\t\tdie(\"BUG: killed-file %.*s not found\",\n \t\t\t\t\t\tent->len, ent->name);\n \t\t\t\tpos = -pos - 1;\n-\t\t\t\twhile (pos < active_nr &&\n-\t\t\t\t       ce_stage(active_cache[pos]))\n+\t\t\t\twhile (pos < istate->cache_nr &&\n+\t\t\t\t       ce_stage(istate->cache[pos]))\n \t\t\t\t\tpos++; /* skip unmerged */\n-\t\t\t\tif (active_nr <= pos)\n+\t\t\t\tif (istate->cache_nr <= pos)\n \t\t\t\t\tbreak;\n \t\t\t\t/* pos points at a name immediately after\n \t\t\t\t * ent->name in the cache.  Does it expect\n \t\t\t\t * ent->name to be a directory?\n \t\t\t\t */\n-\t\t\t\tlen = ce_namelen(active_cache[pos]);\n+\t\t\t\tlen = ce_namelen(istate->cache[pos]);\n \t\t\t\tif ((ent->len < len) &&\n-\t\t\t\t    !strncmp(active_cache[pos]->name,\n+\t\t\t\t    !strncmp(istate->cache[pos]->name,\n \t\t\t\t\t     ent->name, ent->len) &&\n-\t\t\t\t    active_cache[pos]->name[ent->len] == '/')\n+\t\t\t\t    istate->cache[pos]->name[ent->len] == '/')\n \t\t\t\t\tkilled = 1;\n \t\t\t\tbreak;\n \t\t\t}\n-\t\t\tif (0 <= cache_name_pos(ent->name, sp - ent->name)) {\n+\t\t\tif (0 <= index_name_pos(istate, ent->name, sp - ent->name)) {\n \t\t\t\t/* If any of the leading directories in\n \t\t\t\t * ent->name is registered in the cache,\n \t\t\t\t * ent->name will be killed.\n@@ -338,7 +339,7 @@ static void show_files(struct dir_struct *dir)\n \t\tif (show_others)\n \t\t\tshow_other_files(dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(dir);\n+\t\t\tshow_killed_files(&the_index, dir);\n \t}\n \tif (show_cached || show_stage) {\n \t\tfor (i = 0; i < active_nr; i++) {\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321802","messageId":"20170608234100.188529-27-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 26/32] ls-files: convert show_ru_info to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:54Z","receivedAt":"2017-06-08T23:42:25Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex d00ca7810..2838e2f75 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -293,14 +293,14 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \tstrbuf_release(&name);\n }\n \n-static void show_ru_info(void)\n+static void show_ru_info(const struct index_state *istate)\n {\n \tstruct string_list_item *item;\n \n-\tif (!the_index.resolve_undo)\n+\tif (!istate->resolve_undo)\n \t\treturn;\n \n-\tfor_each_string_list_item(item, the_index.resolve_undo) {\n+\tfor_each_string_list_item(item, istate->resolve_undo) {\n \t\tconst char *path = item->string;\n \t\tstruct resolve_undo_info *ui = item->util;\n \t\tint i, len;\n@@ -686,7 +686,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t}\n \tshow_files(&dir);\n \tif (show_resolve_undo)\n-\t\tshow_ru_info();\n+\t\tshow_ru_info(&the_index);\n \n \tif (ps_matched) {\n \t\tint bad;\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321803","messageId":"20170608234100.188529-29-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 28/32] ls-files: convert prune_cache to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:56Z","receivedAt":"2017-06-08T23:42:27Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 289c6b2a5..e2d8fb7f6 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -381,30 +381,31 @@ static void show_files(struct dir_struct *dir)\n /*\n  * Prune the index to only contain stuff starting with \"prefix\"\n  */\n-static void prune_cache(const char *prefix, size_t prefixlen)\n+static void prune_index(struct index_state *istate,\n+\t\t\tconst char *prefix, size_t prefixlen)\n {\n \tint pos;\n \tunsigned int first, last;\n \n \tif (!prefix)\n \t\treturn;\n-\tpos = cache_name_pos(prefix, prefixlen);\n+\tpos = index_name_pos(istate, prefix, prefixlen);\n \tif (pos < 0)\n \t\tpos = -pos-1;\n \tfirst = pos;\n-\tlast = active_nr;\n+\tlast = istate->cache_nr;\n \twhile (last > first) {\n \t\tint next = (last + first) >> 1;\n-\t\tconst struct cache_entry *ce = active_cache[next];\n+\t\tconst struct cache_entry *ce = istate->cache[next];\n \t\tif (!strncmp(ce->name, prefix, prefixlen)) {\n \t\t\tfirst = next+1;\n \t\t\tcontinue;\n \t\t}\n \t\tlast = next;\n \t}\n-\tmemmove(active_cache, active_cache + pos,\n+\tmemmove(istate->cache, istate->cache + pos,\n \t\t(last - pos) * sizeof(struct cache_entry *));\n-\tactive_nr = last - pos;\n+\tistate->cache_nr = last - pos;\n }\n \n static int get_common_prefix_len(const char *common_prefix)\n@@ -662,7 +663,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_cache(max_prefix, max_prefix_len);\n+\tprune_index(&the_index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321804","messageId":"20170608234100.188529-18-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 17/32] convert: convert crlf_to_git to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:45Z","receivedAt":"2017-06-08T23:42:31Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex 574003023..ff3e72657 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -219,13 +219,13 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \t}\n }\n \n-static int has_cr_in_index(const char *path)\n+static int has_cr_in_index(const struct index_state *istate, const char *path)\n {\n \tunsigned long sz;\n \tvoid *data;\n \tint has_cr;\n \n-\tdata = read_blob_data_from_cache(path, &sz);\n+\tdata = read_blob_data_from_index(istate, path, &sz);\n \tif (!data)\n \t\treturn 0;\n \thas_cr = memchr(data, '\\r', sz) != NULL;\n@@ -255,7 +255,8 @@ static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats,\n \n }\n \n-static int crlf_to_git(const char *path, const char *src, size_t len,\n+static int crlf_to_git(const struct index_state *istate,\n+\t\t       const char *path, const char *src, size_t len,\n \t\t       struct strbuf *buf,\n \t\t       enum crlf_action crlf_action, enum safe_crlf checksafe)\n {\n@@ -287,7 +288,8 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \t\t * unless we want to renormalize in a merge or\n \t\t * cherry-pick.\n \t\t */\n-\t\tif ((checksafe != SAFE_CRLF_RENORMALIZE) && has_cr_in_index(path))\n+\t\tif ((checksafe != SAFE_CRLF_RENORMALIZE) &&\n+\t\t    has_cr_in_index(istate, path))\n \t\t\tconvert_crlf_into_lf = 0;\n \t}\n \tif ((checksafe == SAFE_CRLF_WARN ||\n@@ -1099,7 +1101,7 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\tret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);\n+\tret |= crlf_to_git(&the_index, path, src, len, dst, ca.crlf_action, checksafe);\n \tif (ret && dst) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -1119,7 +1121,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n \tif (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))\n \t\tdie(\"%s: clean filter '%s' failed\", path, ca.drv->name);\n \n-\tcrlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n+\tcrlf_to_git(&the_index, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321805","messageId":"20170608234100.188529-32-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 31/32] ls-files: factor out tag calculation","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:59Z","receivedAt":"2017-06-08T23:42:33Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 41 +++++++++++++++++++++++++----------------\n 1 file changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 2849c9a65..6a0302a28 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -94,6 +94,30 @@ static void write_name(const char *name)\n \tstrbuf_release(&full_name);\n }\n \n+static const char *get_tag(const struct cache_entry *ce, const char *tag)\n+{\n+\tstatic char alttag[4];\n+\n+\tif (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) {\n+\t\tmemcpy(alttag, tag, 3);\n+\n+\t\tif (isalpha(tag[0])) {\n+\t\t\talttag[0] = tolower(tag[0]);\n+\t\t} else if (tag[0] == '?') {\n+\t\t\talttag[0] = '!';\n+\t\t} else {\n+\t\t\talttag[0] = 'v';\n+\t\t\talttag[1] = tag[0];\n+\t\t\talttag[2] = ' ';\n+\t\t\talttag[3] = 0;\n+\t\t}\n+\n+\t\ttag = alttag;\n+\t}\n+\n+\treturn tag;\n+}\n+\n static void print_debug(const struct cache_entry *ce)\n {\n \tif (debug_mode) {\n@@ -264,22 +288,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t\t  len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n-\t\tif (tag && *tag && show_valid_bit &&\n-\t\t    (ce->ce_flags & CE_VALID)) {\n-\t\t\tstatic char alttag[4];\n-\t\t\tmemcpy(alttag, tag, 3);\n-\t\t\tif (isalpha(tag[0]))\n-\t\t\t\talttag[0] = tolower(tag[0]);\n-\t\t\telse if (tag[0] == '?')\n-\t\t\t\talttag[0] = '!';\n-\t\t\telse {\n-\t\t\t\talttag[0] = 'v';\n-\t\t\t\talttag[1] = tag[0];\n-\t\t\t\talttag[2] = ' ';\n-\t\t\t\talttag[3] = 0;\n-\t\t\t}\n-\t\t\ttag = alttag;\n-\t\t}\n+\t\ttag = get_tag(ce, tag);\n \n \t\tif (!show_stage) {\n \t\t\tfputs(tag, stdout);\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321806","messageId":"20170608234100.188529-19-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 18/32] convert: convert convert_to_git_filter_fd to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:46Z","receivedAt":"2017-06-08T23:42:37Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c   | 5 +++--\n convert.h   | 3 ++-\n sha1_file.c | 2 +-\n 3 files changed, 6 insertions(+), 4 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex ff3e72657..824b606fa 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1109,7 +1109,8 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \treturn ret | ident_to_git(path, src, len, dst, ca.ident);\n }\n \n-void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n+void convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t      const char *path, int fd, struct strbuf *dst,\n \t\t\t      enum safe_crlf checksafe)\n {\n \tstruct conv_attrs ca;\n@@ -1121,7 +1122,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n \tif (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))\n \t\tdie(\"%s: clean filter '%s' failed\", path, ca.drv->name);\n \n-\tcrlf_to_git(&the_index, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n+\tcrlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \ndiff --git a/convert.h b/convert.h\nindex 667b7dfe0..3a813a797 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -52,7 +52,8 @@ static inline int would_convert_to_git(const char *path)\n \treturn convert_to_git(path, NULL, 0, NULL, 0);\n }\n /* Precondition: would_convert_to_git_filter_fd(path) == true */\n-extern void convert_to_git_filter_fd(const char *path, int fd,\n+extern void convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t\t     const char *path, int fd,\n \t\t\t\t     struct strbuf *dst,\n \t\t\t\t     enum safe_crlf checksafe);\n extern int would_convert_to_git_filter_fd(const char *path);\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 44561e0b9..80e9ef3bb 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -3581,7 +3581,7 @@ static int index_stream_convert_blob(unsigned char *sha1, int fd,\n \tassert(path);\n \tassert(would_convert_to_git_filter_fd(path));\n \n-\tconvert_to_git_filter_fd(path, fd, &sbuf,\n+\tconvert_to_git_filter_fd(&the_index, path, fd, &sbuf,\n \t\t\t\t write_object ? safe_crlf : SAFE_CRLF_FALSE);\n \n \tif (write_object)\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321807","messageId":"20170608234100.188529-14-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 13/32] submodule-config: store the_submodule_cache in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:41Z","receivedAt":"2017-06-08T23:42:39Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Refactor how 'the_submodule_cache' is handled so that it can be stored\ninside of a repository object.  Also migrate 'the_submodule_cache' to be\nstored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n repository.c       |  6 +++++\n repository.h       |  2 ++\n submodule-config.c | 70 ++++++++++++++++++++++++++++++++++++++++--------------\n submodule-config.h | 10 ++++++++\n 4 files changed, 70 insertions(+), 18 deletions(-)\n\ndiff --git a/repository.c b/repository.c\nindex 21719d0a6..98a851d20 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"repository.h\"\n #include \"config.h\"\n+#include \"submodule-config.h\"\n \n /* The main repository */\n static struct repository the_repo;\n@@ -192,6 +193,11 @@ void repo_clear(struct repository *repo)\n \t\trepo->index = NULL;\n \t}\n \n+\tif (repo->submodule_cache) {\n+\t\tsubmodule_cache_free(repo->submodule_cache);\n+\t\trepo->submodule_cache = NULL;\n+\t}\n+\n \tmemset(repo, 0, sizeof(*repo));\n }\n \ndiff --git a/repository.h b/repository.h\nindex 9515cc631..d9f1f721b 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -3,6 +3,7 @@\n \n struct config_set;\n struct index_state;\n+struct submodule_cache;\n \n struct repository {\n \t/* Environment */\n@@ -22,6 +23,7 @@ struct repository {\n \t */\n \tstruct config_set *config;\n \tstruct index_state *index;\n+\tstruct submodule_cache *submodule_cache;\n \n \t/* Configurations */\n \tunsigned ignore_env:1;\ndiff --git a/submodule-config.c b/submodule-config.c\nindex d8f8d5ea3..37cfcceb9 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n@@ -15,6 +16,7 @@\n struct submodule_cache {\n \tstruct hashmap for_path;\n \tstruct hashmap for_name;\n+\tunsigned initialized:1;\n };\n \n /*\n@@ -31,9 +33,6 @@ enum lookup_type {\n \tlookup_path\n };\n \n-static struct submodule_cache the_submodule_cache;\n-static int is_cache_init;\n-\n static int config_path_cmp(const struct submodule_entry *a,\n \t\t\t   const struct submodule_entry *b,\n \t\t\t   const void *unused)\n@@ -50,10 +49,16 @@ static int config_name_cmp(const struct submodule_entry *a,\n \t       hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);\n }\n \n-static void cache_init(struct submodule_cache *cache)\n+static struct submodule_cache *submodule_cache_alloc(void)\n+{\n+\treturn xcalloc(1, sizeof(struct submodule_cache));\n+}\n+\n+static void submodule_cache_init(struct submodule_cache *cache)\n {\n \thashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);\n \thashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);\n+\tcache->initialized = 1;\n }\n \n static void free_one_config(struct submodule_entry *entry)\n@@ -65,11 +70,14 @@ static void free_one_config(struct submodule_entry *entry)\n \tfree(entry->config);\n }\n \n-static void cache_free(struct submodule_cache *cache)\n+static void submodule_cache_clear(struct submodule_cache *cache)\n {\n \tstruct hashmap_iter iter;\n \tstruct submodule_entry *entry;\n \n+\tif (!cache->initialized)\n+\t\treturn;\n+\n \t/*\n \t * We iterate over the name hash here to be symmetric with the\n \t * allocation of struct submodule entries. Each is allocated by\n@@ -81,6 +89,13 @@ static void cache_free(struct submodule_cache *cache)\n \n \thashmap_free(&cache->for_path, 1);\n \thashmap_free(&cache->for_name, 1);\n+\tcache->initialized = 0;\n+}\n+\n+void submodule_cache_free(struct submodule_cache *cache)\n+{\n+\tsubmodule_cache_clear(cache);\n+\tfree(cache);\n }\n \n static unsigned int hash_sha1_string(const unsigned char *sha1,\n@@ -494,43 +509,62 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \treturn submodule;\n }\n \n-static void ensure_cache_init(void)\n+static void submodule_cache_check_init(struct repository *repo)\n {\n-\tif (is_cache_init)\n+\tif (repo->submodule_cache && repo->submodule_cache->initialized)\n \t\treturn;\n \n-\tcache_init(&the_submodule_cache);\n-\tis_cache_init = 1;\n+\tif (!repo->submodule_cache)\n+\t\trepo->submodule_cache = submodule_cache_alloc();\n+\n+\tsubmodule_cache_init(repo->submodule_cache);\n }\n \n-int parse_submodule_config_option(const char *var, const char *value)\n+int submodule_config_option(struct repository *repo,\n+\t\t\t    const char *var, const char *value)\n {\n \tstruct parse_config_parameter parameter;\n-\tparameter.cache = &the_submodule_cache;\n+\n+\tsubmodule_cache_check_init(repo);\n+\n+\tparameter.cache = repo->submodule_cache;\n \tparameter.treeish_name = NULL;\n \tparameter.gitmodules_sha1 = null_sha1;\n \tparameter.overwrite = 1;\n \n-\tensure_cache_init();\n \treturn parse_config(var, value, &parameter);\n }\n \n+int parse_submodule_config_option(const char *var, const char *value)\n+{\n+\treturn submodule_config_option(the_repository, var, value);\n+}\n+\n const struct submodule *submodule_from_name(const unsigned char *treeish_name,\n \t\tconst char *name)\n {\n-\tensure_cache_init();\n-\treturn config_from(&the_submodule_cache, treeish_name, name, lookup_name);\n+\tsubmodule_cache_check_init(the_repository);\n+\treturn config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);\n }\n \n const struct submodule *submodule_from_path(const unsigned char *treeish_name,\n \t\tconst char *path)\n {\n-\tensure_cache_init();\n-\treturn config_from(&the_submodule_cache, treeish_name, path, lookup_path);\n+\tsubmodule_cache_check_init(the_repository);\n+\treturn config_from(the_repository->submodule_cache, treeish_name, path, lookup_path);\n+}\n+\n+const struct submodule *submodule_from_cache(struct repository *repo,\n+\t\t\t\t\t     const unsigned char *treeish_name,\n+\t\t\t\t\t     const char *key)\n+{\n+\tsubmodule_cache_check_init(repo);\n+\treturn config_from(repo->submodule_cache, treeish_name,\n+\t\t\t   key, lookup_path);\n }\n \n void submodule_free(void)\n {\n-\tcache_free(&the_submodule_cache);\n-\tis_cache_init = 0;\n+\tif (the_repository->submodule_cache)\n+\t\tsubmodule_cache_clear(the_repository->submodule_cache);\n }\ndiff --git a/submodule-config.h b/submodule-config.h\nindex d434ecdb4..bc45a25e8 100644\n--- a/submodule-config.h\n+++ b/submodule-config.h\n@@ -22,14 +22,24 @@ struct submodule {\n \tint recommend_shallow;\n };\n \n+struct submodule_cache;\n+struct repository;\n+\n+extern void submodule_cache_free(struct submodule_cache *cache);\n+\n extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_submodule_config_option(const char *var, const char *value);\n+extern int submodule_config_option(struct repository *repo,\n+\t\t\t\t   const char *var, const char *value);\n extern const struct submodule *submodule_from_name(\n \t\tconst unsigned char *commit_or_tree, const char *name);\n extern const struct submodule *submodule_from_path(\n \t\tconst unsigned char *commit_or_tree, const char *path);\n+extern const struct submodule *submodule_from_cache(struct repository *repo,\n+\t\t\t\t\t\t    const unsigned char *treeish_name,\n+\t\t\t\t\t\t    const char *key);\n extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,\n \t\t\t\t      unsigned char *gitmodules_sha1,\n \t\t\t\t      struct strbuf *rev);\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321808","messageId":"20170608234100.188529-13-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 12/32] repository: add index_state to struct repo","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:40Z","receivedAt":"2017-06-08T23:42:41Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n repository.c | 16 ++++++++++++++++\n repository.h |  4 ++++\n 2 files changed, 20 insertions(+)\n\ndiff --git a/repository.c b/repository.c\nindex fd53d6bf7..21719d0a6 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -186,5 +186,21 @@ void repo_clear(struct repository *repo)\n \t\trepo->config = NULL;\n \t}\n \n+\tif (repo->index) {\n+\t\tdiscard_index(repo->index);\n+\t\tfree(repo->index);\n+\t\trepo->index = NULL;\n+\t}\n+\n \tmemset(repo, 0, sizeof(*repo));\n }\n+\n+int repo_read_index(struct repository *repo)\n+{\n+\tif (!repo->index)\n+\t\trepo->index = xcalloc(1, sizeof(struct index_state));\n+\telse\n+\t\tdiscard_index(repo->index);\n+\n+\treturn read_index_from(repo->index, repo->index_file);\n+}\ndiff --git a/repository.h b/repository.h\nindex 2b757df25..9515cc631 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -2,6 +2,7 @@\n #define REPOSITORY_H\n \n struct config_set;\n+struct index_state;\n \n struct repository {\n \t/* Environment */\n@@ -20,6 +21,7 @@ struct repository {\n \t * ~/.gitconfig, XDG config file and the global /etc/gitconfig)\n \t */\n \tstruct config_set *config;\n+\tstruct index_state *index;\n \n \t/* Configurations */\n \tunsigned ignore_env:1;\n@@ -35,4 +37,6 @@ extern char *repo_worktree_path(struct repository *repo, const char *path);\n extern int repo_init(struct repository *repo, const char *path);\n extern void repo_clear(struct repository *repo);\n \n+extern int repo_read_index(struct repository *repo);\n+\n #endif /* REPOSITORY_H */\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321809","messageId":"20170608234100.188529-9-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 08/32] environment: place key repository state in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:36Z","receivedAt":"2017-06-08T23:42:46Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate 'git_dir', 'git_common_dir', 'git_object_dir', 'git_index_file',\n'git_graft_file', and 'namespace' to be stored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h       |  1 -\n environment.c | 65 ++++++++++++++---------------------------------------------\n path.c        | 11 +++++-----\n setup.c       | 17 ++++++++++++++--\n 4 files changed, 36 insertions(+), 58 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c0b4c8d83..02ab5f801 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -769,7 +769,6 @@ extern int core_apply_sparse_checkout;\n extern int precomposed_unicode;\n extern int protect_hfs;\n extern int protect_ntfs;\n-extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n \n /*\n  * Include broken refs in all ref iterations, which will\ndiff --git a/environment.c b/environment.c\nindex 77900b31a..fb52c0daf 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,7 @@\n  * are.\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"refs.h\"\n #include \"fmt-merge-msg.h\"\n@@ -97,14 +98,8 @@ int ignore_untracked_cache_config;\n char *git_work_tree_cfg;\n static char *work_tree;\n \n-static const char *namespace;\n-\n static const char *super_prefix;\n \n-static const char *git_dir, *git_common_dir;\n-static char *git_object_dir, *git_index_file, *git_graft_file;\n-int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -148,47 +143,16 @@ char *expand_namespace(const char *raw_namespace)\n \treturn strbuf_detach(&buf, NULL);\n }\n \n-static char *git_path_from_env(const char *envvar, const char *git_dir,\n-\t\t\t       const char *path, int *fromenv)\n-{\n-\tconst char *value = getenv(envvar);\n-\tif (!value)\n-\t\treturn xstrfmt(\"%s/%s\", git_dir, path);\n-\tif (fromenv)\n-\t\t*fromenv = 1;\n-\treturn xstrdup(value);\n-}\n-\n void setup_git_env(void)\n {\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *gitfile;\n \tconst char *shallow_file;\n \tconst char *replace_ref_base;\n \n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n-\tif (!git_dir) {\n-\t\tif (!startup_info->have_repository)\n-\t\t\tBUG(\"setup_git_env called without repository\");\n-\t\tgit_dir = DEFAULT_GIT_DIR_ENVIRONMENT;\n-\t}\n-\tgitfile = read_gitfile(git_dir);\n-\tgit_dir = xstrdup(gitfile ? gitfile : git_dir);\n-\tif (get_common_dir(&sb, git_dir))\n-\t\tgit_common_dir_env = 1;\n-\tgit_common_dir = strbuf_detach(&sb, NULL);\n-\tgit_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,\n-\t\t\t\t\t   \"objects\", &git_db_env);\n-\tgit_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,\n-\t\t\t\t\t   \"index\", &git_index_env);\n-\tgit_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, git_common_dir,\n-\t\t\t\t\t   \"info/grafts\", &git_graft_env);\n \tif (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))\n \t\tcheck_replace_refs = 0;\n \treplace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);\n \tgit_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base\n \t\t\t\t\t\t\t  : \"refs/replace/\");\n-\tnamespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));\n \tshallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);\n \tif (shallow_file)\n \t\tset_alternate_shallow_file(shallow_file, 0);\n@@ -203,28 +167,28 @@ int is_bare_repository(void)\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n-\t\t|| git_dir;\n+\t\t|| the_repository->gitdir;\n }\n \n const char *get_git_dir(void)\n {\n-\tif (!git_dir)\n+\tif (!the_repository->gitdir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_dir;\n+\treturn the_repository->gitdir;\n }\n \n const char *get_git_common_dir(void)\n {\n-\tif (!git_dir)\n+\tif (!the_repository->commondir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_common_dir;\n+\treturn the_repository->commondir;\n }\n \n const char *get_git_namespace(void)\n {\n-\tif (!namespace)\n+\tif (!the_repository->namespace)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn namespace;\n+\treturn the_repository->namespace;\n }\n \n const char *strip_namespace(const char *namespaced_ref)\n@@ -273,9 +237,9 @@ const char *get_git_work_tree(void)\n \n char *get_object_directory(void)\n {\n-\tif (!git_object_dir)\n+\tif (!the_repository->objectdir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_object_dir;\n+\treturn the_repository->objectdir;\n }\n \n int odb_mkstemp(struct strbuf *template, const char *pattern)\n@@ -313,22 +277,23 @@ int odb_pack_keep(const char *name)\n \n char *get_index_file(void)\n {\n-\tif (!git_index_file)\n+\tif (!the_repository->index_file)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_index_file;\n+\treturn the_repository->index_file;\n }\n \n char *get_graft_file(void)\n {\n-\tif (!git_graft_file)\n+\tif (!the_repository->graft_file)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_graft_file;\n+\treturn the_repository->graft_file;\n }\n \n int set_git_dir(const char *path)\n {\n \tif (setenv(GIT_DIR_ENVIRONMENT, path, 1))\n \t\treturn error(\"Could not set GIT_DIR to '%s'\", path);\n+\trepo_set_gitdir(the_repository, path);\n \tsetup_git_env();\n \treturn 0;\n }\ndiff --git a/path.c b/path.c\nindex c1cb1cf62..e4abea083 100644\n--- a/path.c\n+++ b/path.c\n@@ -2,6 +2,7 @@\n  * Utilities for paths and pathnames\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"dir.h\"\n@@ -355,7 +356,7 @@ void report_linked_checkout_garbage(void)\n \tconst struct common_dir *p;\n \tint len;\n \n-\tif (!git_common_dir_env)\n+\tif (!the_repository->different_commondir)\n \t\treturn;\n \tstrbuf_addf(&sb, \"%s/\", get_git_dir());\n \tlen = sb.len;\n@@ -374,17 +375,17 @@ void report_linked_checkout_garbage(void)\n static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n {\n \tconst char *base = buf->buf + git_dir_len;\n-\tif (git_graft_env && is_dir_file(base, \"info\", \"grafts\"))\n+\tif (is_dir_file(base, \"info\", \"grafts\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      get_graft_file(), strlen(get_graft_file()));\n-\telse if (git_index_env && !strcmp(base, \"index\"))\n+\telse if (!strcmp(base, \"index\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      get_index_file(), strlen(get_index_file()));\n-\telse if (git_db_env && dir_prefix(base, \"objects\"))\n+\telse if (dir_prefix(base, \"objects\"))\n \t\treplace_dir(buf, git_dir_len + 7, get_object_directory());\n \telse if (git_hooks_path && dir_prefix(base, \"hooks\"))\n \t\treplace_dir(buf, git_dir_len + 5, git_hooks_path);\n-\telse if (git_common_dir_env)\n+\telse if (the_repository->different_commondir)\n \t\tupdate_common_dir(buf, git_dir_len, NULL);\n }\n \ndiff --git a/setup.c b/setup.c\nindex b2e05145c..884a74a54 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"dir.h\"\n #include \"string-list.h\"\n@@ -376,6 +377,11 @@ void setup_work_tree(void)\n \tif (getenv(GIT_WORK_TREE_ENVIRONMENT))\n \t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, \".\", 1);\n \n+\t/*\n+\t * NEEDSWORK: this call can essentially be set_git_dir(get_git_dir())\n+\t * which can cause some problems when trying to free the old value of\n+\t * gitdir.\n+\t */\n \tset_git_dir(remove_leading_path(git_dir, work_tree));\n \tinitialized = 1;\n }\n@@ -1074,8 +1080,15 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t * the user has set GIT_DIR.  It may be beneficial to disallow bogus\n \t * GIT_DIR values at some point in the future.\n \t */\n-\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT))\n-\t\tsetup_git_env();\n+\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT)) {\n+\t\tif (!the_repository->gitdir) {\n+\t\t\tconst char *gitdir = getenv(GIT_DIR_ENVIRONMENT);\n+\t\t\tif (!gitdir)\n+\t\t\t\tgitdir = DEFAULT_GIT_DIR_ENVIRONMENT;\n+\t\t\trepo_set_gitdir(the_repository, gitdir);\n+\t\t\tsetup_git_env();\n+\t\t}\n+\t}\n \n \tstrbuf_release(&dir);\n \tstrbuf_release(&gitdir);\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321810","messageId":"20170608234100.188529-12-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v2 11/32] config: read config from a repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-08T23:40:39Z","receivedAt":"2017-06-08T23:42:49Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach the config machinery to read config information from a repository\nobject.  This involves storing a 'struct config_set' inside the\nrepository object and adding a number of functions (repo_config*) to be\nable to query a repository's config.\n\nThe current config API enables lazy-loading of the config.  This means\nthat when 'git_config_get_int()' is called, if the_config_set hasn't\nbeen populated yet, then it will be populated and properly initialized by\nreading the necessary config files (system wide .gitconfig, user's home\n.gitconfig, and the repository's config).  To maintain this paradigm,\nthe new API to read from a repository object's config will also perform\nthis lazy-initialization.\n\nSince both APIs (git_config_get* and repo_config_get*) have the same\nsemantics we can migrate the default config to be stored within\n'the_repository' and just have the 'git_config_get*' family of functions\nredirect to the 'repo_config_get*' functions.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n config.c     | 209 +++++++++++++++++++++++++++++++++++++++--------------------\n config.h     |  24 +++++++\n repository.c |   7 ++\n repository.h |  10 +++\n 4 files changed, 179 insertions(+), 71 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex ff09b27b8..3bfe2766f 100644\n--- a/config.c\n+++ b/config.c\n@@ -7,6 +7,7 @@\n  */\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"repository.h\"\n #include \"lockfile.h\"\n #include \"exec_cmd.h\"\n #include \"strbuf.h\"\n@@ -72,13 +73,6 @@ static int core_compression_seen;\n static int pack_compression_seen;\n static int zlib_compression_seen;\n \n-/*\n- * Default config_set that contains key-value pairs from the usual set of config\n- * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG\n- * config file and the global /etc/gitconfig)\n- */\n-static struct config_set the_config_set;\n-\n static int config_file_fgetc(struct config_source *conf)\n {\n \treturn getc_unlocked(conf->u.file);\n@@ -1606,28 +1600,6 @@ int git_config_with_options(config_fn_t fn, void *data,\n \treturn do_git_config_sequence(opts, fn, data);\n }\n \n-static void git_config_raw(config_fn_t fn, void *data)\n-{\n-\tstruct config_options opts = {0};\n-\n-\topts.respect_includes = 1;\n-\tif (have_git_dir())\n-\t\topts.git_dir = get_git_common_dir();\n-\tif (git_config_with_options(fn, data, NULL, &opts) < 0)\n-\t\t/*\n-\t\t * git_config_with_options() normally returns only\n-\t\t * zero, as most errors are fatal, and\n-\t\t * non-fatal potential errors are guarded by \"if\"\n-\t\t * statements that are entered only when no error is\n-\t\t * possible.\n-\t\t *\n-\t\t * If we ever encounter a non-fatal error, it means\n-\t\t * something went really wrong and we should stop\n-\t\t * immediately.\n-\t\t */\n-\t\tdie(_(\"unknown error occurred while reading the configuration files\"));\n-}\n-\n static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)\n {\n \tint i, value_index;\n@@ -1676,14 +1648,6 @@ void read_early_config(config_fn_t cb, void *data)\n \tstrbuf_release(&buf);\n }\n \n-static void git_config_check_init(void);\n-\n-void git_config(config_fn_t fn, void *data)\n-{\n-\tgit_config_check_init();\n-\tconfigset_iter(&the_config_set, fn, data);\n-}\n-\n static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)\n {\n \tstruct config_set_element k;\n@@ -1893,87 +1857,190 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha\n \t\treturn 1;\n }\n \n-static void git_config_check_init(void)\n+/* Functions use to read configuration from a repository */\n+static void repo_read_config(struct repository *repo)\n {\n-\tif (the_config_set.hash_initialized)\n+\tstruct config_options opts = { 1, repo->commondir };\n+\n+\tif (!repo->config)\n+\t\trepo->config = xcalloc(1, sizeof(struct config_set));\n+\telse\n+\t\tgit_configset_clear(repo->config);\n+\n+\tgit_configset_init(repo->config);\n+\n+\tif (git_config_with_options(config_set_callback, repo->config, NULL, &opts) < 0)\n+\t\t/*\n+\t\t * git_config_with_options() normally returns only\n+\t\t * zero, as most errors are fatal, and\n+\t\t * non-fatal potential errors are guarded by \"if\"\n+\t\t * statements that are entered only when no error is\n+\t\t * possible.\n+\t\t *\n+\t\t * If we ever encounter a non-fatal error, it means\n+\t\t * something went really wrong and we should stop\n+\t\t * immediately.\n+\t\t */\n+\t\tdie(_(\"unknown error occurred while reading the configuration files\"));\n+}\n+\n+static void git_config_check_init(struct repository *repo)\n+{\n+\tif (repo->config && repo->config->hash_initialized)\n \t\treturn;\n-\tgit_configset_init(&the_config_set);\n-\tgit_config_raw(config_set_callback, &the_config_set);\n+\trepo_read_config(repo);\n }\n \n-void git_config_clear(void)\n+static void repo_config_clear(struct repository *repo)\n {\n-\tif (!the_config_set.hash_initialized)\n+\tif (!repo->config || !repo->config->hash_initialized)\n \t\treturn;\n-\tgit_configset_clear(&the_config_set);\n+\tgit_configset_clear(repo->config);\n }\n \n-int git_config_get_value(const char *key, const char **value)\n+void repo_config(struct repository *repo, config_fn_t fn, void *data)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_value(&the_config_set, key, value);\n+\tgit_config_check_init(repo);\n+\tconfigset_iter(repo->config, fn, data);\n }\n \n-const struct string_list *git_config_get_value_multi(const char *key)\n+int repo_config_get_value(struct repository *repo,\n+\t\t\t  const char *key, const char **value)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_value_multi(&the_config_set, key);\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_value(repo->config, key, value);\n }\n \n-int git_config_get_string_const(const char *key, const char **dest)\n+const struct string_list *repo_config_get_value_multi(struct repository *repo,\n+\t\t\t\t\t\t      const char *key)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_value_multi(repo->config, key);\n+}\n+\n+int repo_config_get_string_const(struct repository *repo,\n+\t\t\t\t const char *key, const char **dest)\n {\n \tint ret;\n-\tgit_config_check_init();\n-\tret = git_configset_get_string_const(&the_config_set, key, dest);\n+\tgit_config_check_init(repo);\n+\tret = git_configset_get_string_const(repo->config, key, dest);\n \tif (ret < 0)\n \t\tgit_die_config(key, NULL);\n \treturn ret;\n }\n \n+int repo_config_get_string(struct repository *repo,\n+\t\t\t   const char *key, char **dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn repo_config_get_string_const(repo, key, (const char **)dest);\n+}\n+\n+int repo_config_get_int(struct repository *repo,\n+\t\t\tconst char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_int(repo->config, key, dest);\n+}\n+\n+int repo_config_get_ulong(struct repository *repo,\n+\t\t\t  const char *key, unsigned long *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_ulong(repo->config, key, dest);\n+}\n+\n+int repo_config_get_bool(struct repository *repo,\n+\t\t\t const char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_bool(repo->config, key, dest);\n+}\n+\n+int repo_config_get_bool_or_int(struct repository *repo,\n+\t\t\t\tconst char *key, int *is_bool, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_bool_or_int(repo->config, key, is_bool, dest);\n+}\n+\n+int repo_config_get_maybe_bool(struct repository *repo,\n+\t\t\t       const char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_maybe_bool(repo->config, key, dest);\n+}\n+\n+int repo_config_get_pathname(struct repository *repo,\n+\t\t\t     const char *key, const char **dest)\n+{\n+\tint ret;\n+\tgit_config_check_init(repo);\n+\tret = git_configset_get_pathname(repo->config, key, dest);\n+\tif (ret < 0)\n+\t\tgit_die_config(key, NULL);\n+\treturn ret;\n+}\n+\n+/* Functions used historically to read configuration from 'the_repository' */\n+void git_config(config_fn_t fn, void *data)\n+{\n+\trepo_config(the_repository, fn, data);\n+}\n+\n+void git_config_clear(void)\n+{\n+\trepo_config_clear(the_repository);\n+}\n+\n+int git_config_get_value(const char *key, const char **value)\n+{\n+\treturn repo_config_get_value(the_repository, key, value);\n+}\n+\n+const struct string_list *git_config_get_value_multi(const char *key)\n+{\n+\treturn repo_config_get_value_multi(the_repository, key);\n+}\n+\n+int git_config_get_string_const(const char *key, const char **dest)\n+{\n+\treturn repo_config_get_string_const(the_repository, key, dest);\n+}\n+\n int git_config_get_string(const char *key, char **dest)\n {\n-\tgit_config_check_init();\n-\treturn git_config_get_string_const(key, (const char **)dest);\n+\treturn repo_config_get_string(the_repository, key, dest);\n }\n \n int git_config_get_int(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_int(&the_config_set, key, dest);\n+\treturn repo_config_get_int(the_repository, key, dest);\n }\n \n int git_config_get_ulong(const char *key, unsigned long *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_ulong(&the_config_set, key, dest);\n+\treturn repo_config_get_ulong(the_repository, key, dest);\n }\n \n int git_config_get_bool(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_bool(&the_config_set, key, dest);\n+\treturn repo_config_get_bool(the_repository, key, dest);\n }\n \n int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);\n+\treturn repo_config_get_bool_or_int(the_repository, key, is_bool, dest);\n }\n \n int git_config_get_maybe_bool(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_maybe_bool(&the_config_set, key, dest);\n+\treturn repo_config_get_maybe_bool(the_repository, key, dest);\n }\n \n int git_config_get_pathname(const char *key, const char **dest)\n {\n-\tint ret;\n-\tgit_config_check_init();\n-\tret = git_configset_get_pathname(&the_config_set, key, dest);\n-\tif (ret < 0)\n-\t\tgit_die_config(key, NULL);\n-\treturn ret;\n+\treturn repo_config_get_pathname(the_repository, key, dest);\n }\n \n int git_config_get_expiry(const char *key, const char **output)\ndiff --git a/config.h b/config.h\nindex c70599bd5..a4db8d0f4 100644\n--- a/config.h\n+++ b/config.h\n@@ -162,6 +162,30 @@ extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key,\n extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);\n extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);\n \n+/* Functions for reading a repository's config */\n+struct repository;\n+extern void repo_config(struct repository *repo, config_fn_t fn, void *data);\n+extern int repo_config_get_value(struct repository *repo,\n+\t\t\t\t const char *key, const char **value);\n+extern const struct string_list *repo_config_get_value_multi(struct repository *repo,\n+\t\t\t\t\t\t\t     const char *key);\n+extern int repo_config_get_string_const(struct repository *repo,\n+\t\t\t\t\tconst char *key, const char **dest);\n+extern int repo_config_get_string(struct repository *repo,\n+\t\t\t\t  const char *key, char **dest);\n+extern int repo_config_get_int(struct repository *repo,\n+\t\t\t       const char *key, int *dest);\n+extern int repo_config_get_ulong(struct repository *repo,\n+\t\t\t\t const char *key, unsigned long *dest);\n+extern int repo_config_get_bool(struct repository *repo,\n+\t\t\t\tconst char *key, int *dest);\n+extern int repo_config_get_bool_or_int(struct repository *repo,\n+\t\t\t\t       const char *key, int *is_bool, int *dest);\n+extern int repo_config_get_maybe_bool(struct repository *repo,\n+\t\t\t\t      const char *key, int *dest);\n+extern int repo_config_get_pathname(struct repository *repo,\n+\t\t\t\t    const char *key, const char **dest);\n+\n extern int git_config_get_value(const char *key, const char **value);\n extern const struct string_list *git_config_get_value_multi(const char *key);\n extern void git_config_clear(void);\ndiff --git a/repository.c b/repository.c\nindex 1b48cc816..fd53d6bf7 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"repository.h\"\n+#include \"config.h\"\n \n /* The main repository */\n static struct repository the_repo;\n@@ -179,5 +180,11 @@ void repo_clear(struct repository *repo)\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n \n+\tif (repo->config) {\n+\t\tgit_configset_clear(repo->config);\n+\t\tfree(repo->config);\n+\t\trepo->config = NULL;\n+\t}\n+\n \tmemset(repo, 0, sizeof(*repo));\n }\ndiff --git a/repository.h b/repository.h\nindex a1163ae91..2b757df25 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -1,6 +1,8 @@\n #ifndef REPOSITORY_H\n #define REPOSITORY_H\n \n+struct config_set;\n+\n struct repository {\n \t/* Environment */\n \tchar *gitdir;\n@@ -11,6 +13,14 @@ struct repository {\n \tchar *namespace;\n \tchar *worktree;\n \n+\t/* Subsystems */\n+\t/*\n+\t * Repository's config which contains key-value pairs from the usual\n+\t * set of config files (i.e. repo specific .git/config, user wide\n+\t * ~/.gitconfig, XDG config file and the global /etc/gitconfig)\n+\t */\n+\tstruct config_set *config;\n+\n \t/* Configurations */\n \tunsigned ignore_env:1;\n \t/* Indicates if a repository has a different 'commondir' from 'gitdir' */\n-- \n2.13.1.508.gb3defc5cc-goog\n\n"},{"id":"321811","messageId":"20170609000849.GA130522@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-33-bmwill@google.com","subject":"Re: [PATCH v2 32/32] ls-files: use repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-09T00:08:49Z","receivedAt":"2017-06-09T00:09:02Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/08, Brandon Williams wrote:\n> Convert ls-files to use a repository struct and recurse submodules\n> inprocess.\n> \n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  builtin/ls-files.c                     | 198 ++++++++++++++-------------------\n>  git.c                                  |   2 +-\n>  repository.c                           |   4 +\n>  repository.h                           |   1 +\n>  t/t3007-ls-files-recurse-submodules.sh |  39 +++++++\n>  5 files changed, 129 insertions(+), 115 deletions(-)\n> \n> diff --git a/builtin/ls-files.c b/builtin/ls-files.c\n> index 6a0302a28..503fed5a1 100644\n> --- a/builtin/ls-files.c\n> +++ b/builtin/ls-files.c\n> @@ -5,7 +5,9 @@\n>   *\n>   * Copyright (C) Linus Torvalds, 2005\n>   */\n> +#define NO_THE_INDEX_COMPATIBILITY_MACROS\n>  #include \"cache.h\"\n> +#include \"repository.h\"\n>  #include \"config.h\"\n>  #include \"quote.h\"\n>  #include \"dir.h\"\n> @@ -32,10 +34,8 @@ static int line_terminator = '\\n';\n>  static int debug_mode;\n>  static int show_eol;\n>  static int recurse_submodules;\n> -static struct argv_array submodule_options = ARGV_ARRAY_INIT;\n>  \n>  static const char *prefix;\n> -static const char *super_prefix;\n>  static int max_prefix_len;\n>  static int prefix_len;\n>  static struct pathspec pathspec;\n> @@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,\n>  \n>  static void write_name(const char *name)\n>  {\n> -\t/*\n> -\t * Prepend the super_prefix to name to construct the full_name to be\n> -\t * written.\n> -\t */\n> -\tstruct strbuf full_name = STRBUF_INIT;\n> -\tif (super_prefix) {\n> -\t\tstrbuf_addstr(&full_name, super_prefix);\n> -\t\tstrbuf_addstr(&full_name, name);\n> -\t\tname = full_name.buf;\n> -\t}\n> -\n>  \t/*\n>  \t * With \"--full-name\", prefix_len=0; this caller needs to pass\n>  \t * an empty string in that case (a NULL is good for \"\").\n>  \t */\n>  \twrite_name_quoted_relative(name, prefix_len ? prefix : NULL,\n>  \t\t\t\t   stdout, line_terminator);\n> -\n> -\tstrbuf_release(&full_name);\n>  }\n>  \n>  static const char *get_tag(const struct cache_entry *ce, const char *tag)\n> @@ -210,82 +197,41 @@ static void show_killed_files(const struct index_state *istate,\n>  \t}\n>  }\n>  \n> -/*\n> - * Compile an argv_array with all of the options supported by --recurse_submodules\n> - */\n> -static void compile_submodule_options(const char **argv,\n> -\t\t\t\t      const struct dir_struct *dir,\n> -\t\t\t\t      int show_tag)\n> -{\n> -\tif (line_terminator == '\\0')\n> -\t\targv_array_push(&submodule_options, \"-z\");\n> -\tif (show_tag)\n> -\t\targv_array_push(&submodule_options, \"-t\");\n> -\tif (show_valid_bit)\n> -\t\targv_array_push(&submodule_options, \"-v\");\n> -\tif (show_cached)\n> -\t\targv_array_push(&submodule_options, \"--cached\");\n> -\tif (show_eol)\n> -\t\targv_array_push(&submodule_options, \"--eol\");\n> -\tif (debug_mode)\n> -\t\targv_array_push(&submodule_options, \"--debug\");\n> -\n> -\t/* Add Pathspecs */\n> -\targv_array_push(&submodule_options, \"--\");\n> -\tfor (; *argv; argv++)\n> -\t\targv_array_push(&submodule_options, *argv);\n> -}\n> +static void show_files(struct repository *repo, struct dir_struct *dir);\n>  \n> -/**\n> - * Recursively call ls-files on a submodule\n> - */\n> -static void show_gitlink(const struct cache_entry *ce)\n> +static void show_submodule(const struct repository *superproject,\n> +\t\t\t   struct dir_struct *dir, const char *path)\n>  {\n> -\tstruct child_process cp = CHILD_PROCESS_INIT;\n> -\tint status;\n> -\tchar *dir;\n> -\n> -\tprepare_submodule_repo_env(&cp.env_array);\n> -\targv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);\n> -\n> -\tif (prefix_len)\n> -\t\targv_array_pushf(&cp.env_array, \"%s=%s\",\n> -\t\t\t\t GIT_TOPLEVEL_PREFIX_ENVIRONMENT,\n> -\t\t\t\t prefix);\n> -\targv_array_pushf(&cp.args, \"--super-prefix=%s%s/\",\n> -\t\t\t super_prefix ? super_prefix : \"\",\n> -\t\t\t ce->name);\n> -\targv_array_push(&cp.args, \"ls-files\");\n> -\targv_array_push(&cp.args, \"--recurse-submodules\");\n> -\n> -\t/* add supported options */\n> -\targv_array_pushv(&cp.args, submodule_options.argv);\n> -\n> -\tcp.git_cmd = 1;\n> -\tdir = mkpathdup(\"%s/%s\", get_git_work_tree(), ce->name);\n> -\tcp.dir = dir;\n> -\tstatus = run_command(&cp);\n> -\tfree(dir);\n> -\tif (status)\n> -\t\texit(status);\n> +\tstruct repository submodule;\n> +\tchar *gitdir = mkpathdup(\"%s/%s\", superproject->worktree, path);\n> +\trepo_init(&submodule, gitdir);\n> +\n> +\trepo_read_index(&submodule);\n> +\trepo_read_gitmodules(&submodule);\n> +\n> +\tif (superproject->submodule_prefix)\n> +\t\tsubmodule.submodule_prefix = xstrfmt(\"%s%s/\", superproject->submodule_prefix, path);\n> +\telse\n> +\t\tsubmodule.submodule_prefix = xstrfmt(\"%s/\", path);\n> +\tshow_files(&submodule, dir);\n> +\n> +\trepo_clear(&submodule);\n> +\tfree(gitdir);\n>  }\n>  \n> -static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n> +static void show_ce(struct repository *repo, struct dir_struct *dir,\n> +\t\t    const struct cache_entry *ce, const char *fullname,\n> +\t\t    const char *tag)\n>  {\n> -\tstruct strbuf name = STRBUF_INIT;\n> -\tint len = max_prefix_len;\n> -\tif (super_prefix)\n> -\t\tstrbuf_addstr(&name, super_prefix);\n> -\tstrbuf_addstr(&name, ce->name);\n> -\n> -\tif (len > ce_namelen(ce))\n> +\tif (max_prefix_len > strlen(fullname))\n>  \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n>  \n>  \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n> -\t    submodule_path_match(&pathspec, name.buf, ps_matched)) {\n> -\t\tshow_gitlink(ce);\n> -\t} else if (match_pathspec(&pathspec, name.buf, name.len,\n> -\t\t\t\t  len, ps_matched,\n> +\t    submodule_path_match(&pathspec, fullname, ps_matched) &&\n> +\t    is_submodule_active(repo, ce->name)) {\n> +\t\tshow_submodule(repo, dir, ce->name);\n> +\t} else if (match_pathspec(&pathspec, fullname, strlen(fullname),\n> +\t\t\t\t  max_prefix_len, ps_matched,\n>  \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n>  \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n>  \t\ttag = get_tag(ce, tag);\n> @@ -299,12 +245,11 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n>  \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n>  \t\t\t       ce_stage(ce));\n>  \t\t}\n> -\t\twrite_eolinfo(&the_index, ce, ce->name);\n> -\t\twrite_name(ce->name);\n> +\n> +\t\twrite_eolinfo(repo->index, ce, fullname);\n> +\t\twrite_name(fullname);\n>  \t\tprint_debug(ce);\n>  \t}\n> -\n> -\tstrbuf_release(&name);\n>  }\n>  \n>  static void show_ru_info(const struct index_state *istate)\n> @@ -337,59 +282,79 @@ static void show_ru_info(const struct index_state *istate)\n>  }\n>  \n>  static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n> -\t\t       const struct cache_entry *ce)\n> +\t\t       const char *fullname, const struct cache_entry *ce)\n>  {\n>  \tint dtype = ce_to_dtype(ce);\n> -\treturn is_excluded(dir, istate, ce->name, &dtype);\n> +\treturn is_excluded(dir, istate, fullname, &dtype);\n> +}\n> +\n> +static void construct_fullname(struct strbuf *out, const struct repository *repo,\n> +\t\t\t       const struct cache_entry *ce)\n> +{\n> +\tstrbuf_reset(out);\n> +\tif (repo->submodule_prefix)\n> +\t\tstrbuf_addstr(out, repo->submodule_prefix);\n> +\tstrbuf_addstr(out, ce->name);\n>  }\n>  \n> -static void show_files(struct index_state *istate, struct dir_struct *dir)\n> +static void show_files(struct repository *repo, struct dir_struct *dir)\n>  {\n>  \tint i;\n> +\tstruct strbuf fullname = STRBUF_INIT;\n>  \n>  \t/* For cached/deleted files we don't need to even do the readdir */\n>  \tif (show_others || show_killed) {\n>  \t\tif (!show_others)\n>  \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n> -\t\tfill_directory(dir, istate, &pathspec);\n> +\t\tfill_directory(dir, repo->index, &pathspec);\n>  \t\tif (show_others)\n> -\t\t\tshow_other_files(istate, dir);\n> +\t\t\tshow_other_files(repo->index, dir);\n>  \t\tif (show_killed)\n> -\t\t\tshow_killed_files(istate, dir);\n> +\t\t\tshow_killed_files(repo->index, dir);\n>  \t}\n>  \tif (show_cached || show_stage) {\n> -\t\tfor (i = 0; i < istate->cache_nr; i++) {\n> -\t\t\tconst struct cache_entry *ce = istate->cache[i];\n> +\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n> +\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n> +\n> +\t\t\tconstruct_fullname(&fullname, repo, ce);\n> +\n>  \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n> -\t\t\t    !ce_excluded(dir, istate, ce))\n> +\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n>  \t\t\t\tcontinue;\n>  \t\t\tif (show_unmerged && !ce_stage(ce))\n>  \t\t\t\tcontinue;\n>  \t\t\tif (ce->ce_flags & CE_UPDATE)\n>  \t\t\t\tcontinue;\n> -\t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged :\n> -\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);\n> +\t\t\tshow_ce(repo, dir, ce, fullname.buf,\n> +\t\t\t\tce_stage(ce) ? tag_unmerged :\n> +\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree :\n> +\t\t\t\t tag_cached));\n>  \t\t}\n>  \t}\n>  \tif (show_deleted || show_modified) {\n> -\t\tfor (i = 0; i < istate->cache_nr; i++) {\n> -\t\t\tconst struct cache_entry *ce = istate->cache[i];\n> +\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n> +\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n>  \t\t\tstruct stat st;\n>  \t\t\tint err;\n> +\n> +\t\t\tconstruct_fullname(&fullname, repo, ce);\n> +\n>  \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n> -\t\t\t    !ce_excluded(dir, istate, ce))\n> +\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n>  \t\t\t\tcontinue;\n>  \t\t\tif (ce->ce_flags & CE_UPDATE)\n>  \t\t\t\tcontinue;\n>  \t\t\tif (ce_skip_worktree(ce))\n>  \t\t\t\tcontinue;\n> -\t\t\terr = lstat(ce->name, &st);\n> +\t\t\terr = lstat(fullname.buf, &st);\n>  \t\t\tif (show_deleted && err)\n> -\t\t\t\tshow_ce_entry(tag_removed, ce);\n> -\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n> -\t\t\t\tshow_ce_entry(tag_modified, ce);\n> +\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed);\n> +\t\t\tif (show_modified && ie_modified(repo->index, ce, &st, 0))\n> +\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified);\n>  \t\t}\n>  \t}\n> +\n> +\tstrbuf_release(&fullname);\n>  }\n>  \n>  /*\n> @@ -614,10 +579,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n>  \tprefix = cmd_prefix;\n>  \tif (prefix)\n>  \t\tprefix_len = strlen(prefix);\n> -\tsuper_prefix = get_super_prefix();\n>  \tgit_config(git_default_config, NULL);\n>  \n> -\tif (read_cache() < 0)\n> +\tif (repo_read_index(the_repository))\n\noops, looks like this should have been:\n\n    if (repo_read_index(the_repository) < 0)\n\n>  \t\tdie(\"index file corrupt\");\n>  \n>  \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n> @@ -650,8 +614,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n>  \tif (require_work_tree && !is_inside_work_tree())\n>  \t\tsetup_work_tree();\n>  \n> -\tif (recurse_submodules)\n> -\t\tcompile_submodule_options(argv, &dir, show_tag);\n> +\tif (recurse_submodules) {\n> +\t\trepo_read_gitmodules(the_repository);\n> +\t}\n>  \n>  \tif (recurse_submodules &&\n>  \t    (show_stage || show_deleted || show_others || show_unmerged ||\n> @@ -669,7 +634,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n>  \t/*\n>  \t * Find common prefix for all pathspec's\n>  \t * This is used as a performance optimization which unfortunately cannot\n> -\t * be done when recursing into submodules\n> +\t * be done when recursing into submodules because when a pathspec is\n> +\t * given which spans repository boundaries you can't simply remove the\n> +\t * submodule entry because the pathspec may match something inside the\n> +\t * submodule.\n>  \t */\n>  \tif (recurse_submodules)\n>  \t\tmax_prefix = NULL;\n> @@ -677,7 +645,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n>  \t\tmax_prefix = common_prefix(&pathspec);\n>  \tmax_prefix_len = get_common_prefix_len(max_prefix);\n>  \n> -\tprune_index(&the_index, max_prefix, max_prefix_len);\n> +\tprune_index(the_repository->index, max_prefix, max_prefix_len);\n>  \n>  \t/* Treat unmatching pathspec elements as errors */\n>  \tif (pathspec.nr && error_unmatch)\n> @@ -698,11 +666,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n>  \t\t */\n>  \t\tif (show_stage || show_unmerged)\n>  \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n> -\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n> +\t\toverlay_tree_on_index(the_repository->index, with_tree, max_prefix);\n>  \t}\n> -\tshow_files(&the_index, &dir);\n> +\n> +\tshow_files(the_repository, &dir);\n> +\n>  \tif (show_resolve_undo)\n> -\t\tshow_ru_info(&the_index);\n> +\t\tshow_ru_info(the_repository->index);\n>  \n>  \tif (ps_matched) {\n>  \t\tint bad;\n> diff --git a/git.c b/git.c\n> index 594436e43..16c6e325d 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -442,7 +442,7 @@ static struct cmd_struct commands[] = {\n>  \t{ \"init-db\", cmd_init_db },\n>  \t{ \"interpret-trailers\", cmd_interpret_trailers, RUN_SETUP_GENTLY },\n>  \t{ \"log\", cmd_log, RUN_SETUP },\n> -\t{ \"ls-files\", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n> +\t{ \"ls-files\", cmd_ls_files, RUN_SETUP },\n>  \t{ \"ls-remote\", cmd_ls_remote, RUN_SETUP_GENTLY },\n>  \t{ \"ls-tree\", cmd_ls_tree, RUN_SETUP },\n>  \t{ \"mailinfo\", cmd_mailinfo, RUN_SETUP_GENTLY },\n> diff --git a/repository.c b/repository.c\n> index 98a851d20..9f899a34a 100644\n> --- a/repository.c\n> +++ b/repository.c\n> @@ -152,6 +152,8 @@ int repo_init(struct repository *repo, const char *gitdir)\n>  \tif (verify_repo_format(&format, repo->commondir))\n>  \t\tgoto error;\n>  \n> +\trepo_set_worktree(repo, gitdir);\n> +\n>  \treturn 0;\n>  \n>  error:\n> @@ -180,6 +182,8 @@ void repo_clear(struct repository *repo)\n>  \trepo_clear_env(repo);\n>  \tfree(repo->worktree);\n>  \trepo->worktree = NULL;\n> +\tfree(repo->submodule_prefix);\n> +\trepo->submodule_prefix = NULL;\n>  \n>  \tif (repo->config) {\n>  \t\tgit_configset_clear(repo->config);\n> diff --git a/repository.h b/repository.h\n> index d9f1f721b..eea9a88aa 100644\n> --- a/repository.h\n> +++ b/repository.h\n> @@ -14,6 +14,7 @@ struct repository {\n>  \tchar *graft_file;\n>  \tchar *namespace;\n>  \tchar *worktree;\n> +\tchar *submodule_prefix;\n>  \n>  \t/* Subsystems */\n>  \t/*\n> diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh\n> index ebb956fd1..318b5bce7 100755\n> --- a/t/t3007-ls-files-recurse-submodules.sh\n> +++ b/t/t3007-ls-files-recurse-submodules.sh\n> @@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '\n>  \ttest_cmp expect actual\n>  '\n>  \n> +test_expect_success 'inactive submodule' '\n> +\ttest_when_finished \"git config --bool submodule.submodule.active true\" &&\n> +\ttest_when_finished \"git -C submodule config --bool submodule.subsub.active true\" &&\n> +\tgit config --bool submodule.submodule.active \"false\" &&\n> +\n> +\tcat >expect <<-\\EOF &&\n> +\t.gitmodules\n> +\ta\n> +\tb/b\n> +\th.txt\n> +\tsib/file\n> +\tsub/file\n> +\tsubmodule\n> +\tEOF\n> +\n> +\tgit ls-files --recurse-submodules >actual &&\n> +\ttest_cmp expect actual &&\n> +\n> +\tgit config --bool submodule.submodule.active \"true\" &&\n> +\tgit -C submodule config --bool submodule.subsub.active \"false\" &&\n> +\n> +\tcat >expect <<-\\EOF &&\n> +\t.gitmodules\n> +\ta\n> +\tb/b\n> +\th.txt\n> +\tsib/file\n> +\tsub/file\n> +\tsubmodule/.gitmodules\n> +\tsubmodule/c\n> +\tsubmodule/f.TXT\n> +\tsubmodule/g.txt\n> +\tsubmodule/subsub\n> +\tEOF\n> +\n> +\tgit ls-files --recurse-submodules >actual &&\n> +\ttest_cmp expect actual\n> +'\n> +\n>  test_expect_success '--recurse-submodules and pathspecs' '\n>  \tcat >expect <<-\\EOF &&\n>  \th.txt\n> -- \n> 2.13.1.508.gb3defc5cc-goog\n> \n\n-- \nBrandon Williams\n"},{"id":"321817","messageId":"20170609085346.19974-1-avarab@gmail.com","threadId":"46082","inReplyTo":"20170608234100.188529-8-bmwill@google.com","subject":"[PATCH 0/2] Add a freez() wrapper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-09T08:53:44Z","receivedAt":"2017-06-09T08:54:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Fri, Jun 9, 2017 at 1:40 AM, Brandon Williams <bmwill@google.com> wrote:\n> Introduce the repository object 'struct repository' which can be used to\n> hold all state pertaining to a git repository.\n> [...]\n> +static void repo_clear_env(struct repository *repo)\n> +{\n> +       free(repo->gitdir);\n> +       repo->gitdir = NULL;\n> +       free(repo->commondir);\n> +       repo->commondir = NULL;\n> +       free(repo->objectdir);\n> +       repo->objectdir = NULL;\n> +       free(repo->index_file);\n> +       repo->index_file = NULL;\n> +       free(repo->graft_file);\n> +       repo->graft_file = NULL;\n> +       free(repo->namespace);\n> +       repo->namespace = NULL;\n> +}\n\nWhen seeing this I wondered if it couldn't be less noisy as:\n\n> +       freez(repo->gitdir);\n> +       freez(repo->commondir);\n> +       freez(repo->objectdir);\n> +       freez(repo->index_file);\n> +       freez(repo->graft_file);\n> +       freez(repo->namespace);\n\nIt's not a problem with your patch, but something I thought would be\nnice to have in general, so here's a patch series to implement that.\n\nÆvar Arnfjörð Bjarmason (2):\n  git-compat-util: add a freez() wrapper around free(x); x = NULL\n  *.[ch] refactoring: make use of the freez() wrapper\n\n alias.c                  |  6 ++----\n apply.c                  |  3 +--\n attr.c                   |  6 ++----\n blame.c                  |  3 +--\n branch.c                 |  3 +--\n builtin/am.c             | 18 +++++-------------\n builtin/clean.c          |  6 ++----\n builtin/config.c         |  6 ++----\n builtin/index-pack.c     |  6 ++----\n builtin/pack-objects.c   | 12 ++++--------\n builtin/unpack-objects.c |  3 +--\n builtin/worktree.c       |  6 ++----\n commit-slab.h            |  3 +--\n commit.c                 |  3 +--\n config.c                 |  3 +--\n credential.c             |  9 +++------\n diff-lib.c               |  3 +--\n diff.c                   |  6 ++----\n diffcore-rename.c        |  6 ++----\n dir.c                    |  9 +++------\n fast-import.c            |  6 ++----\n git-compat-util.h        |  1 +\n gpg-interface.c          | 15 +++++----------\n grep.c                   | 12 ++++--------\n help.c                   |  3 +--\n http-push.c              | 24 ++++++++----------------\n http.c                   | 15 +++++----------\n imap-send.c              |  3 +--\n line-log.c               |  6 ++----\n ll-merge.c               |  3 +--\n mailinfo.c               |  3 +--\n object.c                 |  3 +--\n pathspec.c               |  3 +--\n prio-queue.c             |  3 +--\n read-cache.c             |  6 ++----\n ref-filter.c             |  3 +--\n refs/files-backend.c     |  3 +--\n refs/ref-cache.c         |  3 +--\n remote-testsvn.c         |  3 +--\n rerere.c                 |  3 +--\n sequencer.c              |  3 +--\n sha1-array.c             |  3 +--\n sha1_file.c              |  3 +--\n split-index.c            |  3 +--\n transport-helper.c       | 27 +++++++++------------------\n transport.c              |  3 +--\n tree-diff.c              |  6 ++----\n tree-walk.c              |  3 +--\n tree.c                   |  3 +--\n 49 files changed, 98 insertions(+), 197 deletions(-)\n\n-- \n2.13.0.506.g27d5fe0cd\n\n"},{"id":"321818","messageId":"20170609085346.19974-2-avarab@gmail.com","threadId":"46082","inReplyTo":"20170609085346.19974-1-avarab@gmail.com","subject":"[PATCH 1/2] git-compat-util: add a freez() wrapper around free(x); x = NULL","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-09T08:53:45Z","receivedAt":"2017-06-09T08:54:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a freez() wrapper for the common pattern of freeing a pointer and\nassigning NULL to it right afterwards.\n\nThe implementation is the same as the (currently unused) XDL_PTRFREE\nmacro in xdiff/xmacros.h added in commit 3443546f6e (\"Use a *real*\nbuilt-in diff generator\", 2006-03-24).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n git-compat-util.h | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 4b7dcf21ad..21e3710755 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -787,6 +787,7 @@ extern char *xstrdup(const char *str);\n extern void *xmalloc(size_t size);\n extern void *xmallocz(size_t size);\n extern void *xmallocz_gently(size_t size);\n+#define freez(p) do { if (p) { free(p); (p) = NULL; } } while (0)\n extern void *xmemdupz(const void *data, size_t len);\n extern char *xstrndup(const char *str, size_t len);\n extern void *xrealloc(void *ptr, size_t size);\n-- \n2.13.0.506.g27d5fe0cd\n\n"},{"id":"321819","messageId":"20170609085346.19974-3-avarab@gmail.com","threadId":"46082","inReplyTo":"20170609085346.19974-1-avarab@gmail.com","subject":"[PATCH 2/2] *.[ch] refactoring: make use of the freez() wrapper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-09T08:53:46Z","receivedAt":"2017-06-09T08:54:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Replace occurrences of `free(p); p = NULL` with `freez(p)`. This\nintroduces no functional changes, but cuts the number of lines spent\non this cleanup in half.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n alias.c                  |  6 ++----\n apply.c                  |  3 +--\n attr.c                   |  6 ++----\n blame.c                  |  3 +--\n branch.c                 |  3 +--\n builtin/am.c             | 18 +++++-------------\n builtin/clean.c          |  6 ++----\n builtin/config.c         |  6 ++----\n builtin/index-pack.c     |  6 ++----\n builtin/pack-objects.c   | 12 ++++--------\n builtin/unpack-objects.c |  3 +--\n builtin/worktree.c       |  6 ++----\n commit-slab.h            |  3 +--\n commit.c                 |  3 +--\n config.c                 |  3 +--\n credential.c             |  9 +++------\n diff-lib.c               |  3 +--\n diff.c                   |  6 ++----\n diffcore-rename.c        |  6 ++----\n dir.c                    |  9 +++------\n fast-import.c            |  6 ++----\n gpg-interface.c          | 15 +++++----------\n grep.c                   | 12 ++++--------\n help.c                   |  3 +--\n http-push.c              | 24 ++++++++----------------\n http.c                   | 15 +++++----------\n imap-send.c              |  3 +--\n line-log.c               |  6 ++----\n ll-merge.c               |  3 +--\n mailinfo.c               |  3 +--\n object.c                 |  3 +--\n pathspec.c               |  3 +--\n prio-queue.c             |  3 +--\n read-cache.c             |  6 ++----\n ref-filter.c             |  3 +--\n refs/files-backend.c     |  3 +--\n refs/ref-cache.c         |  3 +--\n remote-testsvn.c         |  3 +--\n rerere.c                 |  3 +--\n sequencer.c              |  3 +--\n sha1-array.c             |  3 +--\n sha1_file.c              |  3 +--\n split-index.c            |  3 +--\n transport-helper.c       | 27 +++++++++------------------\n transport.c              |  3 +--\n tree-diff.c              |  6 ++----\n tree-walk.c              |  3 +--\n tree.c                   |  3 +--\n 48 files changed, 97 insertions(+), 197 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex 3b90397a99..99cd547b6b 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -47,8 +47,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \t\t\t\tsrc++;\n \t\t\t\tc = cmdline[src];\n \t\t\t\tif (!c) {\n-\t\t\t\t\tfree(*argv);\n-\t\t\t\t\t*argv = NULL;\n+\t\t\t\t\tfreez(*argv);\n \t\t\t\t\treturn -SPLIT_CMDLINE_BAD_ENDING;\n \t\t\t\t}\n \t\t\t}\n@@ -60,8 +59,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \tcmdline[dst] = 0;\n \n \tif (quoted) {\n-\t\tfree(*argv);\n-\t\t*argv = NULL;\n+\t\tfreez(*argv);\n \t\treturn -SPLIT_CMDLINE_UNCLOSED_QUOTE;\n \t}\n \ndiff --git a/apply.c b/apply.c\nindex c49cef0637..f987e1e961 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3705,8 +3705,7 @@ static int check_preimage(struct apply_state *state,\n  is_new:\n \tpatch->is_new = 1;\n \tpatch->is_delete = 0;\n-\tfree(patch->old_name);\n-\tpatch->old_name = NULL;\n+\tfreez(patch->old_name);\n \treturn 0;\n }\n \ndiff --git a/attr.c b/attr.c\nindex 7e2134471c..cd92a02e98 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -638,13 +638,11 @@ void attr_check_reset(struct attr_check *check)\n \n void attr_check_clear(struct attr_check *check)\n {\n-\tfree(check->items);\n-\tcheck->items = NULL;\n+\tfreez(check->items);\n \tcheck->alloc = 0;\n \tcheck->nr = 0;\n \n-\tfree(check->all_attrs);\n-\tcheck->all_attrs = NULL;\n+\tfreez(check->all_attrs);\n \tcheck->all_attrs_nr = 0;\n \n \tdrop_attr_stack(&check->stack);\ndiff --git a/blame.c b/blame.c\nindex 843c845cba..dc1688889c 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -314,8 +314,7 @@ static void fill_origin_blob(struct diff_options *opt,\n static void drop_origin_blob(struct blame_origin *o)\n {\n \tif (o->file.ptr) {\n-\t\tfree(o->file.ptr);\n-\t\to->file.ptr = NULL;\n+\t\tfreez(o->file.ptr);\n \t}\n }\n \ndiff --git a/branch.c b/branch.c\nindex 985316eb76..ef2ae0b49e 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -24,8 +24,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)\n \t\t} else {\n \t\t\tfree(tracking->spec.src);\n \t\t\tif (tracking->src) {\n-\t\t\t\tfree(tracking->src);\n-\t\t\t\ttracking->src = NULL;\n+\t\t\t\tfreez(tracking->src);\n \t\t\t}\n \t\t}\n \t\ttracking->spec.src = NULL;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5ee146bfb3..f5441cc990 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -483,8 +483,7 @@ static int run_applypatch_msg_hook(struct am_state *state)\n \tret = run_hook_le(NULL, \"applypatch-msg\", am_path(state, \"final-commit\"), NULL);\n \n \tif (!ret) {\n-\t\tfree(state->msg);\n-\t\tstate->msg = NULL;\n+\t\tfreez(state->msg);\n \t\tif (read_commit_msg(state) < 0)\n \t\t\tdie(_(\"'%s' was deleted by the applypatch-msg hook\"),\n \t\t\t\tam_path(state, \"final-commit\"));\n@@ -1073,17 +1072,10 @@ static void am_next(struct am_state *state)\n {\n \tstruct object_id head;\n \n-\tfree(state->author_name);\n-\tstate->author_name = NULL;\n-\n-\tfree(state->author_email);\n-\tstate->author_email = NULL;\n-\n-\tfree(state->author_date);\n-\tstate->author_date = NULL;\n-\n-\tfree(state->msg);\n-\tstate->msg = NULL;\n+\tfreez(state->author_name);\n+\tfreez(state->author_email);\n+\tfreez(state->author_date);\n+\tfreez(state->msg);\n \tstate->msg_len = 0;\n \n \tunlink(am_path(state, \"author-script\"));\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 142bf668cf..cdf7b0911e 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -837,8 +837,7 @@ static void interactive_main_loop(void)\n \t\t\tint ret;\n \t\t\tret = menus[*chosen].fn();\n \t\t\tif (ret != MENU_RETURN_NO_LOOP) {\n-\t\t\t\tfree(chosen);\n-\t\t\t\tchosen = NULL;\n+\t\t\t\tfreez(chosen);\n \t\t\t\tif (!del_list.nr) {\n \t\t\t\t\tclean_print_color(CLEAN_COLOR_ERROR);\n \t\t\t\t\tprintf_ln(_(\"No more files to clean, exiting.\"));\n@@ -851,8 +850,7 @@ static void interactive_main_loop(void)\n \t\t\tquit_cmd();\n \t\t}\n \n-\t\tfree(chosen);\n-\t\tchosen = NULL;\n+\t\tfreez(chosen);\n \t\tbreak;\n \t}\n }\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 7f6c25d4d9..e9adac9622 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -214,8 +214,7 @@ static int get_value(const char *key_, const char *regex_)\n \t\tkey_regexp = (regex_t*)xmalloc(sizeof(regex_t));\n \t\tif (regcomp(key_regexp, key, REG_EXTENDED)) {\n \t\t\terror(\"invalid key pattern: %s\", key_);\n-\t\t\tfree(key_regexp);\n-\t\t\tkey_regexp = NULL;\n+\t\t\tfreez(key_regexp);\n \t\t\tret = CONFIG_INVALID_PATTERN;\n \t\t\tgoto free_strings;\n \t\t}\n@@ -235,8 +234,7 @@ static int get_value(const char *key_, const char *regex_)\n \t\tregexp = (regex_t*)xmalloc(sizeof(regex_t));\n \t\tif (regcomp(regexp, regex_, REG_EXTENDED)) {\n \t\t\terror(\"invalid pattern: %s\", regex_);\n-\t\t\tfree(regexp);\n-\t\t\tregexp = NULL;\n+\t\t\tfreez(regexp);\n \t\t\tret = CONFIG_INVALID_PATTERN;\n \t\t\tgoto free_strings;\n \t\t}\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 04b9dcaf0f..4165e99484 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -388,8 +388,7 @@ static struct base_data *alloc_base_data(void)\n static void free_base_data(struct base_data *c)\n {\n \tif (c->data) {\n-\t\tfree(c->data);\n-\t\tc->data = NULL;\n+\t\tfreez(c->data);\n \t\tget_thread_data()->base_cache_used -= c->size;\n \t}\n }\n@@ -605,8 +604,7 @@ static void *unpack_data(struct object_entry *obj,\n \tgit_inflate_end(&stream);\n \tfree(inbuf);\n \tif (consume) {\n-\t\tfree(data);\n-\t\tdata = NULL;\n+\t\tfreez(data);\n \t}\n \treturn data;\n }\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex f672225def..fb43c1b101 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -264,8 +264,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent\n \t\t * make sure no cached delta data remains from a\n \t\t * previous attempt before a pack split occurred.\n \t\t */\n-\t\tfree(entry->delta_data);\n-\t\tentry->delta_data = NULL;\n+\t\tfreez(entry->delta_data);\n \t\tentry->z_delta_size = 0;\n \t} else if (entry->delta_data) {\n \t\tsize = entry->delta_size;\n@@ -1375,12 +1374,10 @@ static void cleanup_preferred_base(void)\n \t\tif (!pbase_tree_cache[i])\n \t\t\tcontinue;\n \t\tfree(pbase_tree_cache[i]->tree_data);\n-\t\tfree(pbase_tree_cache[i]);\n-\t\tpbase_tree_cache[i] = NULL;\n+\t\tfreez(pbase_tree_cache[i]);\n \t}\n \n-\tfree(done_pbase_paths);\n-\tdone_pbase_paths = NULL;\n+\tfreez(done_pbase_paths);\n \tdone_pbase_paths_num = done_pbase_paths_alloc = 0;\n }\n \n@@ -1970,8 +1967,7 @@ static unsigned long free_unpacked(struct unpacked *n)\n \tn->index = NULL;\n \tif (n->data) {\n \t\tfreed_mem += n->entry->size;\n-\t\tfree(n->data);\n-\t\tn->data = NULL;\n+\t\tfreez(n->data);\n \t}\n \tn->entry = NULL;\n \tn->depth = 0;\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 8bc9997767..236ee6ebfc 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -112,8 +112,7 @@ static void *get_data(unsigned long size)\n \t\t\tbreak;\n \t\tif (ret != Z_OK) {\n \t\t\terror(\"inflate returned %d\", ret);\n-\t\t\tfree(buf);\n-\t\t\tbuf = NULL;\n+\t\t\tfreez(buf);\n \t\t\tif (!recover)\n \t\t\t\texit(1);\n \t\t\thas_errors = 1;\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 793306ea51..dffed4666e 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -299,10 +299,8 @@ static int add_worktree(const char *path, const char *refname,\n \t}\n \n \tis_junk = 0;\n-\tfree(junk_work_tree);\n-\tfree(junk_git_dir);\n-\tjunk_work_tree = NULL;\n-\tjunk_git_dir = NULL;\n+\tfreez(junk_work_tree);\n+\tfreez(junk_git_dir);\n \n done:\n \tif (ret || !opts->keep_locked) {\ndiff --git a/commit-slab.h b/commit-slab.h\nindex 42d16dcded..ffa2a30f53 100644\n--- a/commit-slab.h\n+++ b/commit-slab.h\n@@ -82,8 +82,7 @@ static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s)\t\t\\\n \tfor (i = 0; i < s->slab_count; i++)\t\t\t\t\\\n \t\tfree(s->slab[i]);\t\t\t\t\t\\\n \ts->slab_count = 0;\t\t\t\t\t\t\\\n-\tfree(s->slab);\t\t\t\t\t\t\t\\\n-\ts->slab = NULL;\t\t\t\t\t\t\t\\\n+\tfreez(s->slab);\t\t\t\t\t\t\t\\\n }\t\t\t\t\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s,\t\\\ndiff --git a/commit.c b/commit.c\nindex 713f09feb0..851f1f3516 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -287,8 +287,7 @@ void free_commit_buffer(struct commit *commit)\n {\n \tstruct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);\n \tif (v) {\n-\t\tfree(v->buffer);\n-\t\tv->buffer = NULL;\n+\t\tfreez(v->buffer);\n \t\tv->size = 0;\n \t}\n }\ndiff --git a/config.c b/config.c\nindex 146cb3452a..9ab9260e0f 100644\n--- a/config.c\n+++ b/config.c\n@@ -395,8 +395,7 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \n out_free_ret_1:\n \tif (store_key) {\n-\t\tfree(*store_key);\n-\t\t*store_key = NULL;\n+\t\tfreez(*store_key);\n \t}\n \treturn -CONFIG_INVALID_KEY;\n }\ndiff --git a/credential.c b/credential.c\nindex aa996669fc..120fb996cb 100644\n--- a/credential.c\n+++ b/credential.c\n@@ -93,8 +93,7 @@ static void credential_apply_config(struct credential *c)\n \tc->configured = 1;\n \n \tif (!c->use_http_path && proto_is_http(c->protocol)) {\n-\t\tfree(c->path);\n-\t\tc->path = NULL;\n+\t\tfreez(c->path);\n \t}\n }\n \n@@ -314,10 +313,8 @@ void credential_reject(struct credential *c)\n \tfor (i = 0; i < c->helpers.nr; i++)\n \t\tcredential_do(c, c->helpers.items[i].string, \"erase\");\n \n-\tfree(c->username);\n-\tc->username = NULL;\n-\tfree(c->password);\n-\tc->password = NULL;\n+\tfreez(c->username);\n+\tfreez(c->password);\n \tc->approved = 0;\n }\n \ndiff --git a/diff-lib.c b/diff-lib.c\nindex 2982bf055a..d275c2469f 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -179,8 +179,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\t\tfree(dpath);\n \t\t\t\tcontinue;\n \t\t\t}\n-\t\t\tfree(dpath);\n-\t\t\tdpath = NULL;\n+\t\t\tfreez(dpath);\n \n \t\t\t/*\n \t\t\t * Show the diff for the 'ce' if we found the one\ndiff --git a/diff.c b/diff.c\nindex 5275c4b780..8ae4a6325c 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1218,8 +1218,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)\n \t\t\tregfree(ecbdata->diff_words->word_regex);\n \t\t\tfree(ecbdata->diff_words->word_regex);\n \t\t}\n-\t\tfree(ecbdata->diff_words);\n-\t\tecbdata->diff_words = NULL;\n+\t\tfreez(ecbdata->diff_words);\n \t}\n }\n \n@@ -2951,8 +2950,7 @@ void diff_free_filespec_blob(struct diff_filespec *s)\n void diff_free_filespec_data(struct diff_filespec *s)\n {\n \tdiff_free_filespec_blob(s);\n-\tfree(s->cnt_data);\n-\ts->cnt_data = NULL;\n+\tfreez(s->cnt_data);\n }\n \n static void prep_temp_blob(const char *path, struct diff_tempfile *temp,\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex f7444c86bd..99aab63c85 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -667,11 +667,9 @@ void diffcore_rename(struct diff_options *options)\n \tfor (i = 0; i < rename_dst_nr; i++)\n \t\tfree_filespec(rename_dst[i].two);\n \n-\tfree(rename_dst);\n-\trename_dst = NULL;\n+\tfreez(rename_dst);\n \trename_dst_nr = rename_dst_alloc = 0;\n-\tfree(rename_src);\n-\trename_src = NULL;\n+\tfreez(rename_src);\n \trename_src_nr = rename_src_alloc = 0;\n \treturn;\n }\ndiff --git a/dir.c b/dir.c\nindex 9efcf1eab6..441f98095a 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2117,8 +2117,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,\n \t\tfor (i = j = 0; j < dir->nr; j++) {\n \t\t\tif (i &&\n \t\t\t    check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) {\n-\t\t\t\tfree(dir->entries[j]);\n-\t\t\t\tdir->entries[j] = NULL;\n+\t\t\t\tfreez(dir->entries[j]);\n \t\t\t} else {\n \t\t\t\tdir->entries[i++] = dir->entries[j];\n \t\t\t}\n@@ -2144,8 +2143,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,\n \t\t     dir->untracked->dir_invalidated))\n \t\t\tistate->cache_changed |= UNTRACKED_CHANGED;\n \t\tif (dir->untracked != istate->untracked) {\n-\t\t\tfree(dir->untracked);\n-\t\t\tdir->untracked = NULL;\n+\t\t\tfreez(dir->untracked);\n \t\t}\n \t}\n \treturn dir->nr;\n@@ -2488,8 +2486,7 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra\n \tstrbuf_addbuf(out, &untracked->ident);\n \n \tstrbuf_add(out, ouc, ouc_size(len));\n-\tfree(ouc);\n-\touc = NULL;\n+\tfreez(ouc);\n \n \tif (!untracked->root) {\n \t\tvarint_len = encode_varint(0, varbuf);\ndiff --git a/fast-import.c b/fast-import.c\nindex e69d219682..9d8f91eebd 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1063,8 +1063,7 @@ static void end_packfile(void)\n \t\tclose(pack_data->pack_fd);\n \t\tunlink_or_warn(pack_data->pack_name);\n \t}\n-\tfree(pack_data);\n-\tpack_data = NULL;\n+\tfreez(pack_data);\n \trunning = 0;\n \n \t/* We can't carry a delta across packfiles. */\n@@ -1149,8 +1148,7 @@ static int store_object(\n \n \t\t/* We cannot carry a delta into the new pack. */\n \t\tif (delta) {\n-\t\t\tfree(delta);\n-\t\t\tdelta = NULL;\n+\t\t\tfreez(delta);\n \n \t\t\tgit_deflate_init(&s, pack_compression_level);\n \t\t\ts.next_in = (void *)dat->buf;\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex e44cc27da1..0baca17293 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -13,16 +13,11 @@ static const char *gpg_program = \"gpg\";\n \n void signature_check_clear(struct signature_check *sigc)\n {\n-\tfree(sigc->payload);\n-\tfree(sigc->gpg_output);\n-\tfree(sigc->gpg_status);\n-\tfree(sigc->signer);\n-\tfree(sigc->key);\n-\tsigc->payload = NULL;\n-\tsigc->gpg_output = NULL;\n-\tsigc->gpg_status = NULL;\n-\tsigc->signer = NULL;\n-\tsigc->key = NULL;\n+\tfreez(sigc->payload);\n+\tfreez(sigc->gpg_output);\n+\tfreez(sigc->gpg_status);\n+\tfreez(sigc->signer);\n+\tfreez(sigc->key);\n }\n \n static struct {\ndiff --git a/grep.c b/grep.c\nindex d03d424e5c..c74c5a8270 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1763,12 +1763,9 @@ void grep_source_init(struct grep_source *gs, enum grep_source_type type,\n \n void grep_source_clear(struct grep_source *gs)\n {\n-\tfree(gs->name);\n-\tgs->name = NULL;\n-\tfree(gs->path);\n-\tgs->path = NULL;\n-\tfree(gs->identifier);\n-\tgs->identifier = NULL;\n+\tfreez(gs->name);\n+\tfreez(gs->path);\n+\tfreez(gs->identifier);\n \tgrep_source_clear_data(gs);\n }\n \n@@ -1778,8 +1775,7 @@ void grep_source_clear_data(struct grep_source *gs)\n \tcase GREP_SOURCE_FILE:\n \tcase GREP_SOURCE_SHA1:\n \tcase GREP_SOURCE_SUBMODULE:\n-\t\tfree(gs->buf);\n-\t\tgs->buf = NULL;\n+\t\tfreez(gs->buf);\n \t\tgs->size = 0;\n \t\tbreak;\n \tcase GREP_SOURCE_BUF:\ndiff --git a/help.c b/help.c\nindex db7f3d79a0..6783bb9b4b 100644\n--- a/help.c\n+++ b/help.c\n@@ -267,9 +267,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n \n \tfor (i = 0; i < old->cnt; i++)\n \t\tcmds->names[cmds->cnt++] = old->names[i];\n-\tfree(old->names);\n+\tfreez(old->names);\n \told->cnt = 0;\n-\told->names = NULL;\n }\n \n /* An empirically derived magic number */\ndiff --git a/http-push.c b/http-push.c\nindex 67c4d4b472..89ae33464f 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -291,8 +291,7 @@ static void start_mkcol(struct transfer_request *request)\n \t\trequest->state = RUN_MKCOL;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tfreez(request->url);\n \t}\n }\n #endif\n@@ -409,8 +408,7 @@ static void start_put(struct transfer_request *request)\n \t\trequest->state = RUN_PUT;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tfreez(request->url);\n \t}\n }\n \n@@ -432,8 +430,7 @@ static void start_move(struct transfer_request *request)\n \t\trequest->state = RUN_MOVE;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tfreez(request->url);\n \t}\n }\n \n@@ -526,8 +523,7 @@ static void finish_request(struct transfer_request *request)\n \n \t/* URL is reused for MOVE after PUT */\n \tif (request->state != RUN_PUT) {\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tfreez(request->url);\n \t}\n \n \tif (request->state == RUN_MKCOL) {\n@@ -803,8 +799,7 @@ xml_start_tag(void *userData, const char *name, const char **atts)\n \t}\n \txsnprintf(ctx->name + old_namelen, ctx->len - old_namelen, \".%s\", c);\n \n-\tfree(ctx->cdata);\n-\tctx->cdata = NULL;\n+\tfreez(ctx->cdata);\n \n \tctx->userFunc(ctx, 0);\n }\n@@ -932,8 +927,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)\n \t\tfree(lock->token);\n \t\tfree(lock->owner);\n \t\tfree(url);\n-\t\tfree(lock);\n-\t\tlock = NULL;\n+\t\tfreez(lock);\n \t} else {\n \t\tlock->url = url;\n \t\tlock->start_time = time(NULL);\n@@ -1105,8 +1099,7 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)\n \t\t\tls->dentry_flags |= IS_DIR;\n \t\t}\n \t} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {\n-\t\tfree(ls->dentry_name);\n-\t\tls->dentry_name = NULL;\n+\t\tfreez(ls->dentry_name);\n \t\tls->dentry_flags = 0;\n \t}\n }\n@@ -1547,8 +1540,7 @@ static void fetch_symref(const char *path, char **symref, struct object_id *oid)\n \t\t    curl_errorstr);\n \tfree(url);\n \n-\tfree(*symref);\n-\t*symref = NULL;\n+\tfreez(*symref);\n \toidclr(oid);\n \n \tif (buffer.len == 0)\ndiff --git a/http.c b/http.c\nindex d2e11ec6f0..28eeb0d5ba 100644\n--- a/http.c\n+++ b/http.c\n@@ -1026,8 +1026,7 @@ void http_cleanup(void)\n \n \tif (proxy_auth.password) {\n \t\tmemset(proxy_auth.password, 0, strlen(proxy_auth.password));\n-\t\tfree(proxy_auth.password);\n-\t\tproxy_auth.password = NULL;\n+\t\tfreez(proxy_auth.password);\n \t}\n \n \tfree((void *)curl_proxyuserpwd);\n@@ -1038,13 +1037,11 @@ void http_cleanup(void)\n \n \tif (cert_auth.password != NULL) {\n \t\tmemset(cert_auth.password, 0, strlen(cert_auth.password));\n-\t\tfree(cert_auth.password);\n-\t\tcert_auth.password = NULL;\n+\t\tfreez(cert_auth.password);\n \t}\n \tssl_cert_password_required = 0;\n \n-\tfree(cached_accept_language);\n-\tcached_accept_language = NULL;\n+\tfreez(cached_accept_language);\n }\n \n struct active_request_slot *get_active_slot(void)\n@@ -1896,8 +1893,7 @@ static char *fetch_pack_index(unsigned char *sha1, const char *base_url)\n \n \tif (http_get_file(url, tmp, NULL) != HTTP_OK) {\n \t\terror(\"Unable to get pack index %s\", url);\n-\t\tfree(tmp);\n-\t\ttmp = NULL;\n+\t\tfreez(tmp);\n \t}\n \n \tfree(url);\n@@ -2328,8 +2324,7 @@ void release_http_object_request(struct http_object_request *freq)\n \t\tfreq->localfile = -1;\n \t}\n \tif (freq->url != NULL) {\n-\t\tfree(freq->url);\n-\t\tfreq->url = NULL;\n+\t\tfreez(freq->url);\n \t}\n \tif (freq->slot != NULL) {\n \t\tfreq->slot->callback_func = NULL;\ndiff --git a/imap-send.c b/imap-send.c\nindex 857591660f..a96facf530 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -776,8 +776,7 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)\n \t\t\t       offsetof(struct imap_cmd, next));\n \t\t\tif (cmdp->cb.data) {\n \t\t\t\tn = socket_write(&imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen);\n-\t\t\t\tfree(cmdp->cb.data);\n-\t\t\t\tcmdp->cb.data = NULL;\n+\t\t\t\tfreez(cmdp->cb.data);\n \t\t\t\tif (n != (int)cmdp->cb.dlen)\n \t\t\t\t\treturn RESP_BAD;\n \t\t\t} else if (cmdp->cb.cont) {\ndiff --git a/line-log.c b/line-log.c\nindex b9087814b8..bc7efb91da 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -34,9 +34,8 @@ void range_set_init(struct range_set *rs, size_t prealloc)\n \n void range_set_release(struct range_set *rs)\n {\n-\tfree(rs->ranges);\n+\tfreez(rs->ranges);\n \trs->alloc = rs->nr = 0;\n-\trs->ranges = NULL;\n }\n \n /* dst must be uninitialized! */\n@@ -610,8 +609,7 @@ parse_lines(struct commit *commit, const char *prefix, struct string_list *args)\n \t\tline_log_data_insert(&ranges, full_name, begin, end);\n \n \t\tfree_filespec(spec);\n-\t\tfree(ends);\n-\t\tends = NULL;\n+\t\tfreez(ends);\n \t}\n \n \tfor (p = ranges; p; p = p->next)\ndiff --git a/ll-merge.c b/ll-merge.c\nindex ac0d4a5d78..279ac6319c 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -209,8 +209,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \tresult->size = st.st_size;\n \tresult->ptr = xmallocz(result->size);\n \tif (read_in_full(fd, result->ptr, result->size) != result->size) {\n-\t\tfree(result->ptr);\n-\t\tresult->ptr = NULL;\n+\t\tfreez(result->ptr);\n \t\tresult->size = 0;\n \t}\n  close_bad:\ndiff --git a/mailinfo.c b/mailinfo.c\nindex f92cb9f729..b26689b56d 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -919,8 +919,7 @@ static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n \t\tstrbuf_release(*(mi->content_top));\n-\t\tfree(*(mi->content_top));\n-\t\t*(mi->content_top) = NULL;\n+\t\tfreez(*(mi->content_top));\n \n \t\t/* technically won't happen as is_multipart_boundary()\n \t\t   will fail first.  But just in case..\ndiff --git a/object.c b/object.c\nindex 06ba3a11d8..2883d46a0d 100644\n--- a/object.c\n+++ b/object.c\n@@ -377,8 +377,7 @@ void object_array_clear(struct object_array *array)\n \tint i;\n \tfor (i = 0; i < array->nr; i++)\n \t\tobject_array_release_entry(&array->objects[i]);\n-\tfree(array->objects);\n-\tarray->objects = NULL;\n+\tfreez(array->objects);\n \tarray->nr = array->alloc = 0;\n }\n \ndiff --git a/pathspec.c b/pathspec.c\nindex 828405021f..1f8ff7f4a9 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -662,7 +662,6 @@ void clear_pathspec(struct pathspec *pathspec)\n \t\t\tattr_check_free(pathspec->items[i].attr_check);\n \t}\n \n-\tfree(pathspec->items);\n-\tpathspec->items = NULL;\n+\tfreez(pathspec->items);\n \tpathspec->nr = 0;\n }\ndiff --git a/prio-queue.c b/prio-queue.c\nindex fc3860fdcb..59211eb2e8 100644\n--- a/prio-queue.c\n+++ b/prio-queue.c\n@@ -27,10 +27,9 @@ void prio_queue_reverse(struct prio_queue *queue)\n \n void clear_prio_queue(struct prio_queue *queue)\n {\n-\tfree(queue->array);\n+\tfreez(queue->array);\n \tqueue->nr = 0;\n \tqueue->alloc = 0;\n-\tqueue->array = NULL;\n \tqueue->insertion_ctr = 0;\n }\n \ndiff --git a/read-cache.c b/read-cache.c\nindex bc156a133e..8434ef5577 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1888,8 +1888,7 @@ int discard_index(struct index_state *istate)\n \tfree_name_hash(istate);\n \tcache_tree_free(&(istate->cache_tree));\n \tistate->initialized = 0;\n-\tfree(istate->cache);\n-\tistate->cache = NULL;\n+\tfreez(istate->cache);\n \tistate->cache_alloc = 0;\n \tdiscard_split_index(istate);\n \tfree_untracked_cache(istate->untracked);\n@@ -2603,8 +2602,7 @@ void *read_blob_data_from_index(const struct index_state *istate,\n \n void stat_validity_clear(struct stat_validity *sv)\n {\n-\tfree(sv->sd);\n-\tsv->sd = NULL;\n+\tfreez(sv->sd);\n }\n \n int stat_validity_check(struct stat_validity *sv, const char *path)\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ab32bc9c31..5b05d93575 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1891,8 +1891,7 @@ void ref_array_clear(struct ref_array *array)\n \n \tfor (i = 0; i < array->nr; i++)\n \t\tfree_array_item(array->items[i]);\n-\tfree(array->items);\n-\tarray->items = NULL;\n+\tfreez(array->items);\n \tarray->nr = array->alloc = 0;\n }\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex d8b3f73147..dd90b090e8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2944,8 +2944,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,\n \t\t\t\t       head_oid.hash, &head_type);\n \n \tif (head_ref && !(head_type & REF_ISSYMREF)) {\n-\t\tfree(head_ref);\n-\t\thead_ref = NULL;\n+\t\tfreez(head_ref);\n \t}\n \n \t/*\ndiff --git a/refs/ref-cache.c b/refs/ref-cache.c\nindex af2fcb2c12..ab12e0dc9d 100644\n--- a/refs/ref-cache.c\n+++ b/refs/ref-cache.c\n@@ -82,9 +82,8 @@ static void clear_ref_dir(struct ref_dir *dir)\n \tint i;\n \tfor (i = 0; i < dir->nr; i++)\n \t\tfree_ref_entry(dir->entries[i]);\n-\tfree(dir->entries);\n+\tfreez(dir->entries);\n \tdir->sorted = dir->nr = dir->alloc = 0;\n-\tdir->entries = NULL;\n }\n \n struct ref_entry *create_dir_entry(struct ref_cache *cache,\ndiff --git a/remote-testsvn.c b/remote-testsvn.c\nindex f87bf851ba..9b893a5f09 100644\n--- a/remote-testsvn.c\n+++ b/remote-testsvn.c\n@@ -66,8 +66,7 @@ static char *read_ref_note(const unsigned char sha1[20])\n \telse if (!msglen || type != OBJ_BLOB) {\n \t\terror(\"Note contains unusable content. \"\n \t\t\t\"Is something else using this notes tree? %s\", notes_ref);\n-\t\tfree(msg);\n-\t\tmsg = NULL;\n+\t\tfreez(msg);\n \t}\n \tfree_notes(NULL);\n \treturn msg;\ndiff --git a/rerere.c b/rerere.c\nindex 3bd55caf3b..43b62e6135 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -39,9 +39,8 @@ static void free_rerere_dirs(void)\n \t\tfree(rerere_dir[i]->status);\n \t\tfree(rerere_dir[i]);\n \t}\n-\tfree(rerere_dir);\n+\tfreez(rerere_dir);\n \trerere_dir_nr = rerere_dir_alloc = 0;\n-\trerere_dir = NULL;\n }\n \n static void free_rerere_id(struct string_list_item *item)\ndiff --git a/sequencer.c b/sequencer.c\nindex 924fb1d0c3..e542b3bd79 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1211,8 +1211,7 @@ struct todo_list {\n static void todo_list_release(struct todo_list *todo_list)\n {\n \tstrbuf_release(&todo_list->buf);\n-\tfree(todo_list->items);\n-\ttodo_list->items = NULL;\n+\tfreez(todo_list->items);\n \ttodo_list->nr = todo_list->alloc = 0;\n }\n \ndiff --git a/sha1-array.c b/sha1-array.c\nindex 7d646ab5b8..c98506fd77 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -35,8 +35,7 @@ int oid_array_lookup(struct oid_array *array, const struct object_id *oid)\n \n void oid_array_clear(struct oid_array *array)\n {\n-\tfree(array->oid);\n-\tarray->oid = NULL;\n+\tfreez(array->oid);\n \tarray->nr = 0;\n \tarray->alloc = 0;\n \tarray->sorted = 0;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 59a4ed2ed3..a34d904012 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -610,8 +610,7 @@ char *compute_alternate_path(const char *path, struct strbuf *err)\n \n out:\n \tif (seen_error) {\n-\t\tfree(ref_git);\n-\t\tref_git = NULL;\n+\t\tfreez(ref_git);\n \t}\n \n \treturn ref_git;\ndiff --git a/split-index.c b/split-index.c\nindex 49bd197f71..87c197617a 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -174,10 +174,9 @@ void merge_base_index(struct index_state *istate)\n \n \tewah_free(si->delete_bitmap);\n \tewah_free(si->replace_bitmap);\n-\tfree(si->saved_cache);\n+\tfreez(si->saved_cache);\n \tsi->delete_bitmap  = NULL;\n \tsi->replace_bitmap = NULL;\n-\tsi->saved_cache\t   = NULL;\n \tsi->saved_cache_nr = 0;\n }\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex 36408046eb..a986589a14 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -242,8 +242,7 @@ static int disconnect_helper(struct transport *transport)\n \t\tclose(data->helper->out);\n \t\tfclose(data->out);\n \t\tres = finish_command(data->helper);\n-\t\tfree(data->helper);\n-\t\tdata->helper = NULL;\n+\t\tfreez(data->helper);\n \t}\n \treturn res;\n }\n@@ -711,43 +710,35 @@ static int push_update_ref_status(struct strbuf *buf,\n \n \t\tif (!strcmp(msg, \"no match\")) {\n \t\t\tstatus = REF_STATUS_NONE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tfreez(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"up to date\")) {\n \t\t\tstatus = REF_STATUS_UPTODATE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tfreez(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"non-fast forward\")) {\n \t\t\tstatus = REF_STATUS_REJECT_NONFASTFORWARD;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tfreez(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"already exists\")) {\n \t\t\tstatus = REF_STATUS_REJECT_ALREADY_EXISTS;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tfreez(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"fetch first\")) {\n \t\t\tstatus = REF_STATUS_REJECT_FETCH_FIRST;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tfreez(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"needs force\")) {\n \t\t\tstatus = REF_STATUS_REJECT_NEEDS_FORCE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tfreez(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"stale info\")) {\n \t\t\tstatus = REF_STATUS_REJECT_STALE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tfreez(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"forced update\")) {\n \t\t\tforced = 1;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tfreez(msg);\n \t\t}\n \t}\n \ndiff --git a/transport.c b/transport.c\nindex 9bfcf870f9..1023a2d281 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1145,8 +1145,7 @@ void transport_unlock_pack(struct transport *transport)\n {\n \tif (transport->pack_lockfile) {\n \t\tunlink_or_warn(transport->pack_lockfile);\n-\t\tfree(transport->pack_lockfile);\n-\t\ttransport->pack_lockfile = NULL;\n+\t\tfreez(transport->pack_lockfile);\n \t}\n }\n \ndiff --git a/tree-diff.c b/tree-diff.c\nindex e164e532b2..022745d4bd 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -140,8 +140,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,\n \t/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */\n \tp = last->next;\n \tif (p && (alloclen > (intptr_t)p->next)) {\n-\t\tfree(p);\n-\t\tp = NULL;\n+\t\tfreez(p);\n \t}\n \n \tif (!p) {\n@@ -559,8 +558,7 @@ struct combine_diff_path *diff_tree_paths(\n \t * (see path_appendnew() for details about why)\n \t */\n \tif (p->next) {\n-\t\tfree(p->next);\n-\t\tp->next = NULL;\n+\t\tfreez(p->next);\n \t}\n \n \treturn p;\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 6a42e402b0..9f162155fe 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -479,8 +479,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)\n \tfor (i = 0; i < n; i++)\n \t\tfree_extended_entry(tx + i);\n \tfree(tx);\n-\tfree(traverse_path);\n-\tinfo->traverse_path = NULL;\n+\tfreez(traverse_path);\n \tstrbuf_release(&base);\n \treturn error;\n }\ndiff --git a/tree.c b/tree.c\nindex 603b29ee80..c03caabc0f 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -226,8 +226,7 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \n void free_tree_buffer(struct tree *tree)\n {\n-\tfree(tree->buffer);\n-\ttree->buffer = NULL;\n+\tfreez(tree->buffer);\n \ttree->size = 0;\n \ttree->object.parsed = 0;\n }\n-- \n2.13.0.506.g27d5fe0cd\n\n"},{"id":"321820","messageId":"CAN0heSo_S+_dut8RgDzVxffPZOzSTLwahsKrn7KG8aLvnrPbAw@mail.gmail.com","threadId":"46082","inReplyTo":"20170609085346.19974-3-avarab@gmail.com","subject":"Re: [PATCH 2/2] *.[ch] refactoring: make use of the freez() wrapper","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2017-06-09T10:12:09Z","receivedAt":"2017-06-09T10:12:17Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On 9 June 2017 at 10:53, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> Replace occurrences of `free(p); p = NULL` with `freez(p)`. This\n> introduces no functional changes, but cuts the number of lines spent\n> on this cleanup in half.\n\nIt's even better than that. ;)\n\n>  48 files changed, 97 insertions(+), 197 deletions(-)\n\nThe difference is in builtin/am.c where some empty lines are removed\nin am_next(), so no need to be alarmed.\n\nThe macro would be dangerous with things like \"freez(ptr++)\" but I\ncouldn't find any such side-effects. In hindsight, I guess your commit\nmessage says as much since using \"ptr++\" for \"p\" would already be a\nbug.\n\nI have no idea whether this conflicts with other topics, or any\nopinion on the best strategy for doing the conversion (all-at-once or\n\"while we're here\").\n"},{"id":"321821","messageId":"CACBZZX7U2SO11VZ43duLco1BhgM_XDzNTtrjcknjhijRkaeuxw@mail.gmail.com","threadId":"46082","inReplyTo":"CAN0heSo_S+_dut8RgDzVxffPZOzSTLwahsKrn7KG8aLvnrPbAw@mail.gmail.com","subject":"Re: [PATCH 2/2] *.[ch] refactoring: make use of the freez() wrapper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-09T10:58:51Z","receivedAt":"2017-06-09T10:59:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Fri, Jun 9, 2017 at 12:12 PM, Martin Ågren <martin.agren@gmail.com> wrote:\n> On 9 June 2017 at 10:53, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>> Replace occurrences of `free(p); p = NULL` with `freez(p)`. This\n>> introduces no functional changes, but cuts the number of lines spent\n>> on this cleanup in half.\n>\n> It's even better than that. ;)\n>\n>>  48 files changed, 97 insertions(+), 197 deletions(-)\n>\n> The difference is in builtin/am.c where some empty lines are removed\n> in am_next(), so no need to be alarmed.\n>\n> The macro would be dangerous with things like \"freez(ptr++)\" but I\n> couldn't find any such side-effects. In hindsight, I guess your commit\n> message says as much since using \"ptr++\" for \"p\" would already be a\n> bug.\n\nYes, although perhaps we should call this FREEZ() or GIT_FREEZ()\ninstead of freez() to make it clear that it's a macro.\n\n> I have no idea whether this conflicts with other topics, or any\n> opinion on the best strategy for doing the conversion (all-at-once or\n> \"while we're here\").\n\nIt has no conflicts with pu, so that's something, and passes all tests\nwith & without that merge.\n"},{"id":"321824","messageId":"CAP8UFD0w34frARr4AjLQen0oXhFxu4B37e5JKz49oqn5MyxwhA@mail.gmail.com","threadId":"46082","inReplyTo":"20170609085346.19974-2-avarab@gmail.com","subject":"Re: [PATCH 1/2] git-compat-util: add a freez() wrapper around free(x); x = NULL","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-06-09T12:04:49Z","receivedAt":"2017-06-09T12:04:55Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Fri, Jun 9, 2017 at 10:53 AM, Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -787,6 +787,7 @@ extern char *xstrdup(const char *str);\n>  extern void *xmalloc(size_t size);\n>  extern void *xmallocz(size_t size);\n>  extern void *xmallocz_gently(size_t size);\n> +#define freez(p) do { if (p) { free(p); (p) = NULL; } } while (0)\n\nI think we already rely on free(NULL) working, see\nhttp://public-inbox.org/git/alpine.DEB.2.20.1608301948310.129229@virtualbox/\nfor example, so this could just be:\n\n#define freez(p) do { free(p); (p) = NULL; } while (0)\n\nand yeah FREEZ() would be even better than freez().\n"},{"id":"321832","messageId":"20170609144813.GA81269@google.com","threadId":"46082","inReplyTo":"CACBZZX7U2SO11VZ43duLco1BhgM_XDzNTtrjcknjhijRkaeuxw@mail.gmail.com","subject":"Re: [PATCH 2/2] *.[ch] refactoring: make use of the freez() wrapper","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-09T14:48:13Z","receivedAt":"2017-06-09T14:48:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/09, Ævar Arnfjörð Bjarmason wrote:\n> On Fri, Jun 9, 2017 at 12:12 PM, Martin Ågren <martin.agren@gmail.com> wrote:\n> > On 9 June 2017 at 10:53, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> >> Replace occurrences of `free(p); p = NULL` with `freez(p)`. This\n> >> introduces no functional changes, but cuts the number of lines spent\n> >> on this cleanup in half.\n> >\n> > It's even better than that. ;)\n> >\n> >>  48 files changed, 97 insertions(+), 197 deletions(-)\n> >\n> > The difference is in builtin/am.c where some empty lines are removed\n> > in am_next(), so no need to be alarmed.\n> >\n> > The macro would be dangerous with things like \"freez(ptr++)\" but I\n> > couldn't find any such side-effects. In hindsight, I guess your commit\n> > message says as much since using \"ptr++\" for \"p\" would already be a\n> > bug.\n\nIt also couldn't hurt to add a comment to the macro definition\nexplaining that side-effect operators would be broken.\n\n> \n> Yes, although perhaps we should call this FREEZ() or GIT_FREEZ()\n> instead of freez() to make it clear that it's a macro.\n> \n> > I have no idea whether this conflicts with other topics, or any\n> > opinion on the best strategy for doing the conversion (all-at-once or\n> > \"while we're here\").\n> \n> It has no conflicts with pu, so that's something, and passes all tests\n> with & without that merge.\n\n-- \nBrandon Williams\n"},{"id":"321833","messageId":"20170609145317.GB81269@google.com","threadId":"46082","inReplyTo":"20170609085346.19974-1-avarab@gmail.com","subject":"Re: [PATCH 0/2] Add a freez() wrapper","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-09T14:53:17Z","receivedAt":"2017-06-09T14:54:24Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/09, Ævar Arnfjörð Bjarmason wrote:\n> On Fri, Jun 9, 2017 at 1:40 AM, Brandon Williams <bmwill@google.com> wrote:\n> > Introduce the repository object 'struct repository' which can be used to\n> > hold all state pertaining to a git repository.\n> > [...]\n> > +static void repo_clear_env(struct repository *repo)\n> > +{\n> > +       free(repo->gitdir);\n> > +       repo->gitdir = NULL;\n> > +       free(repo->commondir);\n> > +       repo->commondir = NULL;\n> > +       free(repo->objectdir);\n> > +       repo->objectdir = NULL;\n> > +       free(repo->index_file);\n> > +       repo->index_file = NULL;\n> > +       free(repo->graft_file);\n> > +       repo->graft_file = NULL;\n> > +       free(repo->namespace);\n> > +       repo->namespace = NULL;\n> > +}\n> \n> When seeing this I wondered if it couldn't be less noisy as:\n\nOne of the other alternatives is using memset, but that's difficult to\nonly clear only a few fields.\n\n> \n> > +       freez(repo->gitdir);\n> > +       freez(repo->commondir);\n> > +       freez(repo->objectdir);\n> > +       freez(repo->index_file);\n> > +       freez(repo->graft_file);\n> > +       freez(repo->namespace);\n> \n> It's not a problem with your patch, but something I thought would be\n> nice to have in general, so here's a patch series to implement that.\n\nThis also could makes things a little less error prone.  Thanks!\n\n> \n> Ævar Arnfjörð Bjarmason (2):\n>   git-compat-util: add a freez() wrapper around free(x); x = NULL\n>   *.[ch] refactoring: make use of the freez() wrapper\n> \n>  alias.c                  |  6 ++----\n>  apply.c                  |  3 +--\n>  attr.c                   |  6 ++----\n>  blame.c                  |  3 +--\n>  branch.c                 |  3 +--\n>  builtin/am.c             | 18 +++++-------------\n>  builtin/clean.c          |  6 ++----\n>  builtin/config.c         |  6 ++----\n>  builtin/index-pack.c     |  6 ++----\n>  builtin/pack-objects.c   | 12 ++++--------\n>  builtin/unpack-objects.c |  3 +--\n>  builtin/worktree.c       |  6 ++----\n>  commit-slab.h            |  3 +--\n>  commit.c                 |  3 +--\n>  config.c                 |  3 +--\n>  credential.c             |  9 +++------\n>  diff-lib.c               |  3 +--\n>  diff.c                   |  6 ++----\n>  diffcore-rename.c        |  6 ++----\n>  dir.c                    |  9 +++------\n>  fast-import.c            |  6 ++----\n>  git-compat-util.h        |  1 +\n>  gpg-interface.c          | 15 +++++----------\n>  grep.c                   | 12 ++++--------\n>  help.c                   |  3 +--\n>  http-push.c              | 24 ++++++++----------------\n>  http.c                   | 15 +++++----------\n>  imap-send.c              |  3 +--\n>  line-log.c               |  6 ++----\n>  ll-merge.c               |  3 +--\n>  mailinfo.c               |  3 +--\n>  object.c                 |  3 +--\n>  pathspec.c               |  3 +--\n>  prio-queue.c             |  3 +--\n>  read-cache.c             |  6 ++----\n>  ref-filter.c             |  3 +--\n>  refs/files-backend.c     |  3 +--\n>  refs/ref-cache.c         |  3 +--\n>  remote-testsvn.c         |  3 +--\n>  rerere.c                 |  3 +--\n>  sequencer.c              |  3 +--\n>  sha1-array.c             |  3 +--\n>  sha1_file.c              |  3 +--\n>  split-index.c            |  3 +--\n>  transport-helper.c       | 27 +++++++++------------------\n>  transport.c              |  3 +--\n>  tree-diff.c              |  6 ++----\n>  tree-walk.c              |  3 +--\n>  tree.c                   |  3 +--\n>  49 files changed, 98 insertions(+), 197 deletions(-)\n> \n> -- \n> 2.13.0.506.g27d5fe0cd\n> \n\n-- \nBrandon Williams\n"},{"id":"321856","messageId":"20170609220420.4910-1-avarab@gmail.com","threadId":"46082","inReplyTo":"20170609085346.19974-1-avarab@gmail.com","subject":"[PATCH v2 0/2] Add a FREEZ() wrapper macro","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-09T22:04:18Z","receivedAt":"2017-06-09T22:04:49Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"See <20170609085346.19974-1-avarab@gmail.com>\n(https://public-inbox.org/git/20170609085346.19974-1-avarab@gmail.com/)\nfor v1.\n\nChanges:\n\n * Now called FREEZ() instead of freez().\n * Documented the caveat of giving it ptr++ both in the commit message\n   and in a comment.\n * Moved the definition to be with other similar macros.\n * Just unconditionally call free(ptr), even if ptr is NULL, as we do\n   everywhere else.\n\nÆvar Arnfjörð Bjarmason (2):\n  git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL\n  *.[ch] refactoring: make use of the FREEZ() macro\n\n alias.c                  |  6 ++----\n apply.c                  |  3 +--\n attr.c                   |  6 ++----\n blame.c                  |  3 +--\n branch.c                 |  3 +--\n builtin/am.c             | 18 +++++-------------\n builtin/clean.c          |  6 ++----\n builtin/config.c         |  6 ++----\n builtin/index-pack.c     |  6 ++----\n builtin/pack-objects.c   | 12 ++++--------\n builtin/unpack-objects.c |  3 +--\n builtin/worktree.c       |  6 ++----\n commit-slab.h            |  3 +--\n commit.c                 |  3 +--\n config.c                 |  3 +--\n credential.c             |  9 +++------\n diff-lib.c               |  3 +--\n diff.c                   |  6 ++----\n diffcore-rename.c        |  6 ++----\n dir.c                    |  9 +++------\n fast-import.c            |  6 ++----\n git-compat-util.h        |  6 ++++++\n gpg-interface.c          | 15 +++++----------\n grep.c                   | 12 ++++--------\n help.c                   |  3 +--\n http-push.c              | 24 ++++++++----------------\n http.c                   | 15 +++++----------\n imap-send.c              |  3 +--\n line-log.c               |  6 ++----\n ll-merge.c               |  3 +--\n mailinfo.c               |  3 +--\n object.c                 |  3 +--\n pathspec.c               |  3 +--\n prio-queue.c             |  3 +--\n read-cache.c             |  6 ++----\n ref-filter.c             |  3 +--\n refs/files-backend.c     |  3 +--\n refs/ref-cache.c         |  3 +--\n remote-testsvn.c         |  3 +--\n rerere.c                 |  3 +--\n sequencer.c              |  3 +--\n sha1-array.c             |  3 +--\n sha1_file.c              |  3 +--\n split-index.c            |  3 +--\n transport-helper.c       | 27 +++++++++------------------\n transport.c              |  3 +--\n tree-diff.c              |  6 ++----\n tree-walk.c              |  3 +--\n tree.c                   |  3 +--\n 49 files changed, 103 insertions(+), 197 deletions(-)\n\n-- \n2.13.1.508.gb3defc5cc\n\n"},{"id":"321857","messageId":"20170609220420.4910-2-avarab@gmail.com","threadId":"46082","inReplyTo":"20170609220420.4910-1-avarab@gmail.com","subject":"[PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-09T22:04:19Z","receivedAt":"2017-06-09T22:04:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a FREEZ() wrapper marco for the common pattern of freeing a\npointer and assigning NULL to it right afterwards.\n\nThe implementation is similar to the (currently unused) XDL_PTRFREE\nmacro in xdiff/xmacros.h added in commit 3443546f6e (\"Use a *real*\nbuilt-in diff generator\", 2006-03-24). The only difference is that\nfree() is called unconditionally, see [1].\n\n1. <alpine.DEB.2.20.1608301948310.129229@virtualbox>\n   (http://public-inbox.org/git/alpine.DEB.2.20.1608301948310.129229@virtualbox/)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n git-compat-util.h | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 4b7dcf21ad..ba2d0c8c80 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -805,6 +805,12 @@ extern int xmkstemp_mode(char *template, int mode);\n extern char *xgetcwd(void);\n extern FILE *fopen_for_writing(const char *path);\n \n+/*\n+ * FREEZ(ptr) is like free(ptr) followed by ptr = NULL. Note that ptr\n+ * is used twice, so don't pass e.g. ptr++.\n+ */\n+#define FREEZ(p) do { free(p); (p) = NULL; } while (0)\n+\n #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))\n #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))\n \n-- \n2.13.1.508.gb3defc5cc\n\n"},{"id":"321858","messageId":"20170609220420.4910-3-avarab@gmail.com","threadId":"46082","inReplyTo":"20170609220420.4910-1-avarab@gmail.com","subject":"[PATCH v2 2/2] *.[ch] refactoring: make use of the FREEZ() macro","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-09T22:04:20Z","receivedAt":"2017-06-09T22:04:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Replace occurrences of `free(ptr); ptr = NULL` with `FREEZ(ptr)`. This\nintroduces no functional changes, but reduces the line count and\nestablishes this pattern as a common idiom with a wrapper macro.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n alias.c                  |  6 ++----\n apply.c                  |  3 +--\n attr.c                   |  6 ++----\n blame.c                  |  3 +--\n branch.c                 |  3 +--\n builtin/am.c             | 18 +++++-------------\n builtin/clean.c          |  6 ++----\n builtin/config.c         |  6 ++----\n builtin/index-pack.c     |  6 ++----\n builtin/pack-objects.c   | 12 ++++--------\n builtin/unpack-objects.c |  3 +--\n builtin/worktree.c       |  6 ++----\n commit-slab.h            |  3 +--\n commit.c                 |  3 +--\n config.c                 |  3 +--\n credential.c             |  9 +++------\n diff-lib.c               |  3 +--\n diff.c                   |  6 ++----\n diffcore-rename.c        |  6 ++----\n dir.c                    |  9 +++------\n fast-import.c            |  6 ++----\n gpg-interface.c          | 15 +++++----------\n grep.c                   | 12 ++++--------\n help.c                   |  3 +--\n http-push.c              | 24 ++++++++----------------\n http.c                   | 15 +++++----------\n imap-send.c              |  3 +--\n line-log.c               |  6 ++----\n ll-merge.c               |  3 +--\n mailinfo.c               |  3 +--\n object.c                 |  3 +--\n pathspec.c               |  3 +--\n prio-queue.c             |  3 +--\n read-cache.c             |  6 ++----\n ref-filter.c             |  3 +--\n refs/files-backend.c     |  3 +--\n refs/ref-cache.c         |  3 +--\n remote-testsvn.c         |  3 +--\n rerere.c                 |  3 +--\n sequencer.c              |  3 +--\n sha1-array.c             |  3 +--\n sha1_file.c              |  3 +--\n split-index.c            |  3 +--\n transport-helper.c       | 27 +++++++++------------------\n transport.c              |  3 +--\n tree-diff.c              |  6 ++----\n tree-walk.c              |  3 +--\n tree.c                   |  3 +--\n 48 files changed, 97 insertions(+), 197 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex 3b90397a99..a8cef09650 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -47,8 +47,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \t\t\t\tsrc++;\n \t\t\t\tc = cmdline[src];\n \t\t\t\tif (!c) {\n-\t\t\t\t\tfree(*argv);\n-\t\t\t\t\t*argv = NULL;\n+\t\t\t\t\tFREEZ(*argv);\n \t\t\t\t\treturn -SPLIT_CMDLINE_BAD_ENDING;\n \t\t\t\t}\n \t\t\t}\n@@ -60,8 +59,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \tcmdline[dst] = 0;\n \n \tif (quoted) {\n-\t\tfree(*argv);\n-\t\t*argv = NULL;\n+\t\tFREEZ(*argv);\n \t\treturn -SPLIT_CMDLINE_UNCLOSED_QUOTE;\n \t}\n \ndiff --git a/apply.c b/apply.c\nindex c49cef0637..f11330bbfe 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3705,8 +3705,7 @@ static int check_preimage(struct apply_state *state,\n  is_new:\n \tpatch->is_new = 1;\n \tpatch->is_delete = 0;\n-\tfree(patch->old_name);\n-\tpatch->old_name = NULL;\n+\tFREEZ(patch->old_name);\n \treturn 0;\n }\n \ndiff --git a/attr.c b/attr.c\nindex 7e2134471c..0b550695d5 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -638,13 +638,11 @@ void attr_check_reset(struct attr_check *check)\n \n void attr_check_clear(struct attr_check *check)\n {\n-\tfree(check->items);\n-\tcheck->items = NULL;\n+\tFREEZ(check->items);\n \tcheck->alloc = 0;\n \tcheck->nr = 0;\n \n-\tfree(check->all_attrs);\n-\tcheck->all_attrs = NULL;\n+\tFREEZ(check->all_attrs);\n \tcheck->all_attrs_nr = 0;\n \n \tdrop_attr_stack(&check->stack);\ndiff --git a/blame.c b/blame.c\nindex 843c845cba..5b2eac3915 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -314,8 +314,7 @@ static void fill_origin_blob(struct diff_options *opt,\n static void drop_origin_blob(struct blame_origin *o)\n {\n \tif (o->file.ptr) {\n-\t\tfree(o->file.ptr);\n-\t\to->file.ptr = NULL;\n+\t\tFREEZ(o->file.ptr);\n \t}\n }\n \ndiff --git a/branch.c b/branch.c\nindex 985316eb76..b2fce80706 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -24,8 +24,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)\n \t\t} else {\n \t\t\tfree(tracking->spec.src);\n \t\t\tif (tracking->src) {\n-\t\t\t\tfree(tracking->src);\n-\t\t\t\ttracking->src = NULL;\n+\t\t\t\tFREEZ(tracking->src);\n \t\t\t}\n \t\t}\n \t\ttracking->spec.src = NULL;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5ee146bfb3..f665239dc3 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -483,8 +483,7 @@ static int run_applypatch_msg_hook(struct am_state *state)\n \tret = run_hook_le(NULL, \"applypatch-msg\", am_path(state, \"final-commit\"), NULL);\n \n \tif (!ret) {\n-\t\tfree(state->msg);\n-\t\tstate->msg = NULL;\n+\t\tFREEZ(state->msg);\n \t\tif (read_commit_msg(state) < 0)\n \t\t\tdie(_(\"'%s' was deleted by the applypatch-msg hook\"),\n \t\t\t\tam_path(state, \"final-commit\"));\n@@ -1073,17 +1072,10 @@ static void am_next(struct am_state *state)\n {\n \tstruct object_id head;\n \n-\tfree(state->author_name);\n-\tstate->author_name = NULL;\n-\n-\tfree(state->author_email);\n-\tstate->author_email = NULL;\n-\n-\tfree(state->author_date);\n-\tstate->author_date = NULL;\n-\n-\tfree(state->msg);\n-\tstate->msg = NULL;\n+\tFREEZ(state->author_name);\n+\tFREEZ(state->author_email);\n+\tFREEZ(state->author_date);\n+\tFREEZ(state->msg);\n \tstate->msg_len = 0;\n \n \tunlink(am_path(state, \"author-script\"));\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 142bf668cf..027ce46505 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -837,8 +837,7 @@ static void interactive_main_loop(void)\n \t\t\tint ret;\n \t\t\tret = menus[*chosen].fn();\n \t\t\tif (ret != MENU_RETURN_NO_LOOP) {\n-\t\t\t\tfree(chosen);\n-\t\t\t\tchosen = NULL;\n+\t\t\t\tFREEZ(chosen);\n \t\t\t\tif (!del_list.nr) {\n \t\t\t\t\tclean_print_color(CLEAN_COLOR_ERROR);\n \t\t\t\t\tprintf_ln(_(\"No more files to clean, exiting.\"));\n@@ -851,8 +850,7 @@ static void interactive_main_loop(void)\n \t\t\tquit_cmd();\n \t\t}\n \n-\t\tfree(chosen);\n-\t\tchosen = NULL;\n+\t\tFREEZ(chosen);\n \t\tbreak;\n \t}\n }\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 7f6c25d4d9..f2b698971c 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -214,8 +214,7 @@ static int get_value(const char *key_, const char *regex_)\n \t\tkey_regexp = (regex_t*)xmalloc(sizeof(regex_t));\n \t\tif (regcomp(key_regexp, key, REG_EXTENDED)) {\n \t\t\terror(\"invalid key pattern: %s\", key_);\n-\t\t\tfree(key_regexp);\n-\t\t\tkey_regexp = NULL;\n+\t\t\tFREEZ(key_regexp);\n \t\t\tret = CONFIG_INVALID_PATTERN;\n \t\t\tgoto free_strings;\n \t\t}\n@@ -235,8 +234,7 @@ static int get_value(const char *key_, const char *regex_)\n \t\tregexp = (regex_t*)xmalloc(sizeof(regex_t));\n \t\tif (regcomp(regexp, regex_, REG_EXTENDED)) {\n \t\t\terror(\"invalid pattern: %s\", regex_);\n-\t\t\tfree(regexp);\n-\t\t\tregexp = NULL;\n+\t\t\tFREEZ(regexp);\n \t\t\tret = CONFIG_INVALID_PATTERN;\n \t\t\tgoto free_strings;\n \t\t}\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 04b9dcaf0f..17c86168fb 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -388,8 +388,7 @@ static struct base_data *alloc_base_data(void)\n static void free_base_data(struct base_data *c)\n {\n \tif (c->data) {\n-\t\tfree(c->data);\n-\t\tc->data = NULL;\n+\t\tFREEZ(c->data);\n \t\tget_thread_data()->base_cache_used -= c->size;\n \t}\n }\n@@ -605,8 +604,7 @@ static void *unpack_data(struct object_entry *obj,\n \tgit_inflate_end(&stream);\n \tfree(inbuf);\n \tif (consume) {\n-\t\tfree(data);\n-\t\tdata = NULL;\n+\t\tFREEZ(data);\n \t}\n \treturn data;\n }\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex f672225def..451079b2f2 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -264,8 +264,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent\n \t\t * make sure no cached delta data remains from a\n \t\t * previous attempt before a pack split occurred.\n \t\t */\n-\t\tfree(entry->delta_data);\n-\t\tentry->delta_data = NULL;\n+\t\tFREEZ(entry->delta_data);\n \t\tentry->z_delta_size = 0;\n \t} else if (entry->delta_data) {\n \t\tsize = entry->delta_size;\n@@ -1375,12 +1374,10 @@ static void cleanup_preferred_base(void)\n \t\tif (!pbase_tree_cache[i])\n \t\t\tcontinue;\n \t\tfree(pbase_tree_cache[i]->tree_data);\n-\t\tfree(pbase_tree_cache[i]);\n-\t\tpbase_tree_cache[i] = NULL;\n+\t\tFREEZ(pbase_tree_cache[i]);\n \t}\n \n-\tfree(done_pbase_paths);\n-\tdone_pbase_paths = NULL;\n+\tFREEZ(done_pbase_paths);\n \tdone_pbase_paths_num = done_pbase_paths_alloc = 0;\n }\n \n@@ -1970,8 +1967,7 @@ static unsigned long free_unpacked(struct unpacked *n)\n \tn->index = NULL;\n \tif (n->data) {\n \t\tfreed_mem += n->entry->size;\n-\t\tfree(n->data);\n-\t\tn->data = NULL;\n+\t\tFREEZ(n->data);\n \t}\n \tn->entry = NULL;\n \tn->depth = 0;\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 8bc9997767..402232dc4d 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -112,8 +112,7 @@ static void *get_data(unsigned long size)\n \t\t\tbreak;\n \t\tif (ret != Z_OK) {\n \t\t\terror(\"inflate returned %d\", ret);\n-\t\t\tfree(buf);\n-\t\t\tbuf = NULL;\n+\t\t\tFREEZ(buf);\n \t\t\tif (!recover)\n \t\t\t\texit(1);\n \t\t\thas_errors = 1;\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 793306ea51..2371fef396 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -299,10 +299,8 @@ static int add_worktree(const char *path, const char *refname,\n \t}\n \n \tis_junk = 0;\n-\tfree(junk_work_tree);\n-\tfree(junk_git_dir);\n-\tjunk_work_tree = NULL;\n-\tjunk_git_dir = NULL;\n+\tFREEZ(junk_work_tree);\n+\tFREEZ(junk_git_dir);\n \n done:\n \tif (ret || !opts->keep_locked) {\ndiff --git a/commit-slab.h b/commit-slab.h\nindex 42d16dcded..a239112360 100644\n--- a/commit-slab.h\n+++ b/commit-slab.h\n@@ -82,8 +82,7 @@ static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s)\t\t\\\n \tfor (i = 0; i < s->slab_count; i++)\t\t\t\t\\\n \t\tfree(s->slab[i]);\t\t\t\t\t\\\n \ts->slab_count = 0;\t\t\t\t\t\t\\\n-\tfree(s->slab);\t\t\t\t\t\t\t\\\n-\ts->slab = NULL;\t\t\t\t\t\t\t\\\n+\tFREEZ(s->slab);\t\t\t\t\t\t\t\\\n }\t\t\t\t\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s,\t\\\ndiff --git a/commit.c b/commit.c\nindex 713f09feb0..82c80fdd5e 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -287,8 +287,7 @@ void free_commit_buffer(struct commit *commit)\n {\n \tstruct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);\n \tif (v) {\n-\t\tfree(v->buffer);\n-\t\tv->buffer = NULL;\n+\t\tFREEZ(v->buffer);\n \t\tv->size = 0;\n \t}\n }\ndiff --git a/config.c b/config.c\nindex 146cb3452a..fa366d1c18 100644\n--- a/config.c\n+++ b/config.c\n@@ -395,8 +395,7 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \n out_free_ret_1:\n \tif (store_key) {\n-\t\tfree(*store_key);\n-\t\t*store_key = NULL;\n+\t\tFREEZ(*store_key);\n \t}\n \treturn -CONFIG_INVALID_KEY;\n }\ndiff --git a/credential.c b/credential.c\nindex aa996669fc..73650483b6 100644\n--- a/credential.c\n+++ b/credential.c\n@@ -93,8 +93,7 @@ static void credential_apply_config(struct credential *c)\n \tc->configured = 1;\n \n \tif (!c->use_http_path && proto_is_http(c->protocol)) {\n-\t\tfree(c->path);\n-\t\tc->path = NULL;\n+\t\tFREEZ(c->path);\n \t}\n }\n \n@@ -314,10 +313,8 @@ void credential_reject(struct credential *c)\n \tfor (i = 0; i < c->helpers.nr; i++)\n \t\tcredential_do(c, c->helpers.items[i].string, \"erase\");\n \n-\tfree(c->username);\n-\tc->username = NULL;\n-\tfree(c->password);\n-\tc->password = NULL;\n+\tFREEZ(c->username);\n+\tFREEZ(c->password);\n \tc->approved = 0;\n }\n \ndiff --git a/diff-lib.c b/diff-lib.c\nindex 2982bf055a..1130a9c9d9 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -179,8 +179,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\t\tfree(dpath);\n \t\t\t\tcontinue;\n \t\t\t}\n-\t\t\tfree(dpath);\n-\t\t\tdpath = NULL;\n+\t\t\tFREEZ(dpath);\n \n \t\t\t/*\n \t\t\t * Show the diff for the 'ce' if we found the one\ndiff --git a/diff.c b/diff.c\nindex 5275c4b780..db9282d731 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1218,8 +1218,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)\n \t\t\tregfree(ecbdata->diff_words->word_regex);\n \t\t\tfree(ecbdata->diff_words->word_regex);\n \t\t}\n-\t\tfree(ecbdata->diff_words);\n-\t\tecbdata->diff_words = NULL;\n+\t\tFREEZ(ecbdata->diff_words);\n \t}\n }\n \n@@ -2951,8 +2950,7 @@ void diff_free_filespec_blob(struct diff_filespec *s)\n void diff_free_filespec_data(struct diff_filespec *s)\n {\n \tdiff_free_filespec_blob(s);\n-\tfree(s->cnt_data);\n-\ts->cnt_data = NULL;\n+\tFREEZ(s->cnt_data);\n }\n \n static void prep_temp_blob(const char *path, struct diff_tempfile *temp,\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex f7444c86bd..f9428082bc 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -667,11 +667,9 @@ void diffcore_rename(struct diff_options *options)\n \tfor (i = 0; i < rename_dst_nr; i++)\n \t\tfree_filespec(rename_dst[i].two);\n \n-\tfree(rename_dst);\n-\trename_dst = NULL;\n+\tFREEZ(rename_dst);\n \trename_dst_nr = rename_dst_alloc = 0;\n-\tfree(rename_src);\n-\trename_src = NULL;\n+\tFREEZ(rename_src);\n \trename_src_nr = rename_src_alloc = 0;\n \treturn;\n }\ndiff --git a/dir.c b/dir.c\nindex 9efcf1eab6..0d4e7e6bfa 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2117,8 +2117,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,\n \t\tfor (i = j = 0; j < dir->nr; j++) {\n \t\t\tif (i &&\n \t\t\t    check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) {\n-\t\t\t\tfree(dir->entries[j]);\n-\t\t\t\tdir->entries[j] = NULL;\n+\t\t\t\tFREEZ(dir->entries[j]);\n \t\t\t} else {\n \t\t\t\tdir->entries[i++] = dir->entries[j];\n \t\t\t}\n@@ -2144,8 +2143,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,\n \t\t     dir->untracked->dir_invalidated))\n \t\t\tistate->cache_changed |= UNTRACKED_CHANGED;\n \t\tif (dir->untracked != istate->untracked) {\n-\t\t\tfree(dir->untracked);\n-\t\t\tdir->untracked = NULL;\n+\t\t\tFREEZ(dir->untracked);\n \t\t}\n \t}\n \treturn dir->nr;\n@@ -2488,8 +2486,7 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra\n \tstrbuf_addbuf(out, &untracked->ident);\n \n \tstrbuf_add(out, ouc, ouc_size(len));\n-\tfree(ouc);\n-\touc = NULL;\n+\tFREEZ(ouc);\n \n \tif (!untracked->root) {\n \t\tvarint_len = encode_varint(0, varbuf);\ndiff --git a/fast-import.c b/fast-import.c\nindex e69d219682..4e23caeaad 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1063,8 +1063,7 @@ static void end_packfile(void)\n \t\tclose(pack_data->pack_fd);\n \t\tunlink_or_warn(pack_data->pack_name);\n \t}\n-\tfree(pack_data);\n-\tpack_data = NULL;\n+\tFREEZ(pack_data);\n \trunning = 0;\n \n \t/* We can't carry a delta across packfiles. */\n@@ -1149,8 +1148,7 @@ static int store_object(\n \n \t\t/* We cannot carry a delta into the new pack. */\n \t\tif (delta) {\n-\t\t\tfree(delta);\n-\t\t\tdelta = NULL;\n+\t\t\tFREEZ(delta);\n \n \t\t\tgit_deflate_init(&s, pack_compression_level);\n \t\t\ts.next_in = (void *)dat->buf;\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex e44cc27da1..93739787f9 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -13,16 +13,11 @@ static const char *gpg_program = \"gpg\";\n \n void signature_check_clear(struct signature_check *sigc)\n {\n-\tfree(sigc->payload);\n-\tfree(sigc->gpg_output);\n-\tfree(sigc->gpg_status);\n-\tfree(sigc->signer);\n-\tfree(sigc->key);\n-\tsigc->payload = NULL;\n-\tsigc->gpg_output = NULL;\n-\tsigc->gpg_status = NULL;\n-\tsigc->signer = NULL;\n-\tsigc->key = NULL;\n+\tFREEZ(sigc->payload);\n+\tFREEZ(sigc->gpg_output);\n+\tFREEZ(sigc->gpg_status);\n+\tFREEZ(sigc->signer);\n+\tFREEZ(sigc->key);\n }\n \n static struct {\ndiff --git a/grep.c b/grep.c\nindex d03d424e5c..2ec0f7800d 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1763,12 +1763,9 @@ void grep_source_init(struct grep_source *gs, enum grep_source_type type,\n \n void grep_source_clear(struct grep_source *gs)\n {\n-\tfree(gs->name);\n-\tgs->name = NULL;\n-\tfree(gs->path);\n-\tgs->path = NULL;\n-\tfree(gs->identifier);\n-\tgs->identifier = NULL;\n+\tFREEZ(gs->name);\n+\tFREEZ(gs->path);\n+\tFREEZ(gs->identifier);\n \tgrep_source_clear_data(gs);\n }\n \n@@ -1778,8 +1775,7 @@ void grep_source_clear_data(struct grep_source *gs)\n \tcase GREP_SOURCE_FILE:\n \tcase GREP_SOURCE_SHA1:\n \tcase GREP_SOURCE_SUBMODULE:\n-\t\tfree(gs->buf);\n-\t\tgs->buf = NULL;\n+\t\tFREEZ(gs->buf);\n \t\tgs->size = 0;\n \t\tbreak;\n \tcase GREP_SOURCE_BUF:\ndiff --git a/help.c b/help.c\nindex db7f3d79a0..90d1ff6a48 100644\n--- a/help.c\n+++ b/help.c\n@@ -267,9 +267,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n \n \tfor (i = 0; i < old->cnt; i++)\n \t\tcmds->names[cmds->cnt++] = old->names[i];\n-\tfree(old->names);\n+\tFREEZ(old->names);\n \told->cnt = 0;\n-\told->names = NULL;\n }\n \n /* An empirically derived magic number */\ndiff --git a/http-push.c b/http-push.c\nindex 67c4d4b472..eda9725f14 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -291,8 +291,7 @@ static void start_mkcol(struct transfer_request *request)\n \t\trequest->state = RUN_MKCOL;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tFREEZ(request->url);\n \t}\n }\n #endif\n@@ -409,8 +408,7 @@ static void start_put(struct transfer_request *request)\n \t\trequest->state = RUN_PUT;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tFREEZ(request->url);\n \t}\n }\n \n@@ -432,8 +430,7 @@ static void start_move(struct transfer_request *request)\n \t\trequest->state = RUN_MOVE;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tFREEZ(request->url);\n \t}\n }\n \n@@ -526,8 +523,7 @@ static void finish_request(struct transfer_request *request)\n \n \t/* URL is reused for MOVE after PUT */\n \tif (request->state != RUN_PUT) {\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tFREEZ(request->url);\n \t}\n \n \tif (request->state == RUN_MKCOL) {\n@@ -803,8 +799,7 @@ xml_start_tag(void *userData, const char *name, const char **atts)\n \t}\n \txsnprintf(ctx->name + old_namelen, ctx->len - old_namelen, \".%s\", c);\n \n-\tfree(ctx->cdata);\n-\tctx->cdata = NULL;\n+\tFREEZ(ctx->cdata);\n \n \tctx->userFunc(ctx, 0);\n }\n@@ -932,8 +927,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)\n \t\tfree(lock->token);\n \t\tfree(lock->owner);\n \t\tfree(url);\n-\t\tfree(lock);\n-\t\tlock = NULL;\n+\t\tFREEZ(lock);\n \t} else {\n \t\tlock->url = url;\n \t\tlock->start_time = time(NULL);\n@@ -1105,8 +1099,7 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)\n \t\t\tls->dentry_flags |= IS_DIR;\n \t\t}\n \t} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {\n-\t\tfree(ls->dentry_name);\n-\t\tls->dentry_name = NULL;\n+\t\tFREEZ(ls->dentry_name);\n \t\tls->dentry_flags = 0;\n \t}\n }\n@@ -1547,8 +1540,7 @@ static void fetch_symref(const char *path, char **symref, struct object_id *oid)\n \t\t    curl_errorstr);\n \tfree(url);\n \n-\tfree(*symref);\n-\t*symref = NULL;\n+\tFREEZ(*symref);\n \toidclr(oid);\n \n \tif (buffer.len == 0)\ndiff --git a/http.c b/http.c\nindex d2e11ec6f0..4ce761f9a0 100644\n--- a/http.c\n+++ b/http.c\n@@ -1026,8 +1026,7 @@ void http_cleanup(void)\n \n \tif (proxy_auth.password) {\n \t\tmemset(proxy_auth.password, 0, strlen(proxy_auth.password));\n-\t\tfree(proxy_auth.password);\n-\t\tproxy_auth.password = NULL;\n+\t\tFREEZ(proxy_auth.password);\n \t}\n \n \tfree((void *)curl_proxyuserpwd);\n@@ -1038,13 +1037,11 @@ void http_cleanup(void)\n \n \tif (cert_auth.password != NULL) {\n \t\tmemset(cert_auth.password, 0, strlen(cert_auth.password));\n-\t\tfree(cert_auth.password);\n-\t\tcert_auth.password = NULL;\n+\t\tFREEZ(cert_auth.password);\n \t}\n \tssl_cert_password_required = 0;\n \n-\tfree(cached_accept_language);\n-\tcached_accept_language = NULL;\n+\tFREEZ(cached_accept_language);\n }\n \n struct active_request_slot *get_active_slot(void)\n@@ -1896,8 +1893,7 @@ static char *fetch_pack_index(unsigned char *sha1, const char *base_url)\n \n \tif (http_get_file(url, tmp, NULL) != HTTP_OK) {\n \t\terror(\"Unable to get pack index %s\", url);\n-\t\tfree(tmp);\n-\t\ttmp = NULL;\n+\t\tFREEZ(tmp);\n \t}\n \n \tfree(url);\n@@ -2328,8 +2324,7 @@ void release_http_object_request(struct http_object_request *freq)\n \t\tfreq->localfile = -1;\n \t}\n \tif (freq->url != NULL) {\n-\t\tfree(freq->url);\n-\t\tfreq->url = NULL;\n+\t\tFREEZ(freq->url);\n \t}\n \tif (freq->slot != NULL) {\n \t\tfreq->slot->callback_func = NULL;\ndiff --git a/imap-send.c b/imap-send.c\nindex 857591660f..b4b29c30c8 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -776,8 +776,7 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)\n \t\t\t       offsetof(struct imap_cmd, next));\n \t\t\tif (cmdp->cb.data) {\n \t\t\t\tn = socket_write(&imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen);\n-\t\t\t\tfree(cmdp->cb.data);\n-\t\t\t\tcmdp->cb.data = NULL;\n+\t\t\t\tFREEZ(cmdp->cb.data);\n \t\t\t\tif (n != (int)cmdp->cb.dlen)\n \t\t\t\t\treturn RESP_BAD;\n \t\t\t} else if (cmdp->cb.cont) {\ndiff --git a/line-log.c b/line-log.c\nindex b9087814b8..272c853ede 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -34,9 +34,8 @@ void range_set_init(struct range_set *rs, size_t prealloc)\n \n void range_set_release(struct range_set *rs)\n {\n-\tfree(rs->ranges);\n+\tFREEZ(rs->ranges);\n \trs->alloc = rs->nr = 0;\n-\trs->ranges = NULL;\n }\n \n /* dst must be uninitialized! */\n@@ -610,8 +609,7 @@ parse_lines(struct commit *commit, const char *prefix, struct string_list *args)\n \t\tline_log_data_insert(&ranges, full_name, begin, end);\n \n \t\tfree_filespec(spec);\n-\t\tfree(ends);\n-\t\tends = NULL;\n+\t\tFREEZ(ends);\n \t}\n \n \tfor (p = ranges; p; p = p->next)\ndiff --git a/ll-merge.c b/ll-merge.c\nindex ac0d4a5d78..65067a6a1a 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -209,8 +209,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \tresult->size = st.st_size;\n \tresult->ptr = xmallocz(result->size);\n \tif (read_in_full(fd, result->ptr, result->size) != result->size) {\n-\t\tfree(result->ptr);\n-\t\tresult->ptr = NULL;\n+\t\tFREEZ(result->ptr);\n \t\tresult->size = 0;\n \t}\n  close_bad:\ndiff --git a/mailinfo.c b/mailinfo.c\nindex f92cb9f729..4531ccad58 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -919,8 +919,7 @@ static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n \t\tstrbuf_release(*(mi->content_top));\n-\t\tfree(*(mi->content_top));\n-\t\t*(mi->content_top) = NULL;\n+\t\tFREEZ(*(mi->content_top));\n \n \t\t/* technically won't happen as is_multipart_boundary()\n \t\t   will fail first.  But just in case..\ndiff --git a/object.c b/object.c\nindex 06ba3a11d8..156931f735 100644\n--- a/object.c\n+++ b/object.c\n@@ -377,8 +377,7 @@ void object_array_clear(struct object_array *array)\n \tint i;\n \tfor (i = 0; i < array->nr; i++)\n \t\tobject_array_release_entry(&array->objects[i]);\n-\tfree(array->objects);\n-\tarray->objects = NULL;\n+\tFREEZ(array->objects);\n \tarray->nr = array->alloc = 0;\n }\n \ndiff --git a/pathspec.c b/pathspec.c\nindex 828405021f..ff131a3c02 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -662,7 +662,6 @@ void clear_pathspec(struct pathspec *pathspec)\n \t\t\tattr_check_free(pathspec->items[i].attr_check);\n \t}\n \n-\tfree(pathspec->items);\n-\tpathspec->items = NULL;\n+\tFREEZ(pathspec->items);\n \tpathspec->nr = 0;\n }\ndiff --git a/prio-queue.c b/prio-queue.c\nindex fc3860fdcb..2c16240104 100644\n--- a/prio-queue.c\n+++ b/prio-queue.c\n@@ -27,10 +27,9 @@ void prio_queue_reverse(struct prio_queue *queue)\n \n void clear_prio_queue(struct prio_queue *queue)\n {\n-\tfree(queue->array);\n+\tFREEZ(queue->array);\n \tqueue->nr = 0;\n \tqueue->alloc = 0;\n-\tqueue->array = NULL;\n \tqueue->insertion_ctr = 0;\n }\n \ndiff --git a/read-cache.c b/read-cache.c\nindex bc156a133e..5d3447d618 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1888,8 +1888,7 @@ int discard_index(struct index_state *istate)\n \tfree_name_hash(istate);\n \tcache_tree_free(&(istate->cache_tree));\n \tistate->initialized = 0;\n-\tfree(istate->cache);\n-\tistate->cache = NULL;\n+\tFREEZ(istate->cache);\n \tistate->cache_alloc = 0;\n \tdiscard_split_index(istate);\n \tfree_untracked_cache(istate->untracked);\n@@ -2603,8 +2602,7 @@ void *read_blob_data_from_index(const struct index_state *istate,\n \n void stat_validity_clear(struct stat_validity *sv)\n {\n-\tfree(sv->sd);\n-\tsv->sd = NULL;\n+\tFREEZ(sv->sd);\n }\n \n int stat_validity_check(struct stat_validity *sv, const char *path)\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ab32bc9c31..c9ca76d0d9 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1891,8 +1891,7 @@ void ref_array_clear(struct ref_array *array)\n \n \tfor (i = 0; i < array->nr; i++)\n \t\tfree_array_item(array->items[i]);\n-\tfree(array->items);\n-\tarray->items = NULL;\n+\tFREEZ(array->items);\n \tarray->nr = array->alloc = 0;\n }\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex d8b3f73147..f088c7b9fa 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2944,8 +2944,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,\n \t\t\t\t       head_oid.hash, &head_type);\n \n \tif (head_ref && !(head_type & REF_ISSYMREF)) {\n-\t\tfree(head_ref);\n-\t\thead_ref = NULL;\n+\t\tFREEZ(head_ref);\n \t}\n \n \t/*\ndiff --git a/refs/ref-cache.c b/refs/ref-cache.c\nindex af2fcb2c12..2726d5fd77 100644\n--- a/refs/ref-cache.c\n+++ b/refs/ref-cache.c\n@@ -82,9 +82,8 @@ static void clear_ref_dir(struct ref_dir *dir)\n \tint i;\n \tfor (i = 0; i < dir->nr; i++)\n \t\tfree_ref_entry(dir->entries[i]);\n-\tfree(dir->entries);\n+\tFREEZ(dir->entries);\n \tdir->sorted = dir->nr = dir->alloc = 0;\n-\tdir->entries = NULL;\n }\n \n struct ref_entry *create_dir_entry(struct ref_cache *cache,\ndiff --git a/remote-testsvn.c b/remote-testsvn.c\nindex f87bf851ba..79bfb2a1b7 100644\n--- a/remote-testsvn.c\n+++ b/remote-testsvn.c\n@@ -66,8 +66,7 @@ static char *read_ref_note(const unsigned char sha1[20])\n \telse if (!msglen || type != OBJ_BLOB) {\n \t\terror(\"Note contains unusable content. \"\n \t\t\t\"Is something else using this notes tree? %s\", notes_ref);\n-\t\tfree(msg);\n-\t\tmsg = NULL;\n+\t\tFREEZ(msg);\n \t}\n \tfree_notes(NULL);\n \treturn msg;\ndiff --git a/rerere.c b/rerere.c\nindex 3bd55caf3b..7dbb29f224 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -39,9 +39,8 @@ static void free_rerere_dirs(void)\n \t\tfree(rerere_dir[i]->status);\n \t\tfree(rerere_dir[i]);\n \t}\n-\tfree(rerere_dir);\n+\tFREEZ(rerere_dir);\n \trerere_dir_nr = rerere_dir_alloc = 0;\n-\trerere_dir = NULL;\n }\n \n static void free_rerere_id(struct string_list_item *item)\ndiff --git a/sequencer.c b/sequencer.c\nindex 924fb1d0c3..c3f83e3a01 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1211,8 +1211,7 @@ struct todo_list {\n static void todo_list_release(struct todo_list *todo_list)\n {\n \tstrbuf_release(&todo_list->buf);\n-\tfree(todo_list->items);\n-\ttodo_list->items = NULL;\n+\tFREEZ(todo_list->items);\n \ttodo_list->nr = todo_list->alloc = 0;\n }\n \ndiff --git a/sha1-array.c b/sha1-array.c\nindex 7d646ab5b8..a683198cd7 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -35,8 +35,7 @@ int oid_array_lookup(struct oid_array *array, const struct object_id *oid)\n \n void oid_array_clear(struct oid_array *array)\n {\n-\tfree(array->oid);\n-\tarray->oid = NULL;\n+\tFREEZ(array->oid);\n \tarray->nr = 0;\n \tarray->alloc = 0;\n \tarray->sorted = 0;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 59a4ed2ed3..7758a34ff4 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -610,8 +610,7 @@ char *compute_alternate_path(const char *path, struct strbuf *err)\n \n out:\n \tif (seen_error) {\n-\t\tfree(ref_git);\n-\t\tref_git = NULL;\n+\t\tFREEZ(ref_git);\n \t}\n \n \treturn ref_git;\ndiff --git a/split-index.c b/split-index.c\nindex 49bd197f71..cbcb6eb63f 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -174,10 +174,9 @@ void merge_base_index(struct index_state *istate)\n \n \tewah_free(si->delete_bitmap);\n \tewah_free(si->replace_bitmap);\n-\tfree(si->saved_cache);\n+\tFREEZ(si->saved_cache);\n \tsi->delete_bitmap  = NULL;\n \tsi->replace_bitmap = NULL;\n-\tsi->saved_cache\t   = NULL;\n \tsi->saved_cache_nr = 0;\n }\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex 36408046eb..c20725777d 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -242,8 +242,7 @@ static int disconnect_helper(struct transport *transport)\n \t\tclose(data->helper->out);\n \t\tfclose(data->out);\n \t\tres = finish_command(data->helper);\n-\t\tfree(data->helper);\n-\t\tdata->helper = NULL;\n+\t\tFREEZ(data->helper);\n \t}\n \treturn res;\n }\n@@ -711,43 +710,35 @@ static int push_update_ref_status(struct strbuf *buf,\n \n \t\tif (!strcmp(msg, \"no match\")) {\n \t\t\tstatus = REF_STATUS_NONE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREEZ(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"up to date\")) {\n \t\t\tstatus = REF_STATUS_UPTODATE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREEZ(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"non-fast forward\")) {\n \t\t\tstatus = REF_STATUS_REJECT_NONFASTFORWARD;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREEZ(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"already exists\")) {\n \t\t\tstatus = REF_STATUS_REJECT_ALREADY_EXISTS;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREEZ(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"fetch first\")) {\n \t\t\tstatus = REF_STATUS_REJECT_FETCH_FIRST;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREEZ(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"needs force\")) {\n \t\t\tstatus = REF_STATUS_REJECT_NEEDS_FORCE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREEZ(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"stale info\")) {\n \t\t\tstatus = REF_STATUS_REJECT_STALE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREEZ(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"forced update\")) {\n \t\t\tforced = 1;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREEZ(msg);\n \t\t}\n \t}\n \ndiff --git a/transport.c b/transport.c\nindex 9bfcf870f9..e0fd45f614 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1145,8 +1145,7 @@ void transport_unlock_pack(struct transport *transport)\n {\n \tif (transport->pack_lockfile) {\n \t\tunlink_or_warn(transport->pack_lockfile);\n-\t\tfree(transport->pack_lockfile);\n-\t\ttransport->pack_lockfile = NULL;\n+\t\tFREEZ(transport->pack_lockfile);\n \t}\n }\n \ndiff --git a/tree-diff.c b/tree-diff.c\nindex e164e532b2..36d7455aa4 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -140,8 +140,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,\n \t/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */\n \tp = last->next;\n \tif (p && (alloclen > (intptr_t)p->next)) {\n-\t\tfree(p);\n-\t\tp = NULL;\n+\t\tFREEZ(p);\n \t}\n \n \tif (!p) {\n@@ -559,8 +558,7 @@ struct combine_diff_path *diff_tree_paths(\n \t * (see path_appendnew() for details about why)\n \t */\n \tif (p->next) {\n-\t\tfree(p->next);\n-\t\tp->next = NULL;\n+\t\tFREEZ(p->next);\n \t}\n \n \treturn p;\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 6a42e402b0..26640e00fa 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -479,8 +479,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)\n \tfor (i = 0; i < n; i++)\n \t\tfree_extended_entry(tx + i);\n \tfree(tx);\n-\tfree(traverse_path);\n-\tinfo->traverse_path = NULL;\n+\tFREEZ(traverse_path);\n \tstrbuf_release(&base);\n \treturn error;\n }\ndiff --git a/tree.c b/tree.c\nindex 603b29ee80..1bf175d13d 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -226,8 +226,7 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \n void free_tree_buffer(struct tree *tree)\n {\n-\tfree(tree->buffer);\n-\ttree->buffer = NULL;\n+\tFREEZ(tree->buffer);\n \ttree->size = 0;\n \ttree->object.parsed = 0;\n }\n-- \n2.13.1.508.gb3defc5cc\n\n"},{"id":"321859","messageId":"20170609222738.GF21733@aiede.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170609220420.4910-2-avarab@gmail.com","subject":"Re: [PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-06-09T22:27:38Z","receivedAt":"2017-06-09T22:27:48Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nÆvar Arnfjörð Bjarmason wrote:\n\n> Add a FREEZ() wrapper marco for the common pattern of freeing a\n> pointer and assigning NULL to it right afterwards.\n\nI'm conflicted.  On one hand it makes code more concise and makes it\neasier for people to remember to assign NULL after freeing a variable.\nOn the other hand it makes git more of a custom dialect of C, which\nmay make the code harder to read and hack on for new contributors.\n\nMy feeling is that the costs outweigh the benefits, but I haven't\nthought it through thoroughly.\n\n> The implementation is similar to the (currently unused) XDL_PTRFREE\n> macro in xdiff/xmacros.h added in commit 3443546f6e (\"Use a *real*\n> built-in diff generator\", 2006-03-24). The only difference is that\n> free() is called unconditionally, see [1].\n>\n> 1. <alpine.DEB.2.20.1608301948310.129229@virtualbox>\n>    (http://public-inbox.org/git/alpine.DEB.2.20.1608301948310.129229@virtualbox/)\n\nNit: it's redundant to state the message-id twice.\n\nCan this commit message include a summary of that conversation so\nsomeone trying to understand this patch with \"git log\" does not have\nto open a browser and re-read the thread?  Is that thread being cited\nfor the point that git uses 'free(NULL)' without worrying?  I think\nthat's okay to say without citation --- there are lots of examples\nthroughout the git codebase.\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  git-compat-util.h | 6 ++++++\n>  1 file changed, 6 insertions(+)\n>\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 4b7dcf21ad..ba2d0c8c80 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -805,6 +805,12 @@ extern int xmkstemp_mode(char *template, int mode);\n>  extern char *xgetcwd(void);\n>  extern FILE *fopen_for_writing(const char *path);\n> \n> +/*\n> + * FREEZ(ptr) is like free(ptr) followed by ptr = NULL. Note that ptr\n> + * is used twice, so don't pass e.g. ptr++.\n> + */\n> +#define FREEZ(p) do { free(p); (p) = NULL; } while (0)\n> +\n>  #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))\n>  #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))\n\nGolfing: it's possible to do this without ptr being used twice by\nintroducing a helper function:\n\n\tstatic inline void freez_impl(void **p) {\n\t\tfree(*p);\n\t\t*p = NULL;\n\t}\n\t#define FREEZ(p) freez_impl(&(p))\n\nThat way side-effectful callers like FREEZ(func() ? a : b) would\nwork.\n\nAnother request: if rolling out another version of this series, could\nit go in a new thread?  The cover letter can link to the old version\nfor context.  Each time I see a new reply to the repository object\nseries my heart leaps for a moment, in the hope that we're getting\ncloser to have a repository object in git.\n\nI kind of wish that 'free' returned NULL so that callers could do\n\n\tp = free(p);\n\nwithout requiring a custom helper.  We could introduce a free_wrapper\nthat works that way but that is probably not worth it, either.\n\nThanks for an interesting and pleasant read.\n\nSincerely,\nJonathan\n"},{"id":"321861","messageId":"20170609233701.GA7195@whir","threadId":"46082","inReplyTo":"20170609222738.GF21733@aiede.mtv.corp.google.com","subject":"Re: [PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2017-06-09T23:37:02Z","receivedAt":"2017-06-09T23:37:07Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Jonathan Nieder <jrnieder@gmail.com> wrote:\n> Hi,\n> \n> Ævar Arnfjörð Bjarmason wrote:\n> \n> > Add a FREEZ() wrapper marco for the common pattern of freeing a\n> > pointer and assigning NULL to it right afterwards.\n> \n> I'm conflicted.  On one hand it makes code more concise and makes it\n> easier for people to remember to assign NULL after freeing a variable.\n> On the other hand it makes git more of a custom dialect of C, which\n> may make the code harder to read and hack on for new contributors.\n\nI think this problem could be avoided by using a more explicit\nname, perhaps: \"free_and_null\"\n\nSeeing the initial subject, I thought this series was short for\n\"freeze\" (like \"creat\").\n\nHowever, I admit FREEZ caught my eye because I thought it was\na way to freeze a repository, somehow :)\n\n> My feeling is that the costs outweigh the benefits, but I haven't\n> thought it through thoroughly.\n\n<snip>\n\n> > index 4b7dcf21ad..ba2d0c8c80 100644\n> > --- a/git-compat-util.h\n> > +++ b/git-compat-util.h\n> > @@ -805,6 +805,12 @@ extern int xmkstemp_mode(char *template, int mode);\n> >  extern char *xgetcwd(void);\n> >  extern FILE *fopen_for_writing(const char *path);\n> > \n> > +/*\n> > + * FREEZ(ptr) is like free(ptr) followed by ptr = NULL. Note that ptr\n> > + * is used twice, so don't pass e.g. ptr++.\n> > + */\n> > +#define FREEZ(p) do { free(p); (p) = NULL; } while (0)\n> > +\n> >  #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))\n> >  #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))\n> \n> Golfing: it's possible to do this without ptr being used twice by\n> introducing a helper function:\n> \n> \tstatic inline void freez_impl(void **p) {\n> \t\tfree(*p);\n> \t\t*p = NULL;\n> \t}\n\nYes.  I think it's prudent to avoid macros in case there are\nside effects.\n\n> \t#define FREEZ(p) freez_impl(&(p))\n> \n> That way side-effectful callers like FREEZ(func() ? a : b) would\n> work.\n\nI don't see the point of a macro wrapper, forcing the user to\ntype out the '&' should drive home the point that the pointer\ngets set to NULL.  I also find capitalization tiring-to-read\nbecause all characters are the same height.\n\n<snip>\n\n> I kind of wish that 'free' returned NULL so that callers could do\n> \n> \tp = free(p);\n> \n> without requiring a custom helper.  We could introduce a free_wrapper\n> that works that way but that is probably not worth it, either.\n\nSometimes I have wished similar things, too, but that means the\nsame identifier shows up twice in one line and camouflages the\ncode.\n"},{"id":"321862","messageId":"20170609174034.61889ae8@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-10T00:40:34Z","receivedAt":"2017-06-10T00:40:48Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Thu,  8 Jun 2017 16:40:28 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> When I sent out my RFC series there seemed to be a lot of interest but I\n> haven't seen many people jump to review this series.  Despite lack of review I\n> wanted to get out another version which includes some changes to fix things\n> that were bugging me about the series.  Hopfully this v2 will prod some more\n> people to take a look.\n> \n> The meat of the series is really from 04-15 and patch 32 which converts\n> ls-files to recurse using a repository object.  So if you're pressed for time\n> you can focus on those patches.\n\nThanks - I can see in patch 32 that one immediate benefit is that\nls-files can now recurse into submodules without needing to invoke an\nextra process just to change the GIT_DIR.\n\nBefore I get into the details, I have some questions:\n\n1. I am concerned that \"struct repository\" will end up growing without\nbounds as we store more and more repo-specific concerns in it. Could it\nbe restricted to just the fields populated by repo_init()?\nrepo_read_index() will then return the index itself, instead of using\n\"struct repository\" as a cache. This means that code using\nrepo_read_index() will need to maintain its own variable holding the\nreturned index, but that is likely a positive - it's better for code to\njust pass around the specific thing needed between functions anyway, as\nopposed to passing a giant \"struct repository\" (which partially defeats\nthe purpose of eliminating the usage of globals).\n\n2. If we do the above, another potential benefit is that (I think) the\nrepo_config_get_.* functions would no longer be necessary, since we\nwould have a function that generates a \"struct config_set\" given a repo,\nand then we just use the git_configset_get_.* functions on it. This\nwould also reduce the urgency of extracting the config methods into its\nown header file, and reduce the size of this patch set.\n\n(I was also going to suggest that you remove the \"convert\" patches, but\nthat is not possible - ls-files uses get_cached_convert_stats_ascii()\nfrom convert.h despite not #include-ing it.)\n"},{"id":"321865","messageId":"xmqq60g462nd.fsf@gitster.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170609233701.GA7195@whir","subject":"Re: [PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-10T01:40:38Z","receivedAt":"2017-06-10T01:40:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> Jonathan Nieder <jrnieder@gmail.com> wrote:\n>> Hi,\n>> \n>> Ævar Arnfjörð Bjarmason wrote:\n>> \n>> > Add a FREEZ() wrapper marco for the common pattern of freeing a\n>> > pointer and assigning NULL to it right afterwards.\n>> \n>> I'm conflicted.  On one hand it makes code more concise and makes it\n>> easier for people to remember to assign NULL after freeing a variable.\n>> On the other hand it makes git more of a custom dialect of C, which\n>> may make the code harder to read and hack on for new contributors.\n>\n> I think this problem could be avoided by using a more explicit\n> name, perhaps: \"free_and_null\"\n>\n> Seeing the initial subject, I thought this series was short for\n> \"freeze\" (like \"creat\").\n\nBoth match my thoughts exactly ;-)\n\n> ...\n> I don't see the point of a macro wrapper, forcing the user to\n> type out the '&' should drive home the point that the pointer\n> gets set to NULL.  I also find capitalization tiring-to-read\n> because all characters are the same height.\n\nSounds sensible.\n\nSo make Jonathan's freez_impl a public API and rename it to\nfree_and_null(), perhaps?\n"},{"id":"321875","messageId":"20170610032143.GA7880@starla","threadId":"46082","inReplyTo":"xmqq60g462nd.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2017-06-10T03:21:43Z","receivedAt":"2017-06-10T03:21:52Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> Eric Wong <e@80x24.org> writes:\n> > I don't see the point of a macro wrapper, forcing the user to\n> > type out the '&' should drive home the point that the pointer\n> > gets set to NULL.  I also find capitalization tiring-to-read\n> > because all characters are the same height.\n> \n> Sounds sensible.\n> \n> So make Jonathan's freez_impl a public API and rename it to\n> free_and_null(), perhaps?\n\nPerhaps...  I think it needs to take \"void *\" to avoid warnings:\n\n\tstatic inline void free_and_null(void *ptrptr)\n\t{\n\t\tvoid **tmp = ptrptr;\n\n\t\tfree(*tmp);\n\t\t*tmp = NULL;\n\t}\n\n...At least I needed to do that for \"mog_free_and_null\" in\ncmogstored:\n\n\thttps://bogomips.org/cmogstored.git/plain/alloc.c?h=v1.6.0\n\nBut heck, maybe that's covering up for something else I got\nwrong in cmogstored *shrug*    I don't know all of C.\n"},{"id":"321880","messageId":"xmqq8tl02xjv.fsf@gitster.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170609000849.GA130522@google.com","subject":"Re: [PATCH v2 32/32] ls-files: use repository object","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-10T05:59:00Z","receivedAt":"2017-06-10T05:59:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brandon Williams <bmwill@google.com> writes:\n\n>> -\tif (read_cache() < 0)\n>> +\tif (repo_read_index(the_repository))\n>\n> oops, looks like this should have been:\n\nQueued, with this fix-up already applied.\n\nIt had a bit of conflicts with topics in flight that may added some\nmore globals, so please make sure that the conflict resolution is\nsane (i.e. do not look only at bw/repo-object and be happy; rather,\nplease check \"pu^{/^Merge branch 'bw/repo-object' into pu}\".\n\nThanks.\n"},{"id":"321882","messageId":"20170610060712.foqre5fscaxu3tnx@sigill.intra.peff.net","threadId":"46082","inReplyTo":"20170609174034.61889ae8@twelve2.svl.corp.google.com","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-06-10T06:07:12Z","receivedAt":"2017-06-10T06:12:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jun 09, 2017 at 05:40:34PM -0700, Jonathan Tan wrote:\n\n> Before I get into the details, I have some questions:\n> \n> 1. I am concerned that \"struct repository\" will end up growing without\n> bounds as we store more and more repo-specific concerns in it. Could it\n> be restricted to just the fields populated by repo_init()?\n> repo_read_index() will then return the index itself, instead of using\n> \"struct repository\" as a cache. This means that code using\n> repo_read_index() will need to maintain its own variable holding the\n> returned index, but that is likely a positive - it's better for code to\n> just pass around the specific thing needed between functions anyway, as\n> opposed to passing a giant \"struct repository\" (which partially defeats\n> the purpose of eliminating the usage of globals).\n\nI think the repository object has to become a kitchen sink of sorts,\nbecause we have tons of global variables representing repo-wide config.\nls-files doesn't respect a lot of config, but what should, e.g.:\n\n  git config core.quotepath true\n  git -C submodule config core.quotepath false\n  git ls-files --recurse-submodules\n\ndo?  Right now, with a separate process, we respect the submodule\nversion of the config. But in a single process[1] we'd need one copy of\nthe quote_path_fully variable for each repo object. It's tempting for\nthis case to say that core.quotepath from the super-project should just\ntake precedence, as that's where the command is issued from (and why the\nheck would anybody have per-repo settings for this anyway?). But I\nsuspect as we get into more complicated commands that there are likely\nto be config variables that are important to match to each repo.\n\nI do agree that \"pass just what the sub-function needs\" is a good rule\nof thumb. But the reason that these are globals in the first place is\nthat there are a ton of them, and they are used at the lowest levels of\ncall chains. So I have a feeling that we're always going to need some\nbig object to hold all that context when doing multi-repo operations in\na single process.\n\nFor config, in theory that could be a big \"config_set\" object, but\nthat's not quite how we treat our config. We usually parse it once into\nactual variables. So really you end up with a big parsed-config object\nthat gets passed around, I'd think.\n\n-Peff\n\n[1] I wanted to see how Brandon's series behaved for this quotepath\n    case, but unfortunately I couldn't get it to work in even a simple\n    case.  :(\n\n      $ git ls-files --recurse-submodules\n      fatal: index file corrupt\n"},{"id":"321883","messageId":"20170610061326.2dkdnvpjdq5d7223@sigill.intra.peff.net","threadId":"46082","inReplyTo":"20170610060712.foqre5fscaxu3tnx@sigill.intra.peff.net","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-06-10T06:13:26Z","receivedAt":"2017-06-10T06:13:33Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Jun 10, 2017 at 02:07:12AM -0400, Jeff King wrote:\n\n> I think the repository object has to become a kitchen sink of sorts,\n> because we have tons of global variables representing repo-wide config.\n> ls-files doesn't respect a lot of config, but what should, e.g.:\n> \n>   git config core.quotepath true\n>   git -C submodule config core.quotepath false\n>   git ls-files --recurse-submodules\n>\n> [...]\n>\n> [1] I wanted to see how Brandon's series behaved for this quotepath\n>     case, but unfortunately I couldn't get it to work in even a simple\n>     case.  :(\n> \n>       $ git ls-files --recurse-submodules\n>       fatal: index file corrupt\n\nAh, this was just hitting the bug mentioned later in the thread. With\nthat fix, I can see that it does indeed behave differently than the\ncurrent code:\n\n  git config core.quotepath true\n  git -C submodule config core.quotepath false\n  (cd submodule &&\n   echo hello >buenos_días &&\n   git add .\n  )\n  git ls-files --recurse-submodules\n\nshows:\n\n  submodule/buenos_días\n\nbefore the patch series, and:\n\n  \"submodule/buenos_d\\303\\255as\"\n\nafter.\n\nLike I said, I doubt this is a bug that anybody cares much about, but\nit's hard to know what other repo-specific global-variable usage is\nlurking in low-level code.\n\n-Peff\n"},{"id":"321888","messageId":"m2vao4jpql.fsf@linux-m68k.org","threadId":"46082","inReplyTo":"20170609222738.GF21733@aiede.mtv.corp.google.com","subject":"Re: [PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Andreas Schwab","fromEmail":"schwab@linux-m68k.org","sentAt":"2017-06-10T06:55:46Z","receivedAt":"2017-06-10T06:55:59Z","isPatch":true,"sender":{"key":"schwab@linux-m68k.org","avatar":"https://avatars.githubusercontent.com/u/2175493?v=4"},"body":"On Jun 09 2017, Jonathan Nieder <jrnieder@gmail.com> wrote:\n\n> That way side-effectful callers like FREEZ(func() ? a : b) would\n> work.\n\nExcept that you cannot take the address of a non-lvalue.\n\nAndreas.\n\n-- \nAndreas Schwab, schwab@linux-m68k.org\nGPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5\n\"And now for something completely different.\"\n"},{"id":"321891","messageId":"20170610072506.embaavscstmjnv6v@sigill.intra.peff.net","threadId":"46082","inReplyTo":"20170610032143.GA7880@starla","subject":"Re: [PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-06-10T07:25:06Z","receivedAt":"2017-06-10T07:25:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Jun 10, 2017 at 03:21:43AM +0000, Eric Wong wrote:\n\n> > So make Jonathan's freez_impl a public API and rename it to\n> > free_and_null(), perhaps?\n> \n> Perhaps...  I think it needs to take \"void *\" to avoid warnings:\n> \n> \tstatic inline void free_and_null(void *ptrptr)\n> \t{\n> \t\tvoid **tmp = ptrptr;\n> \n> \t\tfree(*tmp);\n> \t\t*tmp = NULL;\n> \t}\n\nThat unfortunately makes it very easy to get it wrong in the callers.\nBoth:\n\n  free_and_null(&p);\n\nand\n\n  free_and_null(p);\n\nwould be accepted by the compiler, but one of them causes undefined\nbehavior.\n\nUnfortunately using \"void **\" in the declaration doesn't work, because\nC's implicit casting rules don't apply to pointer-to-pointer types.\n\n-Peff\n"},{"id":"321932","messageId":"20170611003500.GD81269@google.com","threadId":"46082","inReplyTo":"20170610060712.foqre5fscaxu3tnx@sigill.intra.peff.net","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-11T00:35:00Z","receivedAt":"2017-06-11T00:35:10Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/10, Jeff King wrote:\n> On Fri, Jun 09, 2017 at 05:40:34PM -0700, Jonathan Tan wrote:\n> \n> > Before I get into the details, I have some questions:\n> > \n> > 1. I am concerned that \"struct repository\" will end up growing without\n> > bounds as we store more and more repo-specific concerns in it. Could it\n> > be restricted to just the fields populated by repo_init()?\n> > repo_read_index() will then return the index itself, instead of using\n> > \"struct repository\" as a cache. This means that code using\n> > repo_read_index() will need to maintain its own variable holding the\n> > returned index, but that is likely a positive - it's better for code to\n> > just pass around the specific thing needed between functions anyway, as\n> > opposed to passing a giant \"struct repository\" (which partially defeats\n> > the purpose of eliminating the usage of globals).\n> \n> I think the repository object has to become a kitchen sink of sorts,\n> because we have tons of global variables representing repo-wide config.\n> ls-files doesn't respect a lot of config, but what should, e.g.:\n> \n>   git config core.quotepath true\n>   git -C submodule config core.quotepath false\n>   git ls-files --recurse-submodules\n> \n> do?  Right now, with a separate process, we respect the submodule\n> version of the config. But in a single process[1] we'd need one copy of\n> the quote_path_fully variable for each repo object. It's tempting for\n> this case to say that core.quotepath from the super-project should just\n> take precedence, as that's where the command is issued from (and why the\n> heck would anybody have per-repo settings for this anyway?). But I\n> suspect as we get into more complicated commands that there are likely\n> to be config variables that are important to match to each repo.\n> \n> I do agree that \"pass just what the sub-function needs\" is a good rule\n> of thumb. But the reason that these are globals in the first place is\n> that there are a ton of them, and they are used at the lowest levels of\n> call chains. So I have a feeling that we're always going to need some\n> big object to hold all that context when doing multi-repo operations in\n> a single process.\n> \n> For config, in theory that could be a big \"config_set\" object, but\n> that's not quite how we treat our config. We usually parse it once into\n> actual variables. So really you end up with a big parsed-config object\n> that gets passed around, I'd think.\n> \n> -Peff\n> \n> [1] I wanted to see how Brandon's series behaved for this quotepath\n>     case, but unfortunately I couldn't get it to work in even a simple\n>     case.  :(\n> \n>       $ git ls-files --recurse-submodules\n>       fatal: index file corrupt\n\nYeah sorry about that...I commented on patch 32 indicating that I made a\nsmall mistake and forgot a '> 0' when checking the index.  I made a last\nminute change before sending v2 out and forgot to run tests again (I'm\nterrible i know!).\n\n-- \nBrandon Williams\n"},{"id":"321933","messageId":"20170611004329.GE81269@google.com","threadId":"46082","inReplyTo":"20170610061326.2dkdnvpjdq5d7223@sigill.intra.peff.net","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-11T00:43:29Z","receivedAt":"2017-06-11T00:43:42Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/10, Jeff King wrote:\n> On Sat, Jun 10, 2017 at 02:07:12AM -0400, Jeff King wrote:\n> \n> > I think the repository object has to become a kitchen sink of sorts,\n> > because we have tons of global variables representing repo-wide config.\n> > ls-files doesn't respect a lot of config, but what should, e.g.:\n> > \n> >   git config core.quotepath true\n> >   git -C submodule config core.quotepath false\n> >   git ls-files --recurse-submodules\n> >\n> > [...]\n> >\n> > [1] I wanted to see how Brandon's series behaved for this quotepath\n> >     case, but unfortunately I couldn't get it to work in even a simple\n> >     case.  :(\n> > \n> >       $ git ls-files --recurse-submodules\n> >       fatal: index file corrupt\n> \n> Ah, this was just hitting the bug mentioned later in the thread. With\n> that fix, I can see that it does indeed behave differently than the\n> current code:\n> \n>   git config core.quotepath true\n>   git -C submodule config core.quotepath false\n>   (cd submodule &&\n>    echo hello >buenos_días &&\n>    git add .\n>   )\n>   git ls-files --recurse-submodules\n> \n> shows:\n> \n>   submodule/buenos_días\n> \n> before the patch series, and:\n> \n>   \"submodule/buenos_d\\303\\255as\"\n> \n> after.\n> \n> Like I said, I doubt this is a bug that anybody cares much about, but\n> it's hard to know what other repo-specific global-variable usage is\n> lurking in low-level code.\n\nI disagree with a few points of what jonathan said (mostly about\nremoving the config from the repo object, as I like the idea of nothing\nknowing about a 'config_set' object) and I think this problem could be\nsolved in a couple ways.\n\nI don't think that the in-memory global variable 'quotepath' (or\nwhatever its called) should live in the repository object (I mean it's\nalready contained in the config) but rather 'quotepath' is specific to\nhow ls-files handles its output.  So really what should happen is you\npass a pair of objects to the ls-files machinery (or any other command's\nmachinery) (1) the repository object being operated on and (2) an\noptions struct which can be configured based on the repository.  So when\nrecursing you can do something like the following:\n\n  repo_init(submodule, path_to_submodule);\n  configure_opts(sub_opts, submodule, super_opts)\n  ls_files(submodule, sub_opts);\n\nThis eliminates bloating 'struct repository' and would allow you to have\nthings configured differently in submodules (which is crazy if you ask\nme, but people do crazy things).\n\n-- \nBrandon Williams\n"},{"id":"321945","messageId":"CAGZ79kbtZJd3O1vZBEkqU5_VRs5LmJhxUKtWu4RWTyk5M1r__Q@mail.gmail.com","threadId":"46082","inReplyTo":"20170610060712.foqre5fscaxu3tnx@sigill.intra.peff.net","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-12T05:24:12Z","receivedAt":"2017-06-12T05:24:19Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Fri, Jun 9, 2017 at 11:07 PM, Jeff King <peff@peff.net> wrote:\n> On Fri, Jun 09, 2017 at 05:40:34PM -0700, Jonathan Tan wrote:\n>\n>> Before I get into the details, I have some questions:\n>>\n>> 1. I am concerned that \"struct repository\" will end up growing without\n>> bounds as we store more and more repo-specific concerns in it. Could it\n>> be restricted to just the fields populated by repo_init()?\n>> repo_read_index() will then return the index itself, instead of using\n>> \"struct repository\" as a cache. This means that code using\n>> repo_read_index() will need to maintain its own variable holding the\n>> returned index, but that is likely a positive - it's better for code to\n>> just pass around the specific thing needed between functions anyway, as\n>> opposed to passing a giant \"struct repository\" (which partially defeats\n>> the purpose of eliminating the usage of globals).\n>\n> I think the repository object has to become a kitchen sink of sorts,\n> because we have tons of global variables representing repo-wide config.\n\nAFAICT we want to operate on struct 'the_repo' and struct 'the_cmd_options'\neventually. In our use case of submodules the submodules would ignore the\nsettings of the main repo, but still accept guidance of the_cmd_config or\n'the_config.\n\n> So I have a feeling that we're always going to need some\n> big object to hold all that context when doing multi-repo operations in\n> a single process.\n\nWell not just one big struct, but two. (or more?)\n"},{"id":"321981","messageId":"20170612120140.3da90194@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170610060712.foqre5fscaxu3tnx@sigill.intra.peff.net","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-12T19:01:40Z","receivedAt":"2017-06-12T19:01:52Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Sat, 10 Jun 2017 02:07:12 -0400\nJeff King <peff@peff.net> wrote:\n\n> I do agree that \"pass just what the sub-function needs\" is a good rule\n> of thumb. But the reason that these are globals in the first place is\n> that there are a ton of them, and they are used at the lowest levels of\n> call chains. So I have a feeling that we're always going to need some\n> big object to hold all that context when doing multi-repo operations in\n> a single process.\n\nFrom my experience with the codebase, it seems that most of these config\nvariables are static (file-local). This means that the lowest levels of\ncall chains could probably get away with storing per-repo configs in a\nstatic hashmap or associative array keyed by repo (if they cannot just\npass the config around).\n\nHaving said that, if it did come to the hashmap, I probably would prefer\njust putting the config in the repo object too. So maybe that is the way\nto go.\n"},{"id":"321983","messageId":"20170612121054.72618ac9@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170611004329.GE81269@google.com","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-12T19:10:54Z","receivedAt":"2017-06-12T19:11:05Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Sat, 10 Jun 2017 17:43:29 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> I disagree with a few points of what jonathan said (mostly about\n> removing the config from the repo object, as I like the idea of nothing\n> knowing about a 'config_set' object) and I think this problem could be\n> solved in a couple ways.\n\nAh...is the plan to eventually delete the git_configset_.* functions and\nonly have repo_config_get_.* functions? If yes, I would prefer the\nin-between state to be \"git_config_set_get_int(repo->configset, ...)\"\ninstead of \"repo_config_get_int(repo, ...)\" to avoid the parallel set of\nfunctions (which will make it more troublesome, for example, to add\nsupport for a new data type) but I can see the benefits of having the\nrepo_config_get_.* functions too (conciseness and not having to make one\nfinal find-and-replace when we finally complete the migration, at least)\nso I don't feel too strongly about this.\n\n> I don't think that the in-memory global variable 'quotepath' (or\n> whatever its called) should live in the repository object (I mean it's\n> already contained in the config) but rather 'quotepath' is specific to\n> how ls-files handles its output.  So really what should happen is you\n> pass a pair of objects to the ls-files machinery (or any other command's\n> machinery) (1) the repository object being operated on and (2) an\n> options struct which can be configured based on the repository.  So when\n> recursing you can do something like the following:\n> \n>   repo_init(submodule, path_to_submodule);\n>   configure_opts(sub_opts, submodule, super_opts)\n>   ls_files(submodule, sub_opts);\n> \n> This eliminates bloating 'struct repository' and would allow you to have\n> things configured differently in submodules (which is crazy if you ask\n> me, but people do crazy things).\n\nThis does sound good to me.\n"},{"id":"321984","messageId":"20170612191121.GB154599@google.com","threadId":"46082","inReplyTo":"20170612120140.3da90194@twelve2.svl.corp.google.com","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-12T19:11:21Z","receivedAt":"2017-06-12T19:11:32Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/12, Jonathan Tan wrote:\n> On Sat, 10 Jun 2017 02:07:12 -0400\n> Jeff King <peff@peff.net> wrote:\n> \n> > I do agree that \"pass just what the sub-function needs\" is a good rule\n> > of thumb. But the reason that these are globals in the first place is\n> > that there are a ton of them, and they are used at the lowest levels of\n> > call chains. So I have a feeling that we're always going to need some\n> > big object to hold all that context when doing multi-repo operations in\n> > a single process.\n> \n> From my experience with the codebase, it seems that most of these config\n> variables are static (file-local). This means that the lowest levels of\n> call chains could probably get away with storing per-repo configs in a\n> static hashmap or associative array keyed by repo (if they cannot just\n> pass the config around).\n> \n> Having said that, if it did come to the hashmap, I probably would prefer\n> just putting the config in the repo object too. So maybe that is the way\n> to go.\n\nThis is how the config is already handled.  A config_set is just a\nwrapper around a fancy hashmap.  Callers query using a string as a key\nand are returned the value for that config option.  I say fancy because\nit does stuff to handle multiple values, etc.\n\nI'm not sure I know what you mean by config variables which are static,\nare you referring to the in-memory options which are populated by\nquerying the config?  Those I wouldn't want to see placed in a\n'repository object'.\n\n-- \nBrandon Williams\n"},{"id":"321986","messageId":"20170612195710.GC154599@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-5-bmwill@google.com","subject":"Re: [PATCH v2 04/32] config: don't implicitly use gitdir","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-12T19:57:10Z","receivedAt":"2017-06-12T19:57:18Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/08, Brandon Williams wrote:\n> Commit 2185fde56 (config: handle conditional include when $GIT_DIR is\n> not set up) added a 'git_dir' field to the config_options struct.  Let's\n> use this option field explicitly all the time instead of occasionally\n> falling back to calling 'git_pathdup(\"config\")' to get the path to the\n> local repository configuration.  This allows 'do_git_config_sequence()'\n> to not implicitly rely on global repository state.\n> \n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  builtin/config.c | 2 ++\n>  config.c         | 4 ++--\n>  2 files changed, 4 insertions(+), 2 deletions(-)\n> \n> diff --git a/builtin/config.c b/builtin/config.c\n> index 753c40a5c..90f49a6ee 100644\n> --- a/builtin/config.c\n> +++ b/builtin/config.c\n> @@ -539,6 +539,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n>  \t\tconfig_options.respect_includes = !given_config_source.file;\n>  \telse\n>  \t\tconfig_options.respect_includes = respect_includes_opt;\n> +\tif (have_git_dir())\n> +\t\tconfig_options.git_dir = get_git_common_dir();\n>  \n>  \tif (end_null) {\n>  \t\tterm = '\\0';\n> diff --git a/config.c b/config.c\n> index 2390f98e3..ff09b27b8 100644\n> --- a/config.c\n> +++ b/config.c\n> @@ -1548,8 +1548,6 @@ static int do_git_config_sequence(const struct config_options *opts,\n>  \n>  \tif (opts->git_dir)\n>  \t\trepo_config = mkpathdup(\"%s/config\", opts->git_dir);\n> -\telse if (have_git_dir())\n> -\t\trepo_config = git_pathdup(\"config\");\n>  \telse\n>  \t\trepo_config = NULL;\n>  \n> @@ -1613,6 +1611,8 @@ static void git_config_raw(config_fn_t fn, void *data)\n>  \tstruct config_options opts = {0};\n>  \n>  \topts.respect_includes = 1;\n> +\tif (have_git_dir())\n> +\t\topts.git_dir = get_git_common_dir();\n>  \tif (git_config_with_options(fn, data, NULL, &opts) < 0)\n>  \t\t/*\n>  \t\t * git_config_with_options() normally returns only\n\nI missed a case in 'include_by_gitdir'.\n\nGiven that these config changes touch a lot of files (making a config.h\nfiles and including it everyone) I think I'll break this into its own\nseries so that it can get reviewed and merged in faster.  This is\nespecially due to this series breaking pu right now.\n\n\n-- \nBrandon Williams\n"},{"id":"321987","messageId":"20170612130409.07725a75@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170612191121.GB154599@google.com","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-12T20:04:09Z","receivedAt":"2017-06-12T20:04:20Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Mon, 12 Jun 2017 12:11:21 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> On 06/12, Jonathan Tan wrote:\n> > On Sat, 10 Jun 2017 02:07:12 -0400\n> > Jeff King <peff@peff.net> wrote:\n> > \n> > > I do agree that \"pass just what the sub-function needs\" is a good rule\n> > > of thumb. But the reason that these are globals in the first place is\n> > > that there are a ton of them, and they are used at the lowest levels of\n> > > call chains. So I have a feeling that we're always going to need some\n> > > big object to hold all that context when doing multi-repo operations in\n> > > a single process.\n> > \n> > From my experience with the codebase, it seems that most of these config\n> > variables are static (file-local). This means that the lowest levels of\n> > call chains could probably get away with storing per-repo configs in a\n> > static hashmap or associative array keyed by repo (if they cannot just\n> > pass the config around).\n> > \n> > Having said that, if it did come to the hashmap, I probably would prefer\n> > just putting the config in the repo object too. So maybe that is the way\n> > to go.\n> \n> This is how the config is already handled.  A config_set is just a\n> wrapper around a fancy hashmap.  Callers query using a string as a key\n> and are returned the value for that config option.  I say fancy because\n> it does stuff to handle multiple values, etc.\n\nThe hashmap I meant is one wrapping the one you describe:\n\n  repo -> configset\n\nOr equivalently:\n\n  repo -> (string -> value(s))\n\n> I'm not sure I know what you mean by config variables which are static,\n> are you referring to the in-memory options which are populated by\n> querying the config?  Those I wouldn't want to see placed in a\n> 'repository object'.\n\nYes. I agree that I wouldn't want to see them placed in a repository\nobject, but after reading Peff's e-mail, I was thinking of what happens\nif a file repeatedly invokes a config-sensitive function in another\nfile. For example:\n\n a.c\n  for (i = 0; i < 100; i++) b_output(repo, x);\n\n b.c\n  void b_output(struct repository *repo, int x)\n  {\n   /* print the configured \"b.prefix\" followed by x */\n  }\n\nWe probably wouldn't want to parse the repo's configset every time\nb_output() is invoked, but then, where to store our parsed \"b.prefix\"?\nThe only alternatives I see is to have a static hashmap in b.c (keyed by\nrepo, as described above), which would work if such a situation is rare\n(or can be made rare), but if it is common, maybe we have no choice but\nto put it in struct repository.\n"},{"id":"321994","messageId":"20170612212350.demwgog22liqae2p@sigill.intra.peff.net","threadId":"46082","inReplyTo":"CAGZ79kbtZJd3O1vZBEkqU5_VRs5LmJhxUKtWu4RWTyk5M1r__Q@mail.gmail.com","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-06-12T21:23:50Z","receivedAt":"2017-06-12T21:23:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Jun 11, 2017 at 10:24:12PM -0700, Stefan Beller wrote:\n\n> On Fri, Jun 9, 2017 at 11:07 PM, Jeff King <peff@peff.net> wrote:\n> > On Fri, Jun 09, 2017 at 05:40:34PM -0700, Jonathan Tan wrote:\n> >\n> >> Before I get into the details, I have some questions:\n> >>\n> >> 1. I am concerned that \"struct repository\" will end up growing without\n> >> bounds as we store more and more repo-specific concerns in it. Could it\n> >> be restricted to just the fields populated by repo_init()?\n> >> repo_read_index() will then return the index itself, instead of using\n> >> \"struct repository\" as a cache. This means that code using\n> >> repo_read_index() will need to maintain its own variable holding the\n> >> returned index, but that is likely a positive - it's better for code to\n> >> just pass around the specific thing needed between functions anyway, as\n> >> opposed to passing a giant \"struct repository\" (which partially defeats\n> >> the purpose of eliminating the usage of globals).\n> >\n> > I think the repository object has to become a kitchen sink of sorts,\n> > because we have tons of global variables representing repo-wide config.\n> \n> AFAICT we want to operate on struct 'the_repo' and struct 'the_cmd_options'\n> eventually. In our use case of submodules the submodules would ignore the\n> settings of the main repo, but still accept guidance of the_cmd_config or\n> 'the_config.\n> \n> > So I have a feeling that we're always going to need some\n> > big object to hold all that context when doing multi-repo operations in\n> > a single process.\n> \n> Well not just one big struct, but two. (or more?)\n\nRight, I think you could have a separate kitchen-sink struct that isn't\nthe \"repo\" one. But now you have to pass both of those around, which is\ngoing to get cumbersome. Almost every function is going to end up\npassing around the context struct.\n\nI almost think it would be easier to shove them all of the context into\na big global struct and \"push\" and \"pop\" contexts from a stack of\nstructs. That gets you the in-process benefits, though of course it's\nabsolutely horrible if you ever want to multi-thread across two contexts.\n\n-Peff\n"},{"id":"321995","messageId":"20170612212429.GD154599@google.com","threadId":"46082","inReplyTo":"xmqq8tl02xjv.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 32/32] ls-files: use repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-12T21:24:29Z","receivedAt":"2017-06-12T21:25:02Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/10, Junio C Hamano wrote:\n> Brandon Williams <bmwill@google.com> writes:\n> \n> >> -\tif (read_cache() < 0)\n> >> +\tif (repo_read_index(the_repository))\n> >\n> > oops, looks like this should have been:\n> \n> Queued, with this fix-up already applied.\n> \n> It had a bit of conflicts with topics in flight that may added some\n> more globals, so please make sure that the conflict resolution is\n> sane (i.e. do not look only at bw/repo-object and be happy; rather,\n> please check \"pu^{/^Merge branch 'bw/repo-object' into pu}\".\n> \n> Thanks.\n\nThanks for picking this up and merging it to pu.  After some discussion\nI think it may be ideal to split this thing up so that the parts that\naren't specific to the 'repository object' can be reviewed more easily\nas a 32 long patch set can be daunting to review.  I also need to think\na little bit more about the breakage this series causes in pu.\n\n-- \nBrandon Williams\n"},{"id":"321996","messageId":"20170612212804.vjg3dvxjvbmayksz@sigill.intra.peff.net","threadId":"46082","inReplyTo":"20170612130409.07725a75@twelve2.svl.corp.google.com","subject":"Re: [PATCH v2 00/32] repository object","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-06-12T21:28:05Z","receivedAt":"2017-06-12T21:28:23Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 12, 2017 at 01:04:09PM -0700, Jonathan Tan wrote:\n\n> > I'm not sure I know what you mean by config variables which are static,\n> > are you referring to the in-memory options which are populated by\n> > querying the config?  Those I wouldn't want to see placed in a\n> > 'repository object'.\n> \n> Yes. I agree that I wouldn't want to see them placed in a repository\n> object, but after reading Peff's e-mail, I was thinking of what happens\n> if a file repeatedly invokes a config-sensitive function in another\n> file. For example:\n> \n>  a.c\n>   for (i = 0; i < 100; i++) b_output(repo, x);\n> \n>  b.c\n>   void b_output(struct repository *repo, int x)\n>   {\n>    /* print the configured \"b.prefix\" followed by x */\n>   }\n> \n> We probably wouldn't want to parse the repo's configset every time\n> b_output() is invoked, but then, where to store our parsed \"b.prefix\"?\n> The only alternatives I see is to have a static hashmap in b.c (keyed by\n> repo, as described above), which would work if such a situation is rare\n> (or can be made rare), but if it is common, maybe we have no choice but\n> to put it in struct repository.\n\nI think besides optimization, we often parse the textual config into\nvariables and then _modify_ those variables based on other input (most\noften command-line arguments provided by the user, but sometimes other\ncircumstances).\n\nYou can move the resolution to the point-of-use instead of\npoint-of-setting, but that's going to be a big change to how most of the\ncode already works.\n\n-Peff\n"},{"id":"322363","messageId":"xmqqfuf12o46.fsf@gitster.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170610072506.embaavscstmjnv6v@sigill.intra.peff.net","subject":"Re: [PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-15T16:48:41Z","receivedAt":"2017-06-15T16:48:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Sat, Jun 10, 2017 at 03:21:43AM +0000, Eric Wong wrote:\n>\n>> > So make Jonathan's freez_impl a public API and rename it to\n>> > free_and_null(), perhaps?\n>> \n>> Perhaps...  I think it needs to take \"void *\" to avoid warnings:\n>> \n>> \tstatic inline void free_and_null(void *ptrptr)\n>> \t{\n>> \t\tvoid **tmp = ptrptr;\n>> \n>> \t\tfree(*tmp);\n>> \t\t*tmp = NULL;\n>> \t}\n>\n> That unfortunately makes it very easy to get it wrong in the callers.\n> Both:\n>\n>   free_and_null(&p);\n>\n> and\n>\n>   free_and_null(p);\n>\n> would be accepted by the compiler, but one of them causes undefined\n> behavior.\n>\n> Unfortunately using \"void **\" in the declaration doesn't work, because\n> C's implicit casting rules don't apply to pointer-to-pointer types.\n\nAll true.  \n\nI still think the macro FREEZ() is too confusing a name to live;\nperhaps we can take Ævar's patch with s/FREEZ/FREE_AND_NULL/ and be\ndone with it?  By spelling it in all caps, readers will know that\nthere is something special going on in that macro, and Eric's\n\"forcing the readers to type & in front to let them be aware that\nthe ptr variable is being manipulated\" may become less necessary.\n\n"},{"id":"322365","messageId":"CACBZZX7S9A=mPSgqtmVyZbLdR3GVH+ux3tGN1QXBMEzbg8Ffog@mail.gmail.com","threadId":"46082","inReplyTo":"xmqqfuf12o46.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 1/2] git-compat-util: add a FREEZ() wrapper around free(ptr); ptr = NULL","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-15T17:13:41Z","receivedAt":"2017-06-15T17:14:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Thu, Jun 15, 2017 at 6:48 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Jeff King <peff@peff.net> writes:\n>\n>> On Sat, Jun 10, 2017 at 03:21:43AM +0000, Eric Wong wrote:\n>>\n>>> > So make Jonathan's freez_impl a public API and rename it to\n>>> > free_and_null(), perhaps?\n>>>\n>>> Perhaps...  I think it needs to take \"void *\" to avoid warnings:\n>>>\n>>>      static inline void free_and_null(void *ptrptr)\n>>>      {\n>>>              void **tmp = ptrptr;\n>>>\n>>>              free(*tmp);\n>>>              *tmp = NULL;\n>>>      }\n>>\n>> That unfortunately makes it very easy to get it wrong in the callers.\n>> Both:\n>>\n>>   free_and_null(&p);\n>>\n>> and\n>>\n>>   free_and_null(p);\n>>\n>> would be accepted by the compiler, but one of them causes undefined\n>> behavior.\n>>\n>> Unfortunately using \"void **\" in the declaration doesn't work, because\n>> C's implicit casting rules don't apply to pointer-to-pointer types.\n>\n> All true.\n>\n> I still think the macro FREEZ() is too confusing a name to live;\n> perhaps we can take Ævar's patch with s/FREEZ/FREE_AND_NULL/ and be\n> done with it?  By spelling it in all caps, readers will know that\n> there is something special going on in that macro, and Eric's\n> \"forcing the readers to type & in front to let them be aware that\n> the ptr variable is being manipulated\" may become less necessary.\n\nI'll change it to FREE_AND_NULL and submit my patch as-is, my reading\nof the rest of this thread is that making it a function instead of a\nmacro would be interesting, but has its own caveats that are likely\nbetter considered as part of its own series, whereas this just changes\nexisting code to its macro-expanded functional equivalent.\n"},{"id":"322394","messageId":"20170615210700.16310-1-avarab@gmail.com","threadId":"46082","inReplyTo":"CACBZZX7S9A=mPSgqtmVyZbLdR3GVH+ux3tGN1QXBMEzbg8Ffog@mail.gmail.com","subject":"[PATCH v3 0/2] Add a FREE_AND_NULL() wrapper macro","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-15T21:06:58Z","receivedAt":"2017-06-15T21:07:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Thu, Jun 15 2017, Ævar Arnfjörð Bjarmason jotted:\n> I'll change it to FREE_AND_NULL and submit my patch as-is, my reading\n> of the rest of this thread is that making it a function instead of a\n> macro would be interesting, but has its own caveats that are likely\n> better considered as part of its own series, whereas this just changes\n> existing code to its macro-expanded functional equivalent.\n\nHere's v3 with that change. Nothing but the macro name (and comments,\ncommit messages etc. referring to it) have changed.\n\nÆvar Arnfjörð Bjarmason (2):\n  git-compat-util: add a FREE_AND_NULL() wrapper around free(ptr); ptr =\n    NULL\n  *.[ch] refactoring: make use of the FREE_AND_NULL() macro\n\n alias.c                  |  6 ++----\n apply.c                  |  3 +--\n attr.c                   |  6 ++----\n blame.c                  |  3 +--\n branch.c                 |  3 +--\n builtin/am.c             | 18 +++++-------------\n builtin/clean.c          |  6 ++----\n builtin/config.c         |  6 ++----\n builtin/index-pack.c     |  6 ++----\n builtin/pack-objects.c   | 12 ++++--------\n builtin/unpack-objects.c |  3 +--\n builtin/worktree.c       |  6 ++----\n commit-slab.h            |  3 +--\n commit.c                 |  3 +--\n config.c                 |  3 +--\n credential.c             |  9 +++------\n diff-lib.c               |  3 +--\n diff.c                   |  6 ++----\n diffcore-rename.c        |  6 ++----\n dir.c                    |  9 +++------\n fast-import.c            |  6 ++----\n git-compat-util.h        |  6 ++++++\n gpg-interface.c          | 15 +++++----------\n grep.c                   | 12 ++++--------\n help.c                   |  3 +--\n http-push.c              | 24 ++++++++----------------\n http.c                   | 15 +++++----------\n imap-send.c              |  3 +--\n line-log.c               |  6 ++----\n ll-merge.c               |  3 +--\n mailinfo.c               |  3 +--\n object.c                 |  3 +--\n pathspec.c               |  3 +--\n prio-queue.c             |  3 +--\n read-cache.c             |  6 ++----\n ref-filter.c             |  3 +--\n refs/files-backend.c     |  3 +--\n refs/ref-cache.c         |  3 +--\n remote-testsvn.c         |  3 +--\n rerere.c                 |  3 +--\n sequencer.c              |  3 +--\n sha1-array.c             |  3 +--\n sha1_file.c              |  3 +--\n split-index.c            |  3 +--\n transport-helper.c       | 27 +++++++++------------------\n transport.c              |  3 +--\n tree-diff.c              |  6 ++----\n tree-walk.c              |  3 +--\n tree.c                   |  3 +--\n 49 files changed, 103 insertions(+), 197 deletions(-)\n\n-- \n2.13.1.508.gb3defc5cc\n\n"},{"id":"322395","messageId":"20170615210700.16310-2-avarab@gmail.com","threadId":"46082","inReplyTo":"20170615210700.16310-1-avarab@gmail.com","subject":"[PATCH v3 1/2] git-compat-util: add a FREE_AND_NULL() wrapper around free(ptr); ptr = NULL","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-15T21:06:59Z","receivedAt":"2017-06-15T21:07:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a FREE_AND_NULL() wrapper marco for the common pattern of freeing\na pointer and assigning NULL to it right afterwards.\n\nThe implementation is similar to the (currently unused) XDL_PTRFREE\nmacro in xdiff/xmacros.h added in commit 3443546f6e (\"Use a *real*\nbuilt-in diff generator\", 2006-03-24). The only difference is that\nfree() is called unconditionally, see [1].\n\nSee [2] for a suggested alternative which does this via a function\ninstead of a macro. As covered in replies to that message, while it's\na viable approach, it would introduce caveats which this approach\ndoesn't have, so that potential change is left to a future follow-up\nchange.\n\nThis merely allows us to translate exactly what we're doing now to a\nless verbose & idiomatic form using a macro, while guaranteeing that\nwe don't introduce any functional changes.\n\n1. <alpine.DEB.2.20.1608301948310.129229@virtualbox>\n   (http://public-inbox.org/git/alpine.DEB.2.20.1608301948310.129229@virtualbox/)\n\n2. <20170610032143.GA7880@starla>\n   (https://public-inbox.org/git/20170610032143.GA7880@starla/)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n git-compat-util.h | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 51ba4e6b3b..047172d173 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -808,6 +808,12 @@ extern char *xgetcwd(void);\n extern FILE *fopen_for_writing(const char *path);\n extern FILE *fopen_or_warn(const char *path, const char *mode);\n \n+/*\n+ * FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note\n+ * that ptr is used twice, so don't pass e.g. ptr++.\n+ */\n+#define FREE_AND_NULL(p) do { free(p); (p) = NULL; } while (0)\n+\n #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))\n #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))\n \n-- \n2.13.1.508.gb3defc5cc\n\n"},{"id":"322396","messageId":"20170615210700.16310-3-avarab@gmail.com","threadId":"46082","inReplyTo":"20170615210700.16310-1-avarab@gmail.com","subject":"[PATCH v3 2/2] *.[ch] refactoring: make use of the FREE_AND_NULL() macro","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-06-15T21:07:00Z","receivedAt":"2017-06-15T21:07:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Replace occurrences of `free(ptr); ptr = NULL` with\n`FREE_AND_NULL(ptr)`. This introduces no functional changes, but\nreduces the line count and establishes this pattern as a common idiom\nwith a wrapper macro.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n alias.c                  |  6 ++----\n apply.c                  |  3 +--\n attr.c                   |  6 ++----\n blame.c                  |  3 +--\n branch.c                 |  3 +--\n builtin/am.c             | 18 +++++-------------\n builtin/clean.c          |  6 ++----\n builtin/config.c         |  6 ++----\n builtin/index-pack.c     |  6 ++----\n builtin/pack-objects.c   | 12 ++++--------\n builtin/unpack-objects.c |  3 +--\n builtin/worktree.c       |  6 ++----\n commit-slab.h            |  3 +--\n commit.c                 |  3 +--\n config.c                 |  3 +--\n credential.c             |  9 +++------\n diff-lib.c               |  3 +--\n diff.c                   |  6 ++----\n diffcore-rename.c        |  6 ++----\n dir.c                    |  9 +++------\n fast-import.c            |  6 ++----\n gpg-interface.c          | 15 +++++----------\n grep.c                   | 12 ++++--------\n help.c                   |  3 +--\n http-push.c              | 24 ++++++++----------------\n http.c                   | 15 +++++----------\n imap-send.c              |  3 +--\n line-log.c               |  6 ++----\n ll-merge.c               |  3 +--\n mailinfo.c               |  3 +--\n object.c                 |  3 +--\n pathspec.c               |  3 +--\n prio-queue.c             |  3 +--\n read-cache.c             |  6 ++----\n ref-filter.c             |  3 +--\n refs/files-backend.c     |  3 +--\n refs/ref-cache.c         |  3 +--\n remote-testsvn.c         |  3 +--\n rerere.c                 |  3 +--\n sequencer.c              |  3 +--\n sha1-array.c             |  3 +--\n sha1_file.c              |  3 +--\n split-index.c            |  3 +--\n transport-helper.c       | 27 +++++++++------------------\n transport.c              |  3 +--\n tree-diff.c              |  6 ++----\n tree-walk.c              |  3 +--\n tree.c                   |  3 +--\n 48 files changed, 97 insertions(+), 197 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex 3b90397a99..911481855f 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -47,8 +47,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \t\t\t\tsrc++;\n \t\t\t\tc = cmdline[src];\n \t\t\t\tif (!c) {\n-\t\t\t\t\tfree(*argv);\n-\t\t\t\t\t*argv = NULL;\n+\t\t\t\t\tFREE_AND_NULL(*argv);\n \t\t\t\t\treturn -SPLIT_CMDLINE_BAD_ENDING;\n \t\t\t\t}\n \t\t\t}\n@@ -60,8 +59,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \tcmdline[dst] = 0;\n \n \tif (quoted) {\n-\t\tfree(*argv);\n-\t\t*argv = NULL;\n+\t\tFREE_AND_NULL(*argv);\n \t\treturn -SPLIT_CMDLINE_UNCLOSED_QUOTE;\n \t}\n \ndiff --git a/apply.c b/apply.c\nindex 854faa6779..e78de0affa 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3705,8 +3705,7 @@ static int check_preimage(struct apply_state *state,\n  is_new:\n \tpatch->is_new = 1;\n \tpatch->is_delete = 0;\n-\tfree(patch->old_name);\n-\tpatch->old_name = NULL;\n+\tFREE_AND_NULL(patch->old_name);\n \treturn 0;\n }\n \ndiff --git a/attr.c b/attr.c\nindex 821203e2a9..ebdcfb0b8a 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -638,13 +638,11 @@ void attr_check_reset(struct attr_check *check)\n \n void attr_check_clear(struct attr_check *check)\n {\n-\tfree(check->items);\n-\tcheck->items = NULL;\n+\tFREE_AND_NULL(check->items);\n \tcheck->alloc = 0;\n \tcheck->nr = 0;\n \n-\tfree(check->all_attrs);\n-\tcheck->all_attrs = NULL;\n+\tFREE_AND_NULL(check->all_attrs);\n \tcheck->all_attrs_nr = 0;\n \n \tdrop_attr_stack(&check->stack);\ndiff --git a/blame.c b/blame.c\nindex 843c845cba..1183943960 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -314,8 +314,7 @@ static void fill_origin_blob(struct diff_options *opt,\n static void drop_origin_blob(struct blame_origin *o)\n {\n \tif (o->file.ptr) {\n-\t\tfree(o->file.ptr);\n-\t\to->file.ptr = NULL;\n+\t\tFREE_AND_NULL(o->file.ptr);\n \t}\n }\n \ndiff --git a/branch.c b/branch.c\nindex 985316eb76..2347cb8649 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -24,8 +24,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)\n \t\t} else {\n \t\t\tfree(tracking->spec.src);\n \t\t\tif (tracking->src) {\n-\t\t\t\tfree(tracking->src);\n-\t\t\t\ttracking->src = NULL;\n+\t\t\t\tFREE_AND_NULL(tracking->src);\n \t\t\t}\n \t\t}\n \t\ttracking->spec.src = NULL;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 8881d73615..80368b6fe6 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -483,8 +483,7 @@ static int run_applypatch_msg_hook(struct am_state *state)\n \tret = run_hook_le(NULL, \"applypatch-msg\", am_path(state, \"final-commit\"), NULL);\n \n \tif (!ret) {\n-\t\tfree(state->msg);\n-\t\tstate->msg = NULL;\n+\t\tFREE_AND_NULL(state->msg);\n \t\tif (read_commit_msg(state) < 0)\n \t\t\tdie(_(\"'%s' was deleted by the applypatch-msg hook\"),\n \t\t\t\tam_path(state, \"final-commit\"));\n@@ -1073,17 +1072,10 @@ static void am_next(struct am_state *state)\n {\n \tstruct object_id head;\n \n-\tfree(state->author_name);\n-\tstate->author_name = NULL;\n-\n-\tfree(state->author_email);\n-\tstate->author_email = NULL;\n-\n-\tfree(state->author_date);\n-\tstate->author_date = NULL;\n-\n-\tfree(state->msg);\n-\tstate->msg = NULL;\n+\tFREE_AND_NULL(state->author_name);\n+\tFREE_AND_NULL(state->author_email);\n+\tFREE_AND_NULL(state->author_date);\n+\tFREE_AND_NULL(state->msg);\n \tstate->msg_len = 0;\n \n \tunlink(am_path(state, \"author-script\"));\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 142bf668cf..bff5a07330 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -837,8 +837,7 @@ static void interactive_main_loop(void)\n \t\t\tint ret;\n \t\t\tret = menus[*chosen].fn();\n \t\t\tif (ret != MENU_RETURN_NO_LOOP) {\n-\t\t\t\tfree(chosen);\n-\t\t\t\tchosen = NULL;\n+\t\t\t\tFREE_AND_NULL(chosen);\n \t\t\t\tif (!del_list.nr) {\n \t\t\t\t\tclean_print_color(CLEAN_COLOR_ERROR);\n \t\t\t\t\tprintf_ln(_(\"No more files to clean, exiting.\"));\n@@ -851,8 +850,7 @@ static void interactive_main_loop(void)\n \t\t\tquit_cmd();\n \t\t}\n \n-\t\tfree(chosen);\n-\t\tchosen = NULL;\n+\t\tFREE_AND_NULL(chosen);\n \t\tbreak;\n \t}\n }\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 7f6c25d4d9..18c2158630 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -214,8 +214,7 @@ static int get_value(const char *key_, const char *regex_)\n \t\tkey_regexp = (regex_t*)xmalloc(sizeof(regex_t));\n \t\tif (regcomp(key_regexp, key, REG_EXTENDED)) {\n \t\t\terror(\"invalid key pattern: %s\", key_);\n-\t\t\tfree(key_regexp);\n-\t\t\tkey_regexp = NULL;\n+\t\t\tFREE_AND_NULL(key_regexp);\n \t\t\tret = CONFIG_INVALID_PATTERN;\n \t\t\tgoto free_strings;\n \t\t}\n@@ -235,8 +234,7 @@ static int get_value(const char *key_, const char *regex_)\n \t\tregexp = (regex_t*)xmalloc(sizeof(regex_t));\n \t\tif (regcomp(regexp, regex_, REG_EXTENDED)) {\n \t\t\terror(\"invalid pattern: %s\", regex_);\n-\t\t\tfree(regexp);\n-\t\t\tregexp = NULL;\n+\t\t\tFREE_AND_NULL(regexp);\n \t\t\tret = CONFIG_INVALID_PATTERN;\n \t\t\tgoto free_strings;\n \t\t}\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 04b9dcaf0f..f3b16520c2 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -388,8 +388,7 @@ static struct base_data *alloc_base_data(void)\n static void free_base_data(struct base_data *c)\n {\n \tif (c->data) {\n-\t\tfree(c->data);\n-\t\tc->data = NULL;\n+\t\tFREE_AND_NULL(c->data);\n \t\tget_thread_data()->base_cache_used -= c->size;\n \t}\n }\n@@ -605,8 +604,7 @@ static void *unpack_data(struct object_entry *obj,\n \tgit_inflate_end(&stream);\n \tfree(inbuf);\n \tif (consume) {\n-\t\tfree(data);\n-\t\tdata = NULL;\n+\t\tFREE_AND_NULL(data);\n \t}\n \treturn data;\n }\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex f672225def..790615b2c3 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -264,8 +264,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent\n \t\t * make sure no cached delta data remains from a\n \t\t * previous attempt before a pack split occurred.\n \t\t */\n-\t\tfree(entry->delta_data);\n-\t\tentry->delta_data = NULL;\n+\t\tFREE_AND_NULL(entry->delta_data);\n \t\tentry->z_delta_size = 0;\n \t} else if (entry->delta_data) {\n \t\tsize = entry->delta_size;\n@@ -1375,12 +1374,10 @@ static void cleanup_preferred_base(void)\n \t\tif (!pbase_tree_cache[i])\n \t\t\tcontinue;\n \t\tfree(pbase_tree_cache[i]->tree_data);\n-\t\tfree(pbase_tree_cache[i]);\n-\t\tpbase_tree_cache[i] = NULL;\n+\t\tFREE_AND_NULL(pbase_tree_cache[i]);\n \t}\n \n-\tfree(done_pbase_paths);\n-\tdone_pbase_paths = NULL;\n+\tFREE_AND_NULL(done_pbase_paths);\n \tdone_pbase_paths_num = done_pbase_paths_alloc = 0;\n }\n \n@@ -1970,8 +1967,7 @@ static unsigned long free_unpacked(struct unpacked *n)\n \tn->index = NULL;\n \tif (n->data) {\n \t\tfreed_mem += n->entry->size;\n-\t\tfree(n->data);\n-\t\tn->data = NULL;\n+\t\tFREE_AND_NULL(n->data);\n \t}\n \tn->entry = NULL;\n \tn->depth = 0;\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 8bc9997767..60bfe48789 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -112,8 +112,7 @@ static void *get_data(unsigned long size)\n \t\t\tbreak;\n \t\tif (ret != Z_OK) {\n \t\t\terror(\"inflate returned %d\", ret);\n-\t\t\tfree(buf);\n-\t\t\tbuf = NULL;\n+\t\t\tFREE_AND_NULL(buf);\n \t\t\tif (!recover)\n \t\t\t\texit(1);\n \t\t\thas_errors = 1;\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 793306ea51..41d1c007a4 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -299,10 +299,8 @@ static int add_worktree(const char *path, const char *refname,\n \t}\n \n \tis_junk = 0;\n-\tfree(junk_work_tree);\n-\tfree(junk_git_dir);\n-\tjunk_work_tree = NULL;\n-\tjunk_git_dir = NULL;\n+\tFREE_AND_NULL(junk_work_tree);\n+\tFREE_AND_NULL(junk_git_dir);\n \n done:\n \tif (ret || !opts->keep_locked) {\ndiff --git a/commit-slab.h b/commit-slab.h\nindex 42d16dcded..3286c3581b 100644\n--- a/commit-slab.h\n+++ b/commit-slab.h\n@@ -82,8 +82,7 @@ static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s)\t\t\\\n \tfor (i = 0; i < s->slab_count; i++)\t\t\t\t\\\n \t\tfree(s->slab[i]);\t\t\t\t\t\\\n \ts->slab_count = 0;\t\t\t\t\t\t\\\n-\tfree(s->slab);\t\t\t\t\t\t\t\\\n-\ts->slab = NULL;\t\t\t\t\t\t\t\\\n+\tFREE_AND_NULL(s->slab);\t\t\t\t\t\t\t\\\n }\t\t\t\t\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s,\t\\\ndiff --git a/commit.c b/commit.c\nindex 99846d9bf4..cbfd689939 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -287,8 +287,7 @@ void free_commit_buffer(struct commit *commit)\n {\n \tstruct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);\n \tif (v) {\n-\t\tfree(v->buffer);\n-\t\tv->buffer = NULL;\n+\t\tFREE_AND_NULL(v->buffer);\n \t\tv->size = 0;\n \t}\n }\ndiff --git a/config.c b/config.c\nindex 34a139c40b..0501a60dd2 100644\n--- a/config.c\n+++ b/config.c\n@@ -395,8 +395,7 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \n out_free_ret_1:\n \tif (store_key) {\n-\t\tfree(*store_key);\n-\t\t*store_key = NULL;\n+\t\tFREE_AND_NULL(*store_key);\n \t}\n \treturn -CONFIG_INVALID_KEY;\n }\ndiff --git a/credential.c b/credential.c\nindex aa996669fc..924ab58538 100644\n--- a/credential.c\n+++ b/credential.c\n@@ -93,8 +93,7 @@ static void credential_apply_config(struct credential *c)\n \tc->configured = 1;\n \n \tif (!c->use_http_path && proto_is_http(c->protocol)) {\n-\t\tfree(c->path);\n-\t\tc->path = NULL;\n+\t\tFREE_AND_NULL(c->path);\n \t}\n }\n \n@@ -314,10 +313,8 @@ void credential_reject(struct credential *c)\n \tfor (i = 0; i < c->helpers.nr; i++)\n \t\tcredential_do(c, c->helpers.items[i].string, \"erase\");\n \n-\tfree(c->username);\n-\tc->username = NULL;\n-\tfree(c->password);\n-\tc->password = NULL;\n+\tFREE_AND_NULL(c->username);\n+\tFREE_AND_NULL(c->password);\n \tc->approved = 0;\n }\n \ndiff --git a/diff-lib.c b/diff-lib.c\nindex 76c8f185cd..7528f4163f 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -179,8 +179,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\t\tfree(dpath);\n \t\t\t\tcontinue;\n \t\t\t}\n-\t\t\tfree(dpath);\n-\t\t\tdpath = NULL;\n+\t\t\tFREE_AND_NULL(dpath);\n \n \t\t\t/*\n \t\t\t * Show the diff for the 'ce' if we found the one\ndiff --git a/diff.c b/diff.c\nindex e35cf6c704..3561adf49f 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1218,8 +1218,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)\n \t\t\tregfree(ecbdata->diff_words->word_regex);\n \t\t\tfree(ecbdata->diff_words->word_regex);\n \t\t}\n-\t\tfree(ecbdata->diff_words);\n-\t\tecbdata->diff_words = NULL;\n+\t\tFREE_AND_NULL(ecbdata->diff_words);\n \t}\n }\n \n@@ -2951,8 +2950,7 @@ void diff_free_filespec_blob(struct diff_filespec *s)\n void diff_free_filespec_data(struct diff_filespec *s)\n {\n \tdiff_free_filespec_blob(s);\n-\tfree(s->cnt_data);\n-\ts->cnt_data = NULL;\n+\tFREE_AND_NULL(s->cnt_data);\n }\n \n static void prep_temp_blob(const char *path, struct diff_tempfile *temp,\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex f7444c86bd..6d8daf9c00 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -667,11 +667,9 @@ void diffcore_rename(struct diff_options *options)\n \tfor (i = 0; i < rename_dst_nr; i++)\n \t\tfree_filespec(rename_dst[i].two);\n \n-\tfree(rename_dst);\n-\trename_dst = NULL;\n+\tFREE_AND_NULL(rename_dst);\n \trename_dst_nr = rename_dst_alloc = 0;\n-\tfree(rename_src);\n-\trename_src = NULL;\n+\tFREE_AND_NULL(rename_src);\n \trename_src_nr = rename_src_alloc = 0;\n \treturn;\n }\ndiff --git a/dir.c b/dir.c\nindex 1759063817..7dc168b806 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2117,8 +2117,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,\n \t\tfor (i = j = 0; j < dir->nr; j++) {\n \t\t\tif (i &&\n \t\t\t    check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) {\n-\t\t\t\tfree(dir->entries[j]);\n-\t\t\t\tdir->entries[j] = NULL;\n+\t\t\t\tFREE_AND_NULL(dir->entries[j]);\n \t\t\t} else {\n \t\t\t\tdir->entries[i++] = dir->entries[j];\n \t\t\t}\n@@ -2144,8 +2143,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,\n \t\t     dir->untracked->dir_invalidated))\n \t\t\tistate->cache_changed |= UNTRACKED_CHANGED;\n \t\tif (dir->untracked != istate->untracked) {\n-\t\t\tfree(dir->untracked);\n-\t\t\tdir->untracked = NULL;\n+\t\t\tFREE_AND_NULL(dir->untracked);\n \t\t}\n \t}\n \treturn dir->nr;\n@@ -2488,8 +2486,7 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra\n \tstrbuf_addbuf(out, &untracked->ident);\n \n \tstrbuf_add(out, ouc, ouc_size(len));\n-\tfree(ouc);\n-\touc = NULL;\n+\tFREE_AND_NULL(ouc);\n \n \tif (!untracked->root) {\n \t\tvarint_len = encode_varint(0, varbuf);\ndiff --git a/fast-import.c b/fast-import.c\nindex 9a22fc92c0..eeab927d5a 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1063,8 +1063,7 @@ static void end_packfile(void)\n \t\tclose(pack_data->pack_fd);\n \t\tunlink_or_warn(pack_data->pack_name);\n \t}\n-\tfree(pack_data);\n-\tpack_data = NULL;\n+\tFREE_AND_NULL(pack_data);\n \trunning = 0;\n \n \t/* We can't carry a delta across packfiles. */\n@@ -1149,8 +1148,7 @@ static int store_object(\n \n \t\t/* We cannot carry a delta into the new pack. */\n \t\tif (delta) {\n-\t\t\tfree(delta);\n-\t\t\tdelta = NULL;\n+\t\t\tFREE_AND_NULL(delta);\n \n \t\t\tgit_deflate_init(&s, pack_compression_level);\n \t\t\ts.next_in = (void *)dat->buf;\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex e44cc27da1..3f377f89d0 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -13,16 +13,11 @@ static const char *gpg_program = \"gpg\";\n \n void signature_check_clear(struct signature_check *sigc)\n {\n-\tfree(sigc->payload);\n-\tfree(sigc->gpg_output);\n-\tfree(sigc->gpg_status);\n-\tfree(sigc->signer);\n-\tfree(sigc->key);\n-\tsigc->payload = NULL;\n-\tsigc->gpg_output = NULL;\n-\tsigc->gpg_status = NULL;\n-\tsigc->signer = NULL;\n-\tsigc->key = NULL;\n+\tFREE_AND_NULL(sigc->payload);\n+\tFREE_AND_NULL(sigc->gpg_output);\n+\tFREE_AND_NULL(sigc->gpg_status);\n+\tFREE_AND_NULL(sigc->signer);\n+\tFREE_AND_NULL(sigc->key);\n }\n \n static struct {\ndiff --git a/grep.c b/grep.c\nindex d03d424e5c..909f35a984 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1763,12 +1763,9 @@ void grep_source_init(struct grep_source *gs, enum grep_source_type type,\n \n void grep_source_clear(struct grep_source *gs)\n {\n-\tfree(gs->name);\n-\tgs->name = NULL;\n-\tfree(gs->path);\n-\tgs->path = NULL;\n-\tfree(gs->identifier);\n-\tgs->identifier = NULL;\n+\tFREE_AND_NULL(gs->name);\n+\tFREE_AND_NULL(gs->path);\n+\tFREE_AND_NULL(gs->identifier);\n \tgrep_source_clear_data(gs);\n }\n \n@@ -1778,8 +1775,7 @@ void grep_source_clear_data(struct grep_source *gs)\n \tcase GREP_SOURCE_FILE:\n \tcase GREP_SOURCE_SHA1:\n \tcase GREP_SOURCE_SUBMODULE:\n-\t\tfree(gs->buf);\n-\t\tgs->buf = NULL;\n+\t\tFREE_AND_NULL(gs->buf);\n \t\tgs->size = 0;\n \t\tbreak;\n \tcase GREP_SOURCE_BUF:\ndiff --git a/help.c b/help.c\nindex db7f3d79a0..a2f48c0df3 100644\n--- a/help.c\n+++ b/help.c\n@@ -267,9 +267,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n \n \tfor (i = 0; i < old->cnt; i++)\n \t\tcmds->names[cmds->cnt++] = old->names[i];\n-\tfree(old->names);\n+\tFREE_AND_NULL(old->names);\n \told->cnt = 0;\n-\told->names = NULL;\n }\n \n /* An empirically derived magic number */\ndiff --git a/http-push.c b/http-push.c\nindex 67c4d4b472..c91f40a610 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -291,8 +291,7 @@ static void start_mkcol(struct transfer_request *request)\n \t\trequest->state = RUN_MKCOL;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tFREE_AND_NULL(request->url);\n \t}\n }\n #endif\n@@ -409,8 +408,7 @@ static void start_put(struct transfer_request *request)\n \t\trequest->state = RUN_PUT;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tFREE_AND_NULL(request->url);\n \t}\n }\n \n@@ -432,8 +430,7 @@ static void start_move(struct transfer_request *request)\n \t\trequest->state = RUN_MOVE;\n \t} else {\n \t\trequest->state = ABORTED;\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tFREE_AND_NULL(request->url);\n \t}\n }\n \n@@ -526,8 +523,7 @@ static void finish_request(struct transfer_request *request)\n \n \t/* URL is reused for MOVE after PUT */\n \tif (request->state != RUN_PUT) {\n-\t\tfree(request->url);\n-\t\trequest->url = NULL;\n+\t\tFREE_AND_NULL(request->url);\n \t}\n \n \tif (request->state == RUN_MKCOL) {\n@@ -803,8 +799,7 @@ xml_start_tag(void *userData, const char *name, const char **atts)\n \t}\n \txsnprintf(ctx->name + old_namelen, ctx->len - old_namelen, \".%s\", c);\n \n-\tfree(ctx->cdata);\n-\tctx->cdata = NULL;\n+\tFREE_AND_NULL(ctx->cdata);\n \n \tctx->userFunc(ctx, 0);\n }\n@@ -932,8 +927,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)\n \t\tfree(lock->token);\n \t\tfree(lock->owner);\n \t\tfree(url);\n-\t\tfree(lock);\n-\t\tlock = NULL;\n+\t\tFREE_AND_NULL(lock);\n \t} else {\n \t\tlock->url = url;\n \t\tlock->start_time = time(NULL);\n@@ -1105,8 +1099,7 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)\n \t\t\tls->dentry_flags |= IS_DIR;\n \t\t}\n \t} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {\n-\t\tfree(ls->dentry_name);\n-\t\tls->dentry_name = NULL;\n+\t\tFREE_AND_NULL(ls->dentry_name);\n \t\tls->dentry_flags = 0;\n \t}\n }\n@@ -1547,8 +1540,7 @@ static void fetch_symref(const char *path, char **symref, struct object_id *oid)\n \t\t    curl_errorstr);\n \tfree(url);\n \n-\tfree(*symref);\n-\t*symref = NULL;\n+\tFREE_AND_NULL(*symref);\n \toidclr(oid);\n \n \tif (buffer.len == 0)\ndiff --git a/http.c b/http.c\nindex d2e11ec6f0..77f46bef0f 100644\n--- a/http.c\n+++ b/http.c\n@@ -1026,8 +1026,7 @@ void http_cleanup(void)\n \n \tif (proxy_auth.password) {\n \t\tmemset(proxy_auth.password, 0, strlen(proxy_auth.password));\n-\t\tfree(proxy_auth.password);\n-\t\tproxy_auth.password = NULL;\n+\t\tFREE_AND_NULL(proxy_auth.password);\n \t}\n \n \tfree((void *)curl_proxyuserpwd);\n@@ -1038,13 +1037,11 @@ void http_cleanup(void)\n \n \tif (cert_auth.password != NULL) {\n \t\tmemset(cert_auth.password, 0, strlen(cert_auth.password));\n-\t\tfree(cert_auth.password);\n-\t\tcert_auth.password = NULL;\n+\t\tFREE_AND_NULL(cert_auth.password);\n \t}\n \tssl_cert_password_required = 0;\n \n-\tfree(cached_accept_language);\n-\tcached_accept_language = NULL;\n+\tFREE_AND_NULL(cached_accept_language);\n }\n \n struct active_request_slot *get_active_slot(void)\n@@ -1896,8 +1893,7 @@ static char *fetch_pack_index(unsigned char *sha1, const char *base_url)\n \n \tif (http_get_file(url, tmp, NULL) != HTTP_OK) {\n \t\terror(\"Unable to get pack index %s\", url);\n-\t\tfree(tmp);\n-\t\ttmp = NULL;\n+\t\tFREE_AND_NULL(tmp);\n \t}\n \n \tfree(url);\n@@ -2328,8 +2324,7 @@ void release_http_object_request(struct http_object_request *freq)\n \t\tfreq->localfile = -1;\n \t}\n \tif (freq->url != NULL) {\n-\t\tfree(freq->url);\n-\t\tfreq->url = NULL;\n+\t\tFREE_AND_NULL(freq->url);\n \t}\n \tif (freq->slot != NULL) {\n \t\tfreq->slot->callback_func = NULL;\ndiff --git a/imap-send.c b/imap-send.c\nindex 857591660f..40ddb496e6 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -776,8 +776,7 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)\n \t\t\t       offsetof(struct imap_cmd, next));\n \t\t\tif (cmdp->cb.data) {\n \t\t\t\tn = socket_write(&imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen);\n-\t\t\t\tfree(cmdp->cb.data);\n-\t\t\t\tcmdp->cb.data = NULL;\n+\t\t\t\tFREE_AND_NULL(cmdp->cb.data);\n \t\t\t\tif (n != (int)cmdp->cb.dlen)\n \t\t\t\t\treturn RESP_BAD;\n \t\t\t} else if (cmdp->cb.cont) {\ndiff --git a/line-log.c b/line-log.c\nindex b9087814b8..2d60c347ca 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -34,9 +34,8 @@ void range_set_init(struct range_set *rs, size_t prealloc)\n \n void range_set_release(struct range_set *rs)\n {\n-\tfree(rs->ranges);\n+\tFREE_AND_NULL(rs->ranges);\n \trs->alloc = rs->nr = 0;\n-\trs->ranges = NULL;\n }\n \n /* dst must be uninitialized! */\n@@ -610,8 +609,7 @@ parse_lines(struct commit *commit, const char *prefix, struct string_list *args)\n \t\tline_log_data_insert(&ranges, full_name, begin, end);\n \n \t\tfree_filespec(spec);\n-\t\tfree(ends);\n-\t\tends = NULL;\n+\t\tFREE_AND_NULL(ends);\n \t}\n \n \tfor (p = ranges; p; p = p->next)\ndiff --git a/ll-merge.c b/ll-merge.c\nindex ac0d4a5d78..91ff519cef 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -209,8 +209,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \tresult->size = st.st_size;\n \tresult->ptr = xmallocz(result->size);\n \tif (read_in_full(fd, result->ptr, result->size) != result->size) {\n-\t\tfree(result->ptr);\n-\t\tresult->ptr = NULL;\n+\t\tFREE_AND_NULL(result->ptr);\n \t\tresult->size = 0;\n \t}\n  close_bad:\ndiff --git a/mailinfo.c b/mailinfo.c\nindex f92cb9f729..44f829edb1 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -919,8 +919,7 @@ static int handle_boundary(struct mailinfo *mi, struct strbuf *line)\n \t\t/* we hit an end boundary */\n \t\t/* pop the current boundary off the stack */\n \t\tstrbuf_release(*(mi->content_top));\n-\t\tfree(*(mi->content_top));\n-\t\t*(mi->content_top) = NULL;\n+\t\tFREE_AND_NULL(*(mi->content_top));\n \n \t\t/* technically won't happen as is_multipart_boundary()\n \t\t   will fail first.  But just in case..\ndiff --git a/object.c b/object.c\nindex 06ba3a11d8..f818777412 100644\n--- a/object.c\n+++ b/object.c\n@@ -377,8 +377,7 @@ void object_array_clear(struct object_array *array)\n \tint i;\n \tfor (i = 0; i < array->nr; i++)\n \t\tobject_array_release_entry(&array->objects[i]);\n-\tfree(array->objects);\n-\tarray->objects = NULL;\n+\tFREE_AND_NULL(array->objects);\n \tarray->nr = array->alloc = 0;\n }\n \ndiff --git a/pathspec.c b/pathspec.c\nindex 828405021f..54aab8bc01 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -662,7 +662,6 @@ void clear_pathspec(struct pathspec *pathspec)\n \t\t\tattr_check_free(pathspec->items[i].attr_check);\n \t}\n \n-\tfree(pathspec->items);\n-\tpathspec->items = NULL;\n+\tFREE_AND_NULL(pathspec->items);\n \tpathspec->nr = 0;\n }\ndiff --git a/prio-queue.c b/prio-queue.c\nindex fc3860fdcb..126d096727 100644\n--- a/prio-queue.c\n+++ b/prio-queue.c\n@@ -27,10 +27,9 @@ void prio_queue_reverse(struct prio_queue *queue)\n \n void clear_prio_queue(struct prio_queue *queue)\n {\n-\tfree(queue->array);\n+\tFREE_AND_NULL(queue->array);\n \tqueue->nr = 0;\n \tqueue->alloc = 0;\n-\tqueue->array = NULL;\n \tqueue->insertion_ctr = 0;\n }\n \ndiff --git a/read-cache.c b/read-cache.c\nindex bc156a133e..66c413657e 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1888,8 +1888,7 @@ int discard_index(struct index_state *istate)\n \tfree_name_hash(istate);\n \tcache_tree_free(&(istate->cache_tree));\n \tistate->initialized = 0;\n-\tfree(istate->cache);\n-\tistate->cache = NULL;\n+\tFREE_AND_NULL(istate->cache);\n \tistate->cache_alloc = 0;\n \tdiscard_split_index(istate);\n \tfree_untracked_cache(istate->untracked);\n@@ -2603,8 +2602,7 @@ void *read_blob_data_from_index(const struct index_state *istate,\n \n void stat_validity_clear(struct stat_validity *sv)\n {\n-\tfree(sv->sd);\n-\tsv->sd = NULL;\n+\tFREE_AND_NULL(sv->sd);\n }\n \n int stat_validity_check(struct stat_validity *sv, const char *path)\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ab32bc9c31..72e6cb8ecc 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1891,8 +1891,7 @@ void ref_array_clear(struct ref_array *array)\n \n \tfor (i = 0; i < array->nr; i++)\n \t\tfree_array_item(array->items[i]);\n-\tfree(array->items);\n-\tarray->items = NULL;\n+\tFREE_AND_NULL(array->items);\n \tarray->nr = array->alloc = 0;\n }\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex d8b3f73147..c1bd99d60f 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2944,8 +2944,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,\n \t\t\t\t       head_oid.hash, &head_type);\n \n \tif (head_ref && !(head_type & REF_ISSYMREF)) {\n-\t\tfree(head_ref);\n-\t\thead_ref = NULL;\n+\t\tFREE_AND_NULL(head_ref);\n \t}\n \n \t/*\ndiff --git a/refs/ref-cache.c b/refs/ref-cache.c\nindex af2fcb2c12..76bb723c86 100644\n--- a/refs/ref-cache.c\n+++ b/refs/ref-cache.c\n@@ -82,9 +82,8 @@ static void clear_ref_dir(struct ref_dir *dir)\n \tint i;\n \tfor (i = 0; i < dir->nr; i++)\n \t\tfree_ref_entry(dir->entries[i]);\n-\tfree(dir->entries);\n+\tFREE_AND_NULL(dir->entries);\n \tdir->sorted = dir->nr = dir->alloc = 0;\n-\tdir->entries = NULL;\n }\n \n struct ref_entry *create_dir_entry(struct ref_cache *cache,\ndiff --git a/remote-testsvn.c b/remote-testsvn.c\nindex 50404ef343..078b0c3139 100644\n--- a/remote-testsvn.c\n+++ b/remote-testsvn.c\n@@ -66,8 +66,7 @@ static char *read_ref_note(const unsigned char sha1[20])\n \telse if (!msglen || type != OBJ_BLOB) {\n \t\terror(\"Note contains unusable content. \"\n \t\t\t\"Is something else using this notes tree? %s\", notes_ref);\n-\t\tfree(msg);\n-\t\tmsg = NULL;\n+\t\tFREE_AND_NULL(msg);\n \t}\n \tfree_notes(NULL);\n \treturn msg;\ndiff --git a/rerere.c b/rerere.c\nindex c26c29f87a..61f3804a1e 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -39,9 +39,8 @@ static void free_rerere_dirs(void)\n \t\tfree(rerere_dir[i]->status);\n \t\tfree(rerere_dir[i]);\n \t}\n-\tfree(rerere_dir);\n+\tFREE_AND_NULL(rerere_dir);\n \trerere_dir_nr = rerere_dir_alloc = 0;\n-\trerere_dir = NULL;\n }\n \n static void free_rerere_id(struct string_list_item *item)\ndiff --git a/sequencer.c b/sequencer.c\nindex 5282fb849c..070b42f240 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1211,8 +1211,7 @@ struct todo_list {\n static void todo_list_release(struct todo_list *todo_list)\n {\n \tstrbuf_release(&todo_list->buf);\n-\tfree(todo_list->items);\n-\ttodo_list->items = NULL;\n+\tFREE_AND_NULL(todo_list->items);\n \ttodo_list->nr = todo_list->alloc = 0;\n }\n \ndiff --git a/sha1-array.c b/sha1-array.c\nindex 7d646ab5b8..838b3bf847 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -35,8 +35,7 @@ int oid_array_lookup(struct oid_array *array, const struct object_id *oid)\n \n void oid_array_clear(struct oid_array *array)\n {\n-\tfree(array->oid);\n-\tarray->oid = NULL;\n+\tFREE_AND_NULL(array->oid);\n \tarray->nr = 0;\n \tarray->alloc = 0;\n \tarray->sorted = 0;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 59a4ed2ed3..d67c88bb8d 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -610,8 +610,7 @@ char *compute_alternate_path(const char *path, struct strbuf *err)\n \n out:\n \tif (seen_error) {\n-\t\tfree(ref_git);\n-\t\tref_git = NULL;\n+\t\tFREE_AND_NULL(ref_git);\n \t}\n \n \treturn ref_git;\ndiff --git a/split-index.c b/split-index.c\nindex 49bd197f71..20477c6a48 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -174,10 +174,9 @@ void merge_base_index(struct index_state *istate)\n \n \tewah_free(si->delete_bitmap);\n \tewah_free(si->replace_bitmap);\n-\tfree(si->saved_cache);\n+\tFREE_AND_NULL(si->saved_cache);\n \tsi->delete_bitmap  = NULL;\n \tsi->replace_bitmap = NULL;\n-\tsi->saved_cache\t   = NULL;\n \tsi->saved_cache_nr = 0;\n }\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex 36408046eb..33cff38cc0 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -242,8 +242,7 @@ static int disconnect_helper(struct transport *transport)\n \t\tclose(data->helper->out);\n \t\tfclose(data->out);\n \t\tres = finish_command(data->helper);\n-\t\tfree(data->helper);\n-\t\tdata->helper = NULL;\n+\t\tFREE_AND_NULL(data->helper);\n \t}\n \treturn res;\n }\n@@ -711,43 +710,35 @@ static int push_update_ref_status(struct strbuf *buf,\n \n \t\tif (!strcmp(msg, \"no match\")) {\n \t\t\tstatus = REF_STATUS_NONE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREE_AND_NULL(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"up to date\")) {\n \t\t\tstatus = REF_STATUS_UPTODATE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREE_AND_NULL(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"non-fast forward\")) {\n \t\t\tstatus = REF_STATUS_REJECT_NONFASTFORWARD;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREE_AND_NULL(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"already exists\")) {\n \t\t\tstatus = REF_STATUS_REJECT_ALREADY_EXISTS;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREE_AND_NULL(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"fetch first\")) {\n \t\t\tstatus = REF_STATUS_REJECT_FETCH_FIRST;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREE_AND_NULL(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"needs force\")) {\n \t\t\tstatus = REF_STATUS_REJECT_NEEDS_FORCE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREE_AND_NULL(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"stale info\")) {\n \t\t\tstatus = REF_STATUS_REJECT_STALE;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREE_AND_NULL(msg);\n \t\t}\n \t\telse if (!strcmp(msg, \"forced update\")) {\n \t\t\tforced = 1;\n-\t\t\tfree(msg);\n-\t\t\tmsg = NULL;\n+\t\t\tFREE_AND_NULL(msg);\n \t\t}\n \t}\n \ndiff --git a/transport.c b/transport.c\nindex 9bfcf870f9..cf35088001 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1145,8 +1145,7 @@ void transport_unlock_pack(struct transport *transport)\n {\n \tif (transport->pack_lockfile) {\n \t\tunlink_or_warn(transport->pack_lockfile);\n-\t\tfree(transport->pack_lockfile);\n-\t\ttransport->pack_lockfile = NULL;\n+\t\tFREE_AND_NULL(transport->pack_lockfile);\n \t}\n }\n \ndiff --git a/tree-diff.c b/tree-diff.c\nindex e164e532b2..1e1b393d08 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -140,8 +140,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,\n \t/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */\n \tp = last->next;\n \tif (p && (alloclen > (intptr_t)p->next)) {\n-\t\tfree(p);\n-\t\tp = NULL;\n+\t\tFREE_AND_NULL(p);\n \t}\n \n \tif (!p) {\n@@ -559,8 +558,7 @@ struct combine_diff_path *diff_tree_paths(\n \t * (see path_appendnew() for details about why)\n \t */\n \tif (p->next) {\n-\t\tfree(p->next);\n-\t\tp->next = NULL;\n+\t\tFREE_AND_NULL(p->next);\n \t}\n \n \treturn p;\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 6a42e402b0..9f67b89c87 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -479,8 +479,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)\n \tfor (i = 0; i < n; i++)\n \t\tfree_extended_entry(tx + i);\n \tfree(tx);\n-\tfree(traverse_path);\n-\tinfo->traverse_path = NULL;\n+\tFREE_AND_NULL(traverse_path);\n \tstrbuf_release(&base);\n \treturn error;\n }\ndiff --git a/tree.c b/tree.c\nindex 603b29ee80..614f91586d 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -226,8 +226,7 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \n void free_tree_buffer(struct tree *tree)\n {\n-\tfree(tree->buffer);\n-\ttree->buffer = NULL;\n+\tFREE_AND_NULL(tree->buffer);\n \ttree->size = 0;\n \ttree->object.parsed = 0;\n }\n-- \n2.13.1.508.gb3defc5cc\n\n"},{"id":"322406","messageId":"xmqqa858zzb3.fsf@gitster.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170615210700.16310-1-avarab@gmail.com","subject":"Re: [PATCH v3 0/2] Add a FREE_AND_NULL() wrapper macro","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-15T22:00:32Z","receivedAt":"2017-06-15T22:00:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> On Thu, Jun 15 2017, Ævar Arnfjörð Bjarmason jotted:\n>> I'll change it to FREE_AND_NULL and submit my patch as-is, my reading\n>> of the rest of this thread is that making it a function instead of a\n>> macro would be interesting, but has its own caveats that are likely\n>> better considered as part of its own series, whereas this just changes\n>> existing code to its macro-expanded functional equivalent.\n>\n> Here's v3 with that change. Nothing but the macro name (and comments,\n> commit messages etc. referring to it) have changed.\n>\n> Ævar Arnfjörð Bjarmason (2):\n>   git-compat-util: add a FREE_AND_NULL() wrapper around free(ptr); ptr =\n>     NULL\n>   *.[ch] refactoring: make use of the FREE_AND_NULL() macro\n\nThanks.\n\nPerhaps somebody wants to do a follow-up patch on top of these two\npatches to add .cocci rule e.g.\n\n\t@@\n\ttype T;\n\tT *ptr;\n\t@@\n\t- free(ptr);\n\t- ptr = NULL;\n\t+ FREE_AND_NULL(ptr);\n\nso that we can periodically sweep new candidates, to which this\nmacro can be applied?\n"},{"id":"322757","messageId":"20170620191951.84791-1-bmwill@google.com","threadId":"46082","inReplyTo":"20170608234100.188529-1-bmwill@google.com","subject":"[PATCH v3 00/20] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:31Z","receivedAt":"2017-06-20T19:23:05Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"I decided to split up the original series into three parts in order to make\nreview a little bit easier.  As such this series is dependent on on\n'bw/config-h' and 'bw/ls-files-sans-the-index' which should be moving into\n'next' soon.  Due to this I was able to greatly shrink this series in terms of\nnumber of patches so hopefully it is a little easier to review.\n\nAs before you can find this series at:\nhttps://github.com/bmwill/git/tree/repository-object\n\nChagnes in v3:\n\n * Once v2 was merged to 'pu' a bug was discovered in how the 'do_git_path'\n   function handled worktree's.  v3 addresses this by ensuring to only replace\n   'gitdir/index' with 'repository->index_file' when not operating specifically\n   on a 'struct worktree'.\n\n * Added a bunch of path related functions to facilitate construction of paths\n   into a repository's gitdir or in a repository's worktree.\n\n * Added an additional initialization function to allow initializing a 'struct\n   repository' as a submodule of another 'struct repository'.\n\nBrandon Williams (20):\n  setup: don't perform lazy initialization of repository state\n  setup: add comment indicating a hack\n  environment: remove namespace_len variable\n  repository: introduce the repository object\n  environment: place key repository state in the_repository\n  environment: store worktree in the_repository\n  path: create path.h\n  path: always pass in commondir to update_common_dir\n  path: convert strbuf_git_common_path to take a 'struct repository'\n  path: convert do_git_path to take a 'struct repository'\n  path: construct correct path to a worktree's index\n  path: add repo_git_path and strbuf_repo_git_path\n  path: add repo_worktree_path and strbuf_repo_worktree_path\n  config: read config from a repository object\n  repository: add index_state to struct repo\n  submodule-config: store the_submodule_cache in the_repository\n  submodule: add repo_read_gitmodules\n  submodule: convert is_submodule_initialized to work on a repository\n  repository: enable initialization of submodules\n  ls-files: use repository object\n\n Makefile                               |   1 +\n builtin/grep.c                         |   3 +-\n builtin/ls-files.c                     | 195 +++++++++++---------------\n builtin/submodule--helper.c            |   9 +-\n cache.h                                |  62 +--------\n config.c                               | 216 +++++++++++++++++++----------\n config.h                               |  24 ++++\n environment.c                          |  91 ++++--------\n git.c                                  |   2 +-\n path.c                                 | 136 ++++++++++++++----\n path.h                                 |  82 +++++++++++\n repository.c                           | 245 +++++++++++++++++++++++++++++++++\n repository.h                           |  76 ++++++++++\n setup.c                                |  33 +++++\n submodule-config.c                     |  70 +++++++---\n submodule-config.h                     |  10 ++\n submodule.c                            |  35 +++--\n submodule.h                            |   4 +-\n t/t3007-ls-files-recurse-submodules.sh |  39 ++++++\n worktree.c                             |   3 +-\n 20 files changed, 962 insertions(+), 374 deletions(-)\n create mode 100644 path.h\n create mode 100644 repository.c\n create mode 100644 repository.h\n\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322758","messageId":"20170620191951.84791-5-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 04/20] repository: introduce the repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:35Z","receivedAt":"2017-06-20T19:23:07Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce the repository object 'struct repository' which can be used to\nhold all state pertaining to a git repository.\n\nSome of the benefits of object-ifying a repository are:\n\n  1. Make the code base more readable and easier to reason about.\n\n  2. Allow for working on multiple repositories, specifically\n     submodules, within the same process.  Currently the process for\n     working on a submodule involves setting up an argv_array of options\n     for a particular command and then launching a child process to\n     execute the command in the context of the submodule.  This is\n     clunky and can require lots of little hacks in order to ensure\n     correctness.  Ideally it would be nice to simply pass a repository\n     and an options struct to a command.\n\n  3. Eliminating reliance on global state will make it easier to\n     enable the use of threading to improve performance.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Makefile     |   1 +\n repository.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n repository.h |  46 ++++++++++++++++\n 3 files changed, 219 insertions(+)\n create mode 100644 repository.c\n create mode 100644 repository.h\n\ndiff --git a/Makefile b/Makefile\nindex f48480163..32e4efc71 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -839,6 +839,7 @@ LIB_OBJS += refs/ref-cache.o\n LIB_OBJS += ref-filter.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\n+LIB_OBJS += repository.o\n LIB_OBJS += rerere.o\n LIB_OBJS += resolve-undo.o\n LIB_OBJS += revision.o\ndiff --git a/repository.c b/repository.c\nnew file mode 100644\nindex 000000000..7c8a7728c\n--- /dev/null\n+++ b/repository.c\n@@ -0,0 +1,172 @@\n+#include \"cache.h\"\n+#include \"repository.h\"\n+\n+/* The main repository */\n+static struct repository the_repo;\n+struct repository *the_repository = &the_repo;\n+\n+static char *git_path_from_env(const char *envvar, const char *git_dir,\n+\t\t\t       const char *path, int fromenv)\n+{\n+\tif (fromenv) {\n+\t\tconst char *value = getenv(envvar);\n+\t\tif (value)\n+\t\t\treturn xstrdup(value);\n+\t}\n+\n+\treturn xstrfmt(\"%s/%s\", git_dir, path);\n+}\n+\n+static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)\n+{\n+\tif (fromenv) {\n+\t\tconst char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n+\t\tif (value) {\n+\t\t\tstrbuf_addstr(sb, value);\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\n+\treturn get_common_dir_noenv(sb, gitdir);\n+}\n+\n+/* called after setting gitdir */\n+static void repo_setup_env(struct repository *repo)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tif (!repo->gitdir)\n+\t\tBUG(\"gitdir wasn't set before setting up the environment\");\n+\n+\trepo->different_commondir = find_common_dir(&sb, repo->gitdir,\n+\t\t\t\t\t\t    !repo->ignore_env);\n+\trepo->commondir = strbuf_detach(&sb, NULL);\n+\trepo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,\n+\t\t\t\t\t    \"objects\", !repo->ignore_env);\n+\trepo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,\n+\t\t\t\t\t     \"info/grafts\", !repo->ignore_env);\n+\trepo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,\n+\t\t\t\t\t     \"index\", !repo->ignore_env);\n+}\n+\n+void repo_set_gitdir(struct repository *repo, const char *path)\n+{\n+\tconst char *gitfile = read_gitfile(path);\n+\n+\t/*\n+\t * NEEDSWORK: Eventually we want to be able to free gitdir and the rest\n+\t * of the environment before reinitializing it again, but we have some\n+\t * crazy code paths where we try to set gitdir with the current gitdir\n+\t * and we don't want to free gitdir before copying the passed in value.\n+\t */\n+\trepo->gitdir = xstrdup(gitfile ? gitfile : path);\n+\n+\trepo_setup_env(repo);\n+}\n+\n+/*\n+ * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.\n+ * Return 0 upon success and a non-zero value upon failure.\n+ */\n+static int repo_init_gitdir(struct repository *repo, const char *gitdir)\n+{\n+\tint ret = 0;\n+\tint error = 0;\n+\tchar *abspath = NULL;\n+\tchar *suspect = NULL;\n+\tconst char *resolved_gitdir;\n+\n+\tabspath = real_pathdup(gitdir, 0);\n+\tif (!abspath) {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\t/* First assume 'gitdir' references the gitdir directly */\n+\tresolved_gitdir = resolve_gitdir_gently(abspath, &error);\n+\t/* otherwise; try 'gitdir'.git */\n+\tif (!resolved_gitdir) {\n+\t\tsuspect = xstrfmt(\"%s/.git\", abspath);\n+\t\tresolved_gitdir = resolve_gitdir_gently(suspect, &error);\n+\t\tif (!resolved_gitdir) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\t}\n+\n+\trepo_set_gitdir(repo, resolved_gitdir);\n+\n+out:\n+\tfree(abspath);\n+\tfree(suspect);\n+\treturn ret;\n+}\n+\n+void repo_set_worktree(struct repository *repo, const char *path)\n+{\n+\trepo->worktree = real_pathdup(path, 1);\n+}\n+\n+static int verify_repo_format(struct repository_format *format,\n+\t\t\t      const char *commondir)\n+{\n+\tint ret = 0;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tstrbuf_addf(&sb, \"%s/config\", commondir);\n+\tread_repository_format(format, sb.buf);\n+\tstrbuf_reset(&sb);\n+\n+\tif (verify_repository_format(format, &sb) < 0) {\n+\t\twarning(\"%s\", sb.buf);\n+\t\tret = -1;\n+\t}\n+\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n+/*\n+ * Initialize 'repo' based on the provided 'gitdir'.\n+ * Return 0 upon success and a non-zero value upon failure.\n+ */\n+int repo_init(struct repository *repo, const char *gitdir, const char *worktree)\n+{\n+\tstruct repository_format format;\n+\tmemset(repo, 0, sizeof(*repo));\n+\n+\trepo->ignore_env = 1;\n+\n+\tif (repo_init_gitdir(repo, gitdir))\n+\t\tgoto error;\n+\n+\tif (verify_repo_format(&format, repo->commondir))\n+\t\tgoto error;\n+\n+\tif (worktree)\n+\t\trepo_set_worktree(repo, worktree);\n+\n+\treturn 0;\n+\n+error:\n+\trepo_clear(repo);\n+\treturn -1;\n+}\n+\n+void repo_clear(struct repository *repo)\n+{\n+\tfree(repo->gitdir);\n+\trepo->gitdir = NULL;\n+\tfree(repo->commondir);\n+\trepo->commondir = NULL;\n+\tfree(repo->objectdir);\n+\trepo->objectdir = NULL;\n+\tfree(repo->graft_file);\n+\trepo->graft_file = NULL;\n+\tfree(repo->index_file);\n+\trepo->index_file = NULL;\n+\tfree(repo->worktree);\n+\trepo->worktree = NULL;\n+\n+\tmemset(repo, 0, sizeof(*repo));\n+}\ndiff --git a/repository.h b/repository.h\nnew file mode 100644\nindex 000000000..ab1744d51\n--- /dev/null\n+++ b/repository.h\n@@ -0,0 +1,46 @@\n+#ifndef REPOSITORY_H\n+#define REPOSITORY_H\n+\n+struct repository {\n+\t/* Environment */\n+\t/* Path to the git directory */\n+\tchar *gitdir;\n+\n+\t/* Path to the common git directory */\n+\tchar *commondir;\n+\n+\t/* Path to the repository's object store */\n+\tchar *objectdir;\n+\n+\t/* Path to the repository's graft file */\n+\tchar *graft_file;\n+\n+\t/* Path to the current worktree's index file */\n+\tchar *index_file;\n+\n+\t/* Path to the working directory */\n+\tchar *worktree;\n+\n+\t/* Configurations */\n+\t/*\n+\t * Bit used during initialization to indicate if repository state (like\n+\t * the location of the 'objectdir') should be read from the\n+\t * environment.  By default this bit will be set at the begining of\n+\t * 'repo_init()' so that all repositories will ignore the environment.\n+\t * The exception to this is 'the_repository', which doesn't go through\n+\t * the normal 'repo_init()' process.\n+\t */\n+\tunsigned ignore_env:1;\n+\n+\t/* Indicate if a repository has a different 'commondir' from 'gitdir' */\n+\tunsigned different_commondir:1;\n+};\n+\n+extern struct repository *the_repository;\n+\n+extern void repo_set_gitdir(struct repository *repo, const char *path);\n+extern void repo_set_worktree(struct repository *repo, const char *path);\n+extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);\n+extern void repo_clear(struct repository *repo);\n+\n+#endif /* REPOSITORY_H */\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322759","messageId":"20170620191951.84791-16-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 15/20] repository: add index_state to struct repo","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:46Z","receivedAt":"2017-06-20T19:23:08Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n repository.c | 16 ++++++++++++++++\n repository.h |  6 ++++++\n 2 files changed, 22 insertions(+)\n\ndiff --git a/repository.c b/repository.c\nindex 3dcfec3b8..883e6e9e9 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -175,5 +175,21 @@ void repo_clear(struct repository *repo)\n \t\trepo->config = NULL;\n \t}\n \n+\tif (repo->index) {\n+\t\tdiscard_index(repo->index);\n+\t\tfree(repo->index);\n+\t\trepo->index = NULL;\n+\t}\n+\n \tmemset(repo, 0, sizeof(*repo));\n }\n+\n+int repo_read_index(struct repository *repo)\n+{\n+\tif (!repo->index)\n+\t\trepo->index = xcalloc(1, sizeof(struct index_state));\n+\telse\n+\t\tdiscard_index(repo->index);\n+\n+\treturn read_index_from(repo->index, repo->index_file);\n+}\ndiff --git a/repository.h b/repository.h\nindex 379b64170..1fa65c42f 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -2,6 +2,7 @@\n #define REPOSITORY_H\n \n struct config_set;\n+struct index_state;\n \n struct repository {\n \t/* Environment */\n@@ -31,6 +32,9 @@ struct repository {\n \t */\n \tstruct config_set *config;\n \n+\t/* Repository's in-memory index */\n+\tstruct index_state *index;\n+\n \t/* Configurations */\n \t/*\n \t * Bit used during initialization to indicate if repository state (like\n@@ -53,4 +57,6 @@ extern void repo_set_worktree(struct repository *repo, const char *path);\n extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);\n extern void repo_clear(struct repository *repo);\n \n+extern int repo_read_index(struct repository *repo);\n+\n #endif /* REPOSITORY_H */\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322760","messageId":"20170620191951.84791-3-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 02/20] setup: add comment indicating a hack","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:33Z","receivedAt":"2017-06-20T19:23:09Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"'GIT_TOPLEVEL_PREFIX_ENVIRONMENT' was added in (b58a68c1c setup: allow\nfor prefix to be passed to git commands) to aid in fixing a bug where\n'ls-files' and 'grep' were not able to properly recurse when called from\nwithin a subdirectory.  Add a 'NEEDSWORK' comment indicating that this\nenvvar should be removed once 'ls-files' and 'grep' can recurse\nin-process.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n setup.c | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/setup.c b/setup.c\nindex 24a738b0d..b477faa44 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1079,6 +1079,12 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t\tdie(\"BUG: unhandled setup_git_directory_1() result\");\n \t}\n \n+\t/*\n+\t * NEEDSWORK: This was a hack in order to get ls-files and grep to have\n+\t * properly formated output when recursing submodules.  Once ls-files\n+\t * and grep have been changed to perform this recursing in-process this\n+\t * needs to be removed.\n+\t */\n \tenv_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT);\n \tif (env_prefix)\n \t\tprefix = env_prefix;\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322761","messageId":"20170620191951.84791-9-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 08/20] path: always pass in commondir to update_common_dir","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:39Z","receivedAt":"2017-06-20T19:23:11Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Instead of passing in 'NULL' and having 'update_common_dir()' query for\nthe commondir, have the callers of 'update_common_dir()' be responsible\nfor providing the commondir.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 41c861c96..2434921d8 100644\n--- a/path.c\n+++ b/path.c\n@@ -345,8 +345,6 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len,\n {\n \tchar *base = buf->buf + git_dir_len;\n \tinit_common_trie();\n-\tif (!common_dir)\n-\t\tcommon_dir = get_git_common_dir();\n \tif (trie_find(&common_trie, base, check_common, NULL) > 0)\n \t\treplace_dir(buf, git_dir_len, common_dir);\n }\n@@ -387,7 +385,7 @@ static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n \telse if (git_hooks_path && dir_prefix(base, \"hooks\"))\n \t\treplace_dir(buf, git_dir_len + 5, git_hooks_path);\n \telse if (the_repository->different_commondir)\n-\t\tupdate_common_dir(buf, git_dir_len, NULL);\n+\t\tupdate_common_dir(buf, git_dir_len, get_git_common_dir());\n }\n \n static void do_git_path(const struct worktree *wt, struct strbuf *buf,\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322762","messageId":"20170620191951.84791-15-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 14/20] config: read config from a repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:45Z","receivedAt":"2017-06-20T19:23:12Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach the config machinery to read config information from a repository\nobject.  This involves storing a 'struct config_set' inside the\nrepository object and adding a number of functions (repo_config*) to be\nable to query a repository's config.\n\nThe current config API enables lazy-loading of the config.  This means\nthat when 'git_config_get_int()' is called, if the_config_set hasn't\nbeen populated yet, then it will be populated and properly initialized by\nreading the necessary config files (system wide .gitconfig, user's home\n.gitconfig, and the repository's config).  To maintain this paradigm,\nthe new API to read from a repository object's config will also perform\nthis lazy-initialization.\n\nSince both APIs (git_config_get* and repo_config_get*) have the same\nsemantics we can migrate the default config to be stored within\n'the_repository' and just have the 'git_config_get*' family of functions\nredirect to the 'repo_config_get*' functions.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n config.c     | 216 +++++++++++++++++++++++++++++++++++++++--------------------\n config.h     |  24 +++++++\n repository.c |   7 ++\n repository.h |  10 +++\n 4 files changed, 183 insertions(+), 74 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex 6f0f8b30f..be1c640a4 100644\n--- a/config.c\n+++ b/config.c\n@@ -7,6 +7,7 @@\n  */\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"repository.h\"\n #include \"lockfile.h\"\n #include \"exec_cmd.h\"\n #include \"strbuf.h\"\n@@ -72,13 +73,6 @@ static int core_compression_seen;\n static int pack_compression_seen;\n static int zlib_compression_seen;\n \n-/*\n- * Default config_set that contains key-value pairs from the usual set of config\n- * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG\n- * config file and the global /etc/gitconfig)\n- */\n-static struct config_set the_config_set;\n-\n static int config_file_fgetc(struct config_source *conf)\n {\n \treturn getc_unlocked(conf->u.file);\n@@ -1605,31 +1599,6 @@ int config_with_options(config_fn_t fn, void *data,\n \treturn do_git_config_sequence(opts, fn, data);\n }\n \n-static void git_config_raw(config_fn_t fn, void *data)\n-{\n-\tstruct config_options opts = {0};\n-\n-\topts.respect_includes = 1;\n-\tif (have_git_dir()) {\n-\t\topts.commondir = get_git_common_dir();\n-\t\topts.git_dir = get_git_dir();\n-\t}\n-\n-\tif (config_with_options(fn, data, NULL, &opts) < 0)\n-\t\t/*\n-\t\t * config_with_options() normally returns only\n-\t\t * zero, as most errors are fatal, and\n-\t\t * non-fatal potential errors are guarded by \"if\"\n-\t\t * statements that are entered only when no error is\n-\t\t * possible.\n-\t\t *\n-\t\t * If we ever encounter a non-fatal error, it means\n-\t\t * something went really wrong and we should stop\n-\t\t * immediately.\n-\t\t */\n-\t\tdie(_(\"unknown error occurred while reading the configuration files\"));\n-}\n-\n static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)\n {\n \tint i, value_index;\n@@ -1683,14 +1652,6 @@ void read_early_config(config_fn_t cb, void *data)\n \tstrbuf_release(&gitdir);\n }\n \n-static void git_config_check_init(void);\n-\n-void git_config(config_fn_t fn, void *data)\n-{\n-\tgit_config_check_init();\n-\tconfigset_iter(&the_config_set, fn, data);\n-}\n-\n static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)\n {\n \tstruct config_set_element k;\n@@ -1900,87 +1861,194 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha\n \t\treturn 1;\n }\n \n-static void git_config_check_init(void)\n+/* Functions use to read configuration from a repository */\n+static void repo_read_config(struct repository *repo)\n {\n-\tif (the_config_set.hash_initialized)\n+\tstruct config_options opts;\n+\n+\topts.respect_includes = 1;\n+\topts.commondir = repo->commondir;\n+\topts.git_dir = repo->gitdir;\n+\n+\tif (!repo->config)\n+\t\trepo->config = xcalloc(1, sizeof(struct config_set));\n+\telse\n+\t\tgit_configset_clear(repo->config);\n+\n+\tgit_configset_init(repo->config);\n+\n+\tif (config_with_options(config_set_callback, repo->config, NULL, &opts) < 0)\n+\t\t/*\n+\t\t * config_with_options() normally returns only\n+\t\t * zero, as most errors are fatal, and\n+\t\t * non-fatal potential errors are guarded by \"if\"\n+\t\t * statements that are entered only when no error is\n+\t\t * possible.\n+\t\t *\n+\t\t * If we ever encounter a non-fatal error, it means\n+\t\t * something went really wrong and we should stop\n+\t\t * immediately.\n+\t\t */\n+\t\tdie(_(\"unknown error occurred while reading the configuration files\"));\n+}\n+\n+static void git_config_check_init(struct repository *repo)\n+{\n+\tif (repo->config && repo->config->hash_initialized)\n \t\treturn;\n-\tgit_configset_init(&the_config_set);\n-\tgit_config_raw(config_set_callback, &the_config_set);\n+\trepo_read_config(repo);\n }\n \n-void git_config_clear(void)\n+static void repo_config_clear(struct repository *repo)\n {\n-\tif (!the_config_set.hash_initialized)\n+\tif (!repo->config || !repo->config->hash_initialized)\n \t\treturn;\n-\tgit_configset_clear(&the_config_set);\n+\tgit_configset_clear(repo->config);\n }\n \n-int git_config_get_value(const char *key, const char **value)\n+void repo_config(struct repository *repo, config_fn_t fn, void *data)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_value(&the_config_set, key, value);\n+\tgit_config_check_init(repo);\n+\tconfigset_iter(repo->config, fn, data);\n }\n \n-const struct string_list *git_config_get_value_multi(const char *key)\n+int repo_config_get_value(struct repository *repo,\n+\t\t\t  const char *key, const char **value)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_value_multi(&the_config_set, key);\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_value(repo->config, key, value);\n }\n \n-int git_config_get_string_const(const char *key, const char **dest)\n+const struct string_list *repo_config_get_value_multi(struct repository *repo,\n+\t\t\t\t\t\t      const char *key)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_value_multi(repo->config, key);\n+}\n+\n+int repo_config_get_string_const(struct repository *repo,\n+\t\t\t\t const char *key, const char **dest)\n+{\n+\tint ret;\n+\tgit_config_check_init(repo);\n+\tret = git_configset_get_string_const(repo->config, key, dest);\n+\tif (ret < 0)\n+\t\tgit_die_config(key, NULL);\n+\treturn ret;\n+}\n+\n+int repo_config_get_string(struct repository *repo,\n+\t\t\t   const char *key, char **dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn repo_config_get_string_const(repo, key, (const char **)dest);\n+}\n+\n+int repo_config_get_int(struct repository *repo,\n+\t\t\tconst char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_int(repo->config, key, dest);\n+}\n+\n+int repo_config_get_ulong(struct repository *repo,\n+\t\t\t  const char *key, unsigned long *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_ulong(repo->config, key, dest);\n+}\n+\n+int repo_config_get_bool(struct repository *repo,\n+\t\t\t const char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_bool(repo->config, key, dest);\n+}\n+\n+int repo_config_get_bool_or_int(struct repository *repo,\n+\t\t\t\tconst char *key, int *is_bool, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_bool_or_int(repo->config, key, is_bool, dest);\n+}\n+\n+int repo_config_get_maybe_bool(struct repository *repo,\n+\t\t\t       const char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_maybe_bool(repo->config, key, dest);\n+}\n+\n+int repo_config_get_pathname(struct repository *repo,\n+\t\t\t     const char *key, const char **dest)\n {\n \tint ret;\n-\tgit_config_check_init();\n-\tret = git_configset_get_string_const(&the_config_set, key, dest);\n+\tgit_config_check_init(repo);\n+\tret = git_configset_get_pathname(repo->config, key, dest);\n \tif (ret < 0)\n \t\tgit_die_config(key, NULL);\n \treturn ret;\n }\n \n+/* Functions used historically to read configuration from 'the_repository' */\n+void git_config(config_fn_t fn, void *data)\n+{\n+\trepo_config(the_repository, fn, data);\n+}\n+\n+void git_config_clear(void)\n+{\n+\trepo_config_clear(the_repository);\n+}\n+\n+int git_config_get_value(const char *key, const char **value)\n+{\n+\treturn repo_config_get_value(the_repository, key, value);\n+}\n+\n+const struct string_list *git_config_get_value_multi(const char *key)\n+{\n+\treturn repo_config_get_value_multi(the_repository, key);\n+}\n+\n+int git_config_get_string_const(const char *key, const char **dest)\n+{\n+\treturn repo_config_get_string_const(the_repository, key, dest);\n+}\n+\n int git_config_get_string(const char *key, char **dest)\n {\n-\tgit_config_check_init();\n-\treturn git_config_get_string_const(key, (const char **)dest);\n+\treturn repo_config_get_string(the_repository, key, dest);\n }\n \n int git_config_get_int(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_int(&the_config_set, key, dest);\n+\treturn repo_config_get_int(the_repository, key, dest);\n }\n \n int git_config_get_ulong(const char *key, unsigned long *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_ulong(&the_config_set, key, dest);\n+\treturn repo_config_get_ulong(the_repository, key, dest);\n }\n \n int git_config_get_bool(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_bool(&the_config_set, key, dest);\n+\treturn repo_config_get_bool(the_repository, key, dest);\n }\n \n int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);\n+\treturn repo_config_get_bool_or_int(the_repository, key, is_bool, dest);\n }\n \n int git_config_get_maybe_bool(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_maybe_bool(&the_config_set, key, dest);\n+\treturn repo_config_get_maybe_bool(the_repository, key, dest);\n }\n \n int git_config_get_pathname(const char *key, const char **dest)\n {\n-\tint ret;\n-\tgit_config_check_init();\n-\tret = git_configset_get_pathname(&the_config_set, key, dest);\n-\tif (ret < 0)\n-\t\tgit_die_config(key, NULL);\n-\treturn ret;\n+\treturn repo_config_get_pathname(the_repository, key, dest);\n }\n \n int git_config_get_expiry(const char *key, const char **output)\ndiff --git a/config.h b/config.h\nindex 9e038cce2..0352da117 100644\n--- a/config.h\n+++ b/config.h\n@@ -163,6 +163,30 @@ extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key,\n extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);\n extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);\n \n+/* Functions for reading a repository's config */\n+struct repository;\n+extern void repo_config(struct repository *repo, config_fn_t fn, void *data);\n+extern int repo_config_get_value(struct repository *repo,\n+\t\t\t\t const char *key, const char **value);\n+extern const struct string_list *repo_config_get_value_multi(struct repository *repo,\n+\t\t\t\t\t\t\t     const char *key);\n+extern int repo_config_get_string_const(struct repository *repo,\n+\t\t\t\t\tconst char *key, const char **dest);\n+extern int repo_config_get_string(struct repository *repo,\n+\t\t\t\t  const char *key, char **dest);\n+extern int repo_config_get_int(struct repository *repo,\n+\t\t\t       const char *key, int *dest);\n+extern int repo_config_get_ulong(struct repository *repo,\n+\t\t\t\t const char *key, unsigned long *dest);\n+extern int repo_config_get_bool(struct repository *repo,\n+\t\t\t\tconst char *key, int *dest);\n+extern int repo_config_get_bool_or_int(struct repository *repo,\n+\t\t\t\t       const char *key, int *is_bool, int *dest);\n+extern int repo_config_get_maybe_bool(struct repository *repo,\n+\t\t\t\t      const char *key, int *dest);\n+extern int repo_config_get_pathname(struct repository *repo,\n+\t\t\t\t    const char *key, const char **dest);\n+\n extern int git_config_get_value(const char *key, const char **value);\n extern const struct string_list *git_config_get_value_multi(const char *key);\n extern void git_config_clear(void);\ndiff --git a/repository.c b/repository.c\nindex 7c8a7728c..3dcfec3b8 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"repository.h\"\n+#include \"config.h\"\n \n /* The main repository */\n static struct repository the_repo;\n@@ -168,5 +169,11 @@ void repo_clear(struct repository *repo)\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n \n+\tif (repo->config) {\n+\t\tgit_configset_clear(repo->config);\n+\t\tfree(repo->config);\n+\t\trepo->config = NULL;\n+\t}\n+\n \tmemset(repo, 0, sizeof(*repo));\n }\ndiff --git a/repository.h b/repository.h\nindex ab1744d51..379b64170 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -1,6 +1,8 @@\n #ifndef REPOSITORY_H\n #define REPOSITORY_H\n \n+struct config_set;\n+\n struct repository {\n \t/* Environment */\n \t/* Path to the git directory */\n@@ -21,6 +23,14 @@ struct repository {\n \t/* Path to the working directory */\n \tchar *worktree;\n \n+\t/* Subsystems */\n+\t/*\n+\t * Repository's config which contains key-value pairs from the usual\n+\t * set of config files (i.e. repo specific .git/config, user wide\n+\t * ~/.gitconfig, XDG config file and the global /etc/gitconfig)\n+\t */\n+\tstruct config_set *config;\n+\n \t/* Configurations */\n \t/*\n \t * Bit used during initialization to indicate if repository state (like\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322763","messageId":"20170620191951.84791-21-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 20/20] ls-files: use repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:51Z","receivedAt":"2017-06-20T19:23:14Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert ls-files to use a repository struct and recurse submodules\ninprocess.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c                     | 195 ++++++++++++++-------------------\n git.c                                  |   2 +-\n t/t3007-ls-files-recurse-submodules.sh |  39 +++++++\n 3 files changed, 120 insertions(+), 116 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex b12d0bb61..f5f36ddb4 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -5,7 +5,9 @@\n  *\n  * Copyright (C) Linus Torvalds, 2005\n  */\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"quote.h\"\n #include \"dir.h\"\n@@ -32,10 +34,8 @@ static int line_terminator = '\\n';\n static int debug_mode;\n static int show_eol;\n static int recurse_submodules;\n-static struct argv_array submodule_options = ARGV_ARRAY_INIT;\n \n static const char *prefix;\n-static const char *super_prefix;\n static int max_prefix_len;\n static int prefix_len;\n static struct pathspec pathspec;\n@@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,\n \n static void write_name(const char *name)\n {\n-\t/*\n-\t * Prepend the super_prefix to name to construct the full_name to be\n-\t * written.\n-\t */\n-\tstruct strbuf full_name = STRBUF_INIT;\n-\tif (super_prefix) {\n-\t\tstrbuf_addstr(&full_name, super_prefix);\n-\t\tstrbuf_addstr(&full_name, name);\n-\t\tname = full_name.buf;\n-\t}\n-\n \t/*\n \t * With \"--full-name\", prefix_len=0; this caller needs to pass\n \t * an empty string in that case (a NULL is good for \"\").\n \t */\n \twrite_name_quoted_relative(name, prefix_len ? prefix : NULL,\n \t\t\t\t   stdout, line_terminator);\n-\n-\tstrbuf_release(&full_name);\n }\n \n static const char *get_tag(const struct cache_entry *ce, const char *tag)\n@@ -210,83 +197,38 @@ static void show_killed_files(const struct index_state *istate,\n \t}\n }\n \n-/*\n- * Compile an argv_array with all of the options supported by --recurse_submodules\n- */\n-static void compile_submodule_options(const char **argv,\n-\t\t\t\t      const struct dir_struct *dir,\n-\t\t\t\t      int show_tag)\n-{\n-\tif (line_terminator == '\\0')\n-\t\targv_array_push(&submodule_options, \"-z\");\n-\tif (show_tag)\n-\t\targv_array_push(&submodule_options, \"-t\");\n-\tif (show_valid_bit)\n-\t\targv_array_push(&submodule_options, \"-v\");\n-\tif (show_cached)\n-\t\targv_array_push(&submodule_options, \"--cached\");\n-\tif (show_eol)\n-\t\targv_array_push(&submodule_options, \"--eol\");\n-\tif (debug_mode)\n-\t\targv_array_push(&submodule_options, \"--debug\");\n-\n-\t/* Add Pathspecs */\n-\targv_array_push(&submodule_options, \"--\");\n-\tfor (; *argv; argv++)\n-\t\targv_array_push(&submodule_options, *argv);\n-}\n+static void show_files(struct repository *repo, struct dir_struct *dir);\n \n-/**\n- * Recursively call ls-files on a submodule\n- */\n-static void show_gitlink(const struct cache_entry *ce)\n+static void show_submodule(struct repository *superproject,\n+\t\t\t   struct dir_struct *dir, const char *path)\n {\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n-\tint status;\n-\tchar *dir;\n-\n-\tprepare_submodule_repo_env(&cp.env_array);\n-\targv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);\n-\n-\tif (prefix_len)\n-\t\targv_array_pushf(&cp.env_array, \"%s=%s\",\n-\t\t\t\t GIT_TOPLEVEL_PREFIX_ENVIRONMENT,\n-\t\t\t\t prefix);\n-\targv_array_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t\t super_prefix ? super_prefix : \"\",\n-\t\t\t ce->name);\n-\targv_array_push(&cp.args, \"ls-files\");\n-\targv_array_push(&cp.args, \"--recurse-submodules\");\n-\n-\t/* add supported options */\n-\targv_array_pushv(&cp.args, submodule_options.argv);\n-\n-\tcp.git_cmd = 1;\n-\tdir = mkpathdup(\"%s/%s\", get_git_work_tree(), ce->name);\n-\tcp.dir = dir;\n-\tstatus = run_command(&cp);\n-\tfree(dir);\n-\tif (status)\n-\t\texit(status);\n+\tstruct repository submodule;\n+\n+\tif (repo_submodule_init(&submodule, superproject, path))\n+\t\treturn;\n+\n+\tif (repo_read_index(&submodule) < 0)\n+\t\tdie(\"index file corrupt\");\n+\n+\trepo_read_gitmodules(&submodule);\n+\n+\tshow_files(&submodule, dir);\n+\n+\trepo_clear(&submodule);\n }\n \n-static void show_ce_entry(const struct index_state *istate,\n-\t\t\t  const char *tag, const struct cache_entry *ce)\n+static void show_ce(struct repository *repo, struct dir_struct *dir,\n+\t\t    const struct cache_entry *ce, const char *fullname,\n+\t\t    const char *tag)\n {\n-\tstruct strbuf name = STRBUF_INIT;\n-\tint len = max_prefix_len;\n-\tif (super_prefix)\n-\t\tstrbuf_addstr(&name, super_prefix);\n-\tstrbuf_addstr(&name, ce->name);\n-\n-\tif (len > ce_namelen(ce))\n+\tif (max_prefix_len > strlen(fullname))\n \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n \n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t    submodule_path_match(&pathspec, name.buf, ps_matched)) {\n-\t\tshow_gitlink(ce);\n-\t} else if (match_pathspec(&pathspec, name.buf, name.len,\n-\t\t\t\t  len, ps_matched,\n+\t    is_submodule_active(repo, ce->name)) {\n+\t\tshow_submodule(repo, dir, ce->name);\n+\t} else if (match_pathspec(&pathspec, fullname, strlen(fullname),\n+\t\t\t\t  max_prefix_len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n \t\ttag = get_tag(ce, tag);\n@@ -300,12 +242,10 @@ static void show_ce_entry(const struct index_state *istate,\n \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n \t\t\t       ce_stage(ce));\n \t\t}\n-\t\twrite_eolinfo(istate, ce, ce->name);\n-\t\twrite_name(ce->name);\n+\t\twrite_eolinfo(repo->index, ce, fullname);\n+\t\twrite_name(fullname);\n \t\tprint_debug(ce);\n \t}\n-\n-\tstrbuf_release(&name);\n }\n \n static void show_ru_info(const struct index_state *istate)\n@@ -338,59 +278,79 @@ static void show_ru_info(const struct index_state *istate)\n }\n \n static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n-\t\t       const struct cache_entry *ce)\n+\t\t       const char *fullname, const struct cache_entry *ce)\n {\n \tint dtype = ce_to_dtype(ce);\n-\treturn is_excluded(dir, istate, ce->name, &dtype);\n+\treturn is_excluded(dir, istate, fullname, &dtype);\n }\n \n-static void show_files(struct index_state *istate, struct dir_struct *dir)\n+static void construct_fullname(struct strbuf *out, const struct repository *repo,\n+\t\t\t       const struct cache_entry *ce)\n+{\n+\tstrbuf_reset(out);\n+\tif (repo->submodule_prefix)\n+\t\tstrbuf_addstr(out, repo->submodule_prefix);\n+\tstrbuf_addstr(out, ce->name);\n+}\n+\n+static void show_files(struct repository *repo, struct dir_struct *dir)\n {\n \tint i;\n+\tstruct strbuf fullname = STRBUF_INIT;\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others || show_killed) {\n \t\tif (!show_others)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n-\t\tfill_directory(dir, istate, &pathspec);\n+\t\tfill_directory(dir, repo->index, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(istate, dir);\n+\t\t\tshow_other_files(repo->index, dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(istate, dir);\n+\t\t\tshow_killed_files(repo->index, dir);\n \t}\n \tif (show_cached || show_stage) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-\t\t\tshow_ce_entry(istate, ce_stage(ce) ? tag_unmerged :\n-\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);\n+\t\t\tshow_ce(repo, dir, ce, fullname.buf,\n+\t\t\t\tce_stage(ce) ? tag_unmerged :\n+\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree :\n+\t\t\t\t tag_cached));\n \t\t}\n \t}\n \tif (show_deleted || show_modified) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n \t\t\tstruct stat st;\n \t\t\tint err;\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n \t\t\tif (ce_skip_worktree(ce))\n \t\t\t\tcontinue;\n-\t\t\terr = lstat(ce->name, &st);\n+\t\t\terr = lstat(fullname.buf, &st);\n \t\t\tif (show_deleted && err)\n-\t\t\t\tshow_ce_entry(istate, tag_removed, ce);\n-\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n-\t\t\t\tshow_ce_entry(istate, tag_modified, ce);\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed);\n+\t\t\tif (show_modified && ie_modified(repo->index, ce, &st, 0))\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified);\n \t\t}\n \t}\n+\n+\tstrbuf_release(&fullname);\n }\n \n /*\n@@ -615,10 +575,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tprefix = cmd_prefix;\n \tif (prefix)\n \t\tprefix_len = strlen(prefix);\n-\tsuper_prefix = get_super_prefix();\n \tgit_config(git_default_config, NULL);\n \n-\tif (read_cache() < 0)\n+\tif (repo_read_index(the_repository) < 0)\n \t\tdie(\"index file corrupt\");\n \n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n@@ -651,8 +610,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (require_work_tree && !is_inside_work_tree())\n \t\tsetup_work_tree();\n \n-\tif (recurse_submodules)\n-\t\tcompile_submodule_options(argv, &dir, show_tag);\n+\tif (recurse_submodules) {\n+\t\trepo_read_gitmodules(the_repository);\n+\t}\n \n \tif (recurse_submodules &&\n \t    (show_stage || show_deleted || show_others || show_unmerged ||\n@@ -670,7 +630,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t/*\n \t * Find common prefix for all pathspec's\n \t * This is used as a performance optimization which unfortunately cannot\n-\t * be done when recursing into submodules\n+\t * be done when recursing into submodules because when a pathspec is\n+\t * given which spans repository boundaries you can't simply remove the\n+\t * submodule entry because the pathspec may match something inside the\n+\t * submodule.\n \t */\n \tif (recurse_submodules)\n \t\tmax_prefix = NULL;\n@@ -678,7 +641,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_index(&the_index, max_prefix, max_prefix_len);\n+\tprune_index(the_repository->index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n@@ -699,11 +662,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n-\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n+\t\toverlay_tree_on_index(the_repository->index, with_tree, max_prefix);\n \t}\n-\tshow_files(&the_index, &dir);\n+\n+\tshow_files(the_repository, &dir);\n+\n \tif (show_resolve_undo)\n-\t\tshow_ru_info(&the_index);\n+\t\tshow_ru_info(the_repository->index);\n \n \tif (ps_matched) {\n \t\tint bad;\ndiff --git a/git.c b/git.c\nindex 5be27b07e..489aab4d8 100644\n--- a/git.c\n+++ b/git.c\n@@ -400,7 +400,7 @@ static struct cmd_struct commands[] = {\n \t{ \"init-db\", cmd_init_db },\n \t{ \"interpret-trailers\", cmd_interpret_trailers, RUN_SETUP_GENTLY },\n \t{ \"log\", cmd_log, RUN_SETUP },\n-\t{ \"ls-files\", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"ls-files\", cmd_ls_files, RUN_SETUP },\n \t{ \"ls-remote\", cmd_ls_remote, RUN_SETUP_GENTLY },\n \t{ \"ls-tree\", cmd_ls_tree, RUN_SETUP },\n \t{ \"mailinfo\", cmd_mailinfo, RUN_SETUP_GENTLY },\ndiff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh\nindex ebb956fd1..318b5bce7 100755\n--- a/t/t3007-ls-files-recurse-submodules.sh\n+++ b/t/t3007-ls-files-recurse-submodules.sh\n@@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'inactive submodule' '\n+\ttest_when_finished \"git config --bool submodule.submodule.active true\" &&\n+\ttest_when_finished \"git -C submodule config --bool submodule.subsub.active true\" &&\n+\tgit config --bool submodule.submodule.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tgit config --bool submodule.submodule.active \"true\" &&\n+\tgit -C submodule config --bool submodule.subsub.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule/.gitmodules\n+\tsubmodule/c\n+\tsubmodule/f.TXT\n+\tsubmodule/g.txt\n+\tsubmodule/subsub\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success '--recurse-submodules and pathspecs' '\n \tcat >expect <<-\\EOF &&\n \th.txt\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322764","messageId":"20170620191951.84791-17-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 16/20] submodule-config: store the_submodule_cache in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:47Z","receivedAt":"2017-06-20T19:23:15Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Refactor how 'the_submodule_cache' is handled so that it can be stored\ninside of a repository object.  Also migrate 'the_submodule_cache' to be\nstored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n repository.c       |  6 +++++\n repository.h       |  4 ++++\n submodule-config.c | 70 ++++++++++++++++++++++++++++++++++++++++--------------\n submodule-config.h | 10 ++++++++\n 4 files changed, 72 insertions(+), 18 deletions(-)\n\ndiff --git a/repository.c b/repository.c\nindex 883e6e9e9..317041a4a 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"repository.h\"\n #include \"config.h\"\n+#include \"submodule-config.h\"\n \n /* The main repository */\n static struct repository the_repo;\n@@ -181,6 +182,11 @@ void repo_clear(struct repository *repo)\n \t\trepo->index = NULL;\n \t}\n \n+\tif (repo->submodule_cache) {\n+\t\tsubmodule_cache_free(repo->submodule_cache);\n+\t\trepo->submodule_cache = NULL;\n+\t}\n+\n \tmemset(repo, 0, sizeof(*repo));\n }\n \ndiff --git a/repository.h b/repository.h\nindex 1fa65c42f..4bc70ebc5 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -3,6 +3,7 @@\n \n struct config_set;\n struct index_state;\n+struct submodule_cache;\n \n struct repository {\n \t/* Environment */\n@@ -32,6 +33,9 @@ struct repository {\n \t */\n \tstruct config_set *config;\n \n+\t/* Repository's submodule config as defined by '.gitmodules' */\n+\tstruct submodule_cache *submodule_cache;\n+\n \t/* Repository's in-memory index */\n \tstruct index_state *index;\n \ndiff --git a/submodule-config.c b/submodule-config.c\nindex d8f8d5ea3..37cfcceb9 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n@@ -15,6 +16,7 @@\n struct submodule_cache {\n \tstruct hashmap for_path;\n \tstruct hashmap for_name;\n+\tunsigned initialized:1;\n };\n \n /*\n@@ -31,9 +33,6 @@ enum lookup_type {\n \tlookup_path\n };\n \n-static struct submodule_cache the_submodule_cache;\n-static int is_cache_init;\n-\n static int config_path_cmp(const struct submodule_entry *a,\n \t\t\t   const struct submodule_entry *b,\n \t\t\t   const void *unused)\n@@ -50,10 +49,16 @@ static int config_name_cmp(const struct submodule_entry *a,\n \t       hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);\n }\n \n-static void cache_init(struct submodule_cache *cache)\n+static struct submodule_cache *submodule_cache_alloc(void)\n+{\n+\treturn xcalloc(1, sizeof(struct submodule_cache));\n+}\n+\n+static void submodule_cache_init(struct submodule_cache *cache)\n {\n \thashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);\n \thashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);\n+\tcache->initialized = 1;\n }\n \n static void free_one_config(struct submodule_entry *entry)\n@@ -65,11 +70,14 @@ static void free_one_config(struct submodule_entry *entry)\n \tfree(entry->config);\n }\n \n-static void cache_free(struct submodule_cache *cache)\n+static void submodule_cache_clear(struct submodule_cache *cache)\n {\n \tstruct hashmap_iter iter;\n \tstruct submodule_entry *entry;\n \n+\tif (!cache->initialized)\n+\t\treturn;\n+\n \t/*\n \t * We iterate over the name hash here to be symmetric with the\n \t * allocation of struct submodule entries. Each is allocated by\n@@ -81,6 +89,13 @@ static void cache_free(struct submodule_cache *cache)\n \n \thashmap_free(&cache->for_path, 1);\n \thashmap_free(&cache->for_name, 1);\n+\tcache->initialized = 0;\n+}\n+\n+void submodule_cache_free(struct submodule_cache *cache)\n+{\n+\tsubmodule_cache_clear(cache);\n+\tfree(cache);\n }\n \n static unsigned int hash_sha1_string(const unsigned char *sha1,\n@@ -494,43 +509,62 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \treturn submodule;\n }\n \n-static void ensure_cache_init(void)\n+static void submodule_cache_check_init(struct repository *repo)\n {\n-\tif (is_cache_init)\n+\tif (repo->submodule_cache && repo->submodule_cache->initialized)\n \t\treturn;\n \n-\tcache_init(&the_submodule_cache);\n-\tis_cache_init = 1;\n+\tif (!repo->submodule_cache)\n+\t\trepo->submodule_cache = submodule_cache_alloc();\n+\n+\tsubmodule_cache_init(repo->submodule_cache);\n }\n \n-int parse_submodule_config_option(const char *var, const char *value)\n+int submodule_config_option(struct repository *repo,\n+\t\t\t    const char *var, const char *value)\n {\n \tstruct parse_config_parameter parameter;\n-\tparameter.cache = &the_submodule_cache;\n+\n+\tsubmodule_cache_check_init(repo);\n+\n+\tparameter.cache = repo->submodule_cache;\n \tparameter.treeish_name = NULL;\n \tparameter.gitmodules_sha1 = null_sha1;\n \tparameter.overwrite = 1;\n \n-\tensure_cache_init();\n \treturn parse_config(var, value, &parameter);\n }\n \n+int parse_submodule_config_option(const char *var, const char *value)\n+{\n+\treturn submodule_config_option(the_repository, var, value);\n+}\n+\n const struct submodule *submodule_from_name(const unsigned char *treeish_name,\n \t\tconst char *name)\n {\n-\tensure_cache_init();\n-\treturn config_from(&the_submodule_cache, treeish_name, name, lookup_name);\n+\tsubmodule_cache_check_init(the_repository);\n+\treturn config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);\n }\n \n const struct submodule *submodule_from_path(const unsigned char *treeish_name,\n \t\tconst char *path)\n {\n-\tensure_cache_init();\n-\treturn config_from(&the_submodule_cache, treeish_name, path, lookup_path);\n+\tsubmodule_cache_check_init(the_repository);\n+\treturn config_from(the_repository->submodule_cache, treeish_name, path, lookup_path);\n+}\n+\n+const struct submodule *submodule_from_cache(struct repository *repo,\n+\t\t\t\t\t     const unsigned char *treeish_name,\n+\t\t\t\t\t     const char *key)\n+{\n+\tsubmodule_cache_check_init(repo);\n+\treturn config_from(repo->submodule_cache, treeish_name,\n+\t\t\t   key, lookup_path);\n }\n \n void submodule_free(void)\n {\n-\tcache_free(&the_submodule_cache);\n-\tis_cache_init = 0;\n+\tif (the_repository->submodule_cache)\n+\t\tsubmodule_cache_clear(the_repository->submodule_cache);\n }\ndiff --git a/submodule-config.h b/submodule-config.h\nindex d434ecdb4..bc45a25e8 100644\n--- a/submodule-config.h\n+++ b/submodule-config.h\n@@ -22,14 +22,24 @@ struct submodule {\n \tint recommend_shallow;\n };\n \n+struct submodule_cache;\n+struct repository;\n+\n+extern void submodule_cache_free(struct submodule_cache *cache);\n+\n extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_submodule_config_option(const char *var, const char *value);\n+extern int submodule_config_option(struct repository *repo,\n+\t\t\t\t   const char *var, const char *value);\n extern const struct submodule *submodule_from_name(\n \t\tconst unsigned char *commit_or_tree, const char *name);\n extern const struct submodule *submodule_from_path(\n \t\tconst unsigned char *commit_or_tree, const char *path);\n+extern const struct submodule *submodule_from_cache(struct repository *repo,\n+\t\t\t\t\t\t    const unsigned char *treeish_name,\n+\t\t\t\t\t\t    const char *key);\n extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,\n \t\t\t\t      unsigned char *gitmodules_sha1,\n \t\t\t\t      struct strbuf *rev);\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322765","messageId":"20170620191951.84791-19-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 18/20] submodule: convert is_submodule_initialized to work on a repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:49Z","receivedAt":"2017-06-20T19:23:16Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'is_submodule_initialized()' to take a repository object and\nwhile we're at it, lets rename the function to 'is_submodule_active()'\nand remove the NEEDSWORK comment.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/grep.c              |  3 ++-\n builtin/submodule--helper.c |  9 +++++----\n submodule.c                 | 20 ++++++++------------\n submodule.h                 |  2 +-\n 4 files changed, 16 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex f61a9d938..e3ba1d98e 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -4,6 +4,7 @@\n  * Copyright (c) 2006 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"blob.h\"\n #include \"tree.h\"\n@@ -643,7 +644,7 @@ static int grep_submodule_launch(struct grep_opt *opt,\n static int grep_submodule(struct grep_opt *opt, const struct object_id *oid,\n \t\t\t  const char *filename, const char *path)\n {\n-\tif (!is_submodule_initialized(path))\n+\tif (!is_submodule_active(the_repository, path))\n \t\treturn 0;\n \tif (!is_submodule_populated_gently(path, NULL)) {\n \t\t/*\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 8517032b3..e1b06c41d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"repository.h\"\n #include \"cache.h\"\n #include \"config.h\"\n #include \"parse-options.h\"\n@@ -280,7 +281,7 @@ static void module_list_active(struct module_list *list)\n \tfor (i = 0; i < list->nr; i++) {\n \t\tconst struct cache_entry *ce = list->entries[i];\n \n-\t\tif (!is_submodule_initialized(ce->name))\n+\t\tif (!is_submodule_active(the_repository, ce->name))\n \t\t\tcontinue;\n \n \t\tALLOC_GROW(active_modules.entries,\n@@ -362,7 +363,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t *\n \t * Set active flag for the submodule being initialized\n \t */\n-\tif (!is_submodule_initialized(path)) {\n+\tif (!is_submodule_active(the_repository, path)) {\n \t\tstrbuf_reset(&sb);\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n@@ -817,7 +818,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \t}\n \n \t/* Check if the submodule has been initialized. */\n-\tif (!is_submodule_initialized(ce->name)) {\n+\tif (!is_submodule_active(the_repository, ce->name)) {\n \t\tnext_submodule_warn_missing(suc, out, displaypath);\n \t\tgoto cleanup;\n \t}\n@@ -1193,7 +1194,7 @@ static int is_active(int argc, const char **argv, const char *prefix)\n \n \tgitmodules_config();\n \n-\treturn !is_submodule_initialized(argv[1]);\n+\treturn !is_submodule_active(the_repository, argv[1]);\n }\n \n #define SUPPORT_SUPER_PREFIX (1<<0)\ndiff --git a/submodule.c b/submodule.c\nindex d0b894772..b23c25311 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -283,21 +283,17 @@ void gitmodules_config_sha1(const unsigned char *commit_sha1)\n }\n \n /*\n- * NEEDSWORK: With the addition of different configuration options to determine\n- * if a submodule is of interests, the validity of this function's name comes\n- * into question.  Once the dust has settled and more concrete terminology is\n- * decided upon, come up with a more proper name for this function.  One\n- * potential candidate could be 'is_submodule_active()'.\n- *\n  * Determine if a submodule has been initialized at a given 'path'\n  */\n-int is_submodule_initialized(const char *path)\n+int is_submodule_active(struct repository *repo, const char *path)\n {\n \tint ret = 0;\n \tchar *key = NULL;\n \tchar *value = NULL;\n \tconst struct string_list *sl;\n-\tconst struct submodule *module = submodule_from_path(null_sha1, path);\n+\tconst struct submodule *module;\n+\n+\tmodule = submodule_from_cache(repo, null_sha1, path);\n \n \t/* early return if there isn't a path->module mapping */\n \tif (!module)\n@@ -305,14 +301,14 @@ int is_submodule_initialized(const char *path)\n \n \t/* submodule.<name>.active is set */\n \tkey = xstrfmt(\"submodule.%s.active\", module->name);\n-\tif (!git_config_get_bool(key, &ret)) {\n+\tif (!repo_config_get_bool(repo, key, &ret)) {\n \t\tfree(key);\n \t\treturn ret;\n \t}\n \tfree(key);\n \n \t/* submodule.active is set */\n-\tsl = git_config_get_value_multi(\"submodule.active\");\n+\tsl = repo_config_get_value_multi(repo, \"submodule.active\");\n \tif (sl) {\n \t\tstruct pathspec ps;\n \t\tstruct argv_array args = ARGV_ARRAY_INIT;\n@@ -332,7 +328,7 @@ int is_submodule_initialized(const char *path)\n \n \t/* fallback to checking if the URL is set */\n \tkey = xstrfmt(\"submodule.%s.url\", module->name);\n-\tret = !git_config_get_string(key, &value);\n+\tret = !repo_config_get_string(repo, key, &value);\n \n \tfree(value);\n \tfree(key);\n@@ -1532,7 +1528,7 @@ int submodule_move_head(const char *path,\n \tconst struct submodule *sub;\n \tint *error_code_ptr, error_code;\n \n-\tif (!is_submodule_initialized(path))\n+\tif (!is_submodule_active(the_repository, path))\n \t\treturn 0;\n \n \tif (flags & SUBMODULE_MOVE_HEAD_FORCE)\ndiff --git a/submodule.h b/submodule.h\nindex 8a3771ec6..623ce6ad7 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -49,7 +49,7 @@ void load_submodule_cache(void);\n extern void gitmodules_config(void);\n extern void repo_read_gitmodules(struct repository *repo);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n-extern int is_submodule_initialized(const char *path);\n+extern int is_submodule_active(struct repository *repo, const char *path);\n /*\n  * Determine if a submodule has been populated at a given 'path' by checking if\n  * the <path>/.git resolves to a valid git repository.\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322766","messageId":"20170620191951.84791-20-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 19/20] repository: enable initialization of submodules","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:50Z","receivedAt":"2017-06-20T19:23:17Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce 'repo_submodule_init()' which performs initialization of a\n'struct repository' as a submodule of another 'struct repository'.\n\nThe resulting submodule can be in one of three states:\n\n  1. The submodule is initialized and has a worktree.\n\n  2. The submodule is initialized but does not have a worktree.  This\n     would occur when the submodule's gitdir is present in the\n     superproject's 'gitdir/modules/' directory yet the submodule has not\n     been checked out in superproject's worktree.\n\n  3. The submodule remains uninitialized due to an error in the\n     initialization process or there is no matching submodule at the\n     provided path in the superproject.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n repository.c | 44 ++++++++++++++++++++++++++++++++++++++++++++\n repository.h | 10 ++++++++++\n 2 files changed, 54 insertions(+)\n\ndiff --git a/repository.c b/repository.c\nindex 317041a4a..673b35ca5 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -155,6 +155,48 @@ int repo_init(struct repository *repo, const char *gitdir, const char *worktree)\n \treturn -1;\n }\n \n+/*\n+ * Initialize 'submodule' as the submodule given by 'path' in parent repository\n+ * 'superproject'.\n+ * Return 0 upon success and a non-zero value upon failure.\n+ */\n+int repo_submodule_init(struct repository *submodule,\n+\t\t\tstruct repository *superproject,\n+\t\t\tconst char *path)\n+{\n+\tconst struct submodule *sub;\n+\tstruct strbuf submodule_path = STRBUF_INIT;\n+\tint ret = 0;\n+\n+\tsub = submodule_from_cache(superproject, null_sha1, path);\n+\tif (!sub) {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\tstrbuf_repo_worktree_path(&submodule_path, superproject, \"%s\", path);\n+\n+\tif (repo_init(submodule, submodule_path.buf, submodule_path.buf)) {\n+\t\tstrbuf_reset(&submodule_path);\n+\t\tstrbuf_repo_git_path(&submodule_path, superproject,\n+\t\t\t\t     \"modules/%s\", sub->name);\n+\n+\t\tif (repo_init(submodule, submodule_path.buf, NULL)) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\t}\n+\n+\tsubmodule->submodule_prefix = xstrfmt(\"%s%s/\",\n+\t\t\t\t\t      superproject->submodule_prefix ?\n+\t\t\t\t\t      superproject->submodule_prefix :\n+\t\t\t\t\t      \"\", path);\n+\n+out:\n+\tstrbuf_release(&submodule_path);\n+\treturn ret;\n+}\n+\n void repo_clear(struct repository *repo)\n {\n \tfree(repo->gitdir);\n@@ -169,6 +211,8 @@ void repo_clear(struct repository *repo)\n \trepo->index_file = NULL;\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n+\tfree(repo->submodule_prefix);\n+\trepo->submodule_prefix = NULL;\n \n \tif (repo->config) {\n \t\tgit_configset_clear(repo->config);\ndiff --git a/repository.h b/repository.h\nindex 4bc70ebc5..7b352accb 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -25,6 +25,13 @@ struct repository {\n \t/* Path to the working directory */\n \tchar *worktree;\n \n+\t/*\n+\t * Path from the root of the top-level superproject down to this\n+\t * repository.  This is only non-NULL if the repository is initialized\n+\t * as a submodule of another repository.\n+\t */\n+\tchar *submodule_prefix;\n+\n \t/* Subsystems */\n \t/*\n \t * Repository's config which contains key-value pairs from the usual\n@@ -59,6 +66,9 @@ extern struct repository *the_repository;\n extern void repo_set_gitdir(struct repository *repo, const char *path);\n extern void repo_set_worktree(struct repository *repo, const char *path);\n extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);\n+extern int repo_submodule_init(struct repository *submodule,\n+\t\t\t       struct repository *superproject,\n+\t\t\t       const char *path);\n extern void repo_clear(struct repository *repo);\n \n extern int repo_read_index(struct repository *repo);\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322767","messageId":"20170620191951.84791-18-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 17/20] submodule: add repo_read_gitmodules","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:48Z","receivedAt":"2017-06-20T19:23:19Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach the repo object to be able to populate the submodule_cache by\nreading the repository's gitmodules file.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n submodule.c | 15 +++++++++++++++\n submodule.h |  2 ++\n 2 files changed, 17 insertions(+)\n\ndiff --git a/submodule.c b/submodule.c\nindex da0b80549..d0b894772 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n@@ -255,6 +256,20 @@ void gitmodules_config(void)\n \t}\n }\n \n+static int gitmodules_cb(const char *var, const char *value, void *data)\n+{\n+\tstruct repository *repo = data;\n+\treturn submodule_config_option(repo, var, value);\n+}\n+\n+void repo_read_gitmodules(struct repository *repo)\n+{\n+\tchar *gitmodules_path = repo_worktree_path(repo, \".gitmodules\");\n+\n+\tgit_config_from_file(gitmodules_cb, gitmodules_path, repo);\n+\tfree(gitmodules_path);\n+}\n+\n void gitmodules_config_sha1(const unsigned char *commit_sha1)\n {\n \tstruct strbuf rev = STRBUF_INIT;\ndiff --git a/submodule.h b/submodule.h\nindex cbe5c1726..8a3771ec6 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -1,6 +1,7 @@\n #ifndef SUBMODULE_H\n #define SUBMODULE_H\n \n+struct repository;\n struct diff_options;\n struct argv_array;\n struct oid_array;\n@@ -46,6 +47,7 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\n \t\t\t\t\t\t     const char *arg, int unset);\n void load_submodule_cache(void);\n extern void gitmodules_config(void);\n+extern void repo_read_gitmodules(struct repository *repo);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n extern int is_submodule_initialized(const char *path);\n /*\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322768","messageId":"20170620191951.84791-8-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 07/20] path: create path.h","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:38Z","receivedAt":"2017-06-20T19:23:20Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Move all path related declarations from cache.h to a new path.h header\nfile.  This makes cache.h smaller and makes it easier to add new path\nrelated functions.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h | 59 +----------------------------------------------------------\n path.c  |  1 +\n path.h  | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 64 insertions(+), 58 deletions(-)\n create mode 100644 path.h\n\ndiff --git a/cache.h b/cache.h\nindex cd64cbc81..c958fc3ce 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -11,6 +11,7 @@\n #include \"string-list.h\"\n #include \"pack-revindex.h\"\n #include \"hash.h\"\n+#include \"path.h\"\n \n #ifndef platform_SHA_CTX\n /*\n@@ -892,64 +893,6 @@ extern void check_repository_format(void);\n #define DATA_CHANGED    0x0020\n #define TYPE_CHANGED    0x0040\n \n-/*\n- * Return a statically allocated filename, either generically (mkpath), in\n- * the repository directory (git_path), or in a submodule's repository\n- * directory (git_path_submodule). In all cases, note that the result\n- * may be overwritten by another call to _any_ of the functions. Consider\n- * using the safer \"dup\" or \"strbuf\" formats below (in some cases, the\n- * unsafe versions have already been removed).\n- */\n-extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n-extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n-extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n-\n-extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)\n-\t__attribute__((format (printf, 3, 4)));\n-extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n-extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n-extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n-extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,\n-\t\t\t\t     const char *fmt, ...)\n-\t__attribute__((format (printf, 3, 4)));\n-extern char *git_pathdup(const char *fmt, ...)\n-\t__attribute__((format (printf, 1, 2)));\n-extern char *mkpathdup(const char *fmt, ...)\n-\t__attribute__((format (printf, 1, 2)));\n-extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n-\n-extern void report_linked_checkout_garbage(void);\n-\n-/*\n- * You can define a static memoized git path like:\n- *\n- *    static GIT_PATH_FUNC(git_path_foo, \"FOO\");\n- *\n- * or use one of the global ones below.\n- */\n-#define GIT_PATH_FUNC(func, filename) \\\n-\tconst char *func(void) \\\n-\t{ \\\n-\t\tstatic char *ret; \\\n-\t\tif (!ret) \\\n-\t\t\tret = git_pathdup(filename); \\\n-\t\treturn ret; \\\n-\t}\n-\n-const char *git_path_cherry_pick_head(void);\n-const char *git_path_revert_head(void);\n-const char *git_path_squash_msg(void);\n-const char *git_path_merge_msg(void);\n-const char *git_path_merge_rr(void);\n-const char *git_path_merge_mode(void);\n-const char *git_path_merge_head(void);\n-const char *git_path_fetch_head(void);\n-const char *git_path_shallow(void);\n-\n /*\n  * Return the name of the file in the local object database that would\n  * be used to store a loose object with the specified sha1.  The\ndiff --git a/path.c b/path.c\nindex e4abea083..41c861c96 100644\n--- a/path.c\n+++ b/path.c\n@@ -8,6 +8,7 @@\n #include \"dir.h\"\n #include \"worktree.h\"\n #include \"submodule-config.h\"\n+#include \"path.h\"\n \n static int get_st_mode_bits(const char *path, int *mode)\n {\ndiff --git a/path.h b/path.h\nnew file mode 100644\nindex 000000000..522cd029b\n--- /dev/null\n+++ b/path.h\n@@ -0,0 +1,62 @@\n+#ifndef PATH_H\n+#define PATH_H\n+\n+/*\n+ * Return a statically allocated filename, either generically (mkpath), in\n+ * the repository directory (git_path), or in a submodule's repository\n+ * directory (git_path_submodule). In all cases, note that the result\n+ * may be overwritten by another call to _any_ of the functions. Consider\n+ * using the safer \"dup\" or \"strbuf\" formats below (in some cases, the\n+ * unsafe versions have already been removed).\n+ */\n+extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n+extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n+extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n+\n+extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n+extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,\n+\t\t\t\t     const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n+extern char *git_pathdup(const char *fmt, ...)\n+\t__attribute__((format (printf, 1, 2)));\n+extern char *mkpathdup(const char *fmt, ...)\n+\t__attribute__((format (printf, 1, 2)));\n+extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+\n+extern void report_linked_checkout_garbage(void);\n+\n+/*\n+ * You can define a static memoized git path like:\n+ *\n+ *    static GIT_PATH_FUNC(git_path_foo, \"FOO\");\n+ *\n+ * or use one of the global ones below.\n+ */\n+#define GIT_PATH_FUNC(func, filename) \\\n+\tconst char *func(void) \\\n+\t{ \\\n+\t\tstatic char *ret; \\\n+\t\tif (!ret) \\\n+\t\t\tret = git_pathdup(filename); \\\n+\t\treturn ret; \\\n+\t}\n+\n+const char *git_path_cherry_pick_head(void);\n+const char *git_path_revert_head(void);\n+const char *git_path_squash_msg(void);\n+const char *git_path_merge_msg(void);\n+const char *git_path_merge_rr(void);\n+const char *git_path_merge_mode(void);\n+const char *git_path_merge_head(void);\n+const char *git_path_fetch_head(void);\n+const char *git_path_shallow(void);\n+\n+#endif /* PATH_H */\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322769","messageId":"20170620191951.84791-13-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 12/20] path: add repo_git_path and strbuf_repo_git_path","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:43Z","receivedAt":"2017-06-20T19:23:21Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce 'repo_git_path' and 'strbuf_repo_git_path' which take a\nrepository struct and constructs a path into the repository's git\ndirectory.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 21 +++++++++++++++++++++\n path.h |  8 ++++++++\n 2 files changed, 29 insertions(+)\n\ndiff --git a/path.c b/path.c\nindex c6832a30e..3d223e0b2 100644\n--- a/path.c\n+++ b/path.c\n@@ -422,6 +422,27 @@ static void do_git_path(const struct repository *repo,\n \tstrbuf_cleanup_path(buf);\n }\n \n+char *repo_git_path(const struct repository *repo,\n+\t\t    const char *fmt, ...)\n+{\n+\tstruct strbuf path = STRBUF_INIT;\n+\tva_list args;\n+\tva_start(args, fmt);\n+\tdo_git_path(repo, NULL, &path, fmt, args);\n+\tva_end(args);\n+\treturn strbuf_detach(&path, NULL);\n+}\n+\n+void strbuf_repo_git_path(struct strbuf *sb,\n+\t\t\t  const struct repository *repo,\n+\t\t\t  const char *fmt, ...)\n+{\n+\tva_list args;\n+\tva_start(args, fmt);\n+\tdo_git_path(repo, NULL, sb, fmt, args);\n+\tva_end(args);\n+}\n+\n char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n {\n \tva_list args;\ndiff --git a/path.h b/path.h\nindex 568d63be5..c779c4aa2 100644\n--- a/path.h\n+++ b/path.h\n@@ -35,6 +35,14 @@ extern char *mkpathdup(const char *fmt, ...)\n extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)\n \t__attribute__((format (printf, 2, 3)));\n \n+extern char *repo_git_path(const struct repository *repo,\n+\t\t\t   const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern void strbuf_repo_git_path(struct strbuf *sb,\n+\t\t\t\t const struct repository *repo,\n+\t\t\t\t const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n+\n extern void report_linked_checkout_garbage(void);\n \n /*\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322770","messageId":"20170620191951.84791-6-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 05/20] environment: place key repository state in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:36Z","receivedAt":"2017-06-20T19:23:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate 'git_dir', 'git_common_dir', 'git_object_dir', 'git_index_file',\n'git_graft_file', and 'namespace' to be stored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h       |  1 -\n environment.c | 58 +++++++++++++---------------------------------------------\n path.c        | 11 ++++++-----\n setup.c       | 17 +++++++++++++++--\n 4 files changed, 34 insertions(+), 53 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 7c81749a9..cd64cbc81 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -771,7 +771,6 @@ extern int core_apply_sparse_checkout;\n extern int precomposed_unicode;\n extern int protect_hfs;\n extern int protect_ntfs;\n-extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n \n /*\n  * Include broken refs in all ref iterations, which will\ndiff --git a/environment.c b/environment.c\nindex e035f6372..aa79ef83e 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,7 @@\n  * are.\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"refs.h\"\n #include \"fmt-merge-msg.h\"\n@@ -101,10 +102,6 @@ static const char *namespace;\n \n static const char *super_prefix;\n \n-static const char *git_dir, *git_common_dir;\n-static char *git_object_dir, *git_index_file, *git_graft_file;\n-int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -148,41 +145,11 @@ static char *expand_namespace(const char *raw_namespace)\n \treturn strbuf_detach(&buf, NULL);\n }\n \n-static char *git_path_from_env(const char *envvar, const char *git_dir,\n-\t\t\t       const char *path, int *fromenv)\n-{\n-\tconst char *value = getenv(envvar);\n-\tif (!value)\n-\t\treturn xstrfmt(\"%s/%s\", git_dir, path);\n-\tif (fromenv)\n-\t\t*fromenv = 1;\n-\treturn xstrdup(value);\n-}\n-\n void setup_git_env(void)\n {\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *gitfile;\n \tconst char *shallow_file;\n \tconst char *replace_ref_base;\n \n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n-\tif (!git_dir) {\n-\t\tif (!startup_info->have_repository)\n-\t\t\tBUG(\"setup_git_env called without repository\");\n-\t\tgit_dir = DEFAULT_GIT_DIR_ENVIRONMENT;\n-\t}\n-\tgitfile = read_gitfile(git_dir);\n-\tgit_dir = xstrdup(gitfile ? gitfile : git_dir);\n-\tif (get_common_dir(&sb, git_dir))\n-\t\tgit_common_dir_env = 1;\n-\tgit_common_dir = strbuf_detach(&sb, NULL);\n-\tgit_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,\n-\t\t\t\t\t   \"objects\", &git_db_env);\n-\tgit_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,\n-\t\t\t\t\t   \"index\", &git_index_env);\n-\tgit_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, git_common_dir,\n-\t\t\t\t\t   \"info/grafts\", &git_graft_env);\n \tif (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))\n \t\tcheck_replace_refs = 0;\n \treplace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);\n@@ -203,21 +170,21 @@ int is_bare_repository(void)\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n-\t\t|| git_dir;\n+\t\t|| the_repository->gitdir;\n }\n \n const char *get_git_dir(void)\n {\n-\tif (!git_dir)\n+\tif (!the_repository->gitdir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_dir;\n+\treturn the_repository->gitdir;\n }\n \n const char *get_git_common_dir(void)\n {\n-\tif (!git_dir)\n+\tif (!the_repository->commondir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_common_dir;\n+\treturn the_repository->commondir;\n }\n \n const char *get_git_namespace(void)\n@@ -273,9 +240,9 @@ const char *get_git_work_tree(void)\n \n char *get_object_directory(void)\n {\n-\tif (!git_object_dir)\n+\tif (!the_repository->objectdir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_object_dir;\n+\treturn the_repository->objectdir;\n }\n \n int odb_mkstemp(struct strbuf *template, const char *pattern)\n@@ -313,22 +280,23 @@ int odb_pack_keep(const char *name)\n \n char *get_index_file(void)\n {\n-\tif (!git_index_file)\n+\tif (!the_repository->index_file)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_index_file;\n+\treturn the_repository->index_file;\n }\n \n char *get_graft_file(void)\n {\n-\tif (!git_graft_file)\n+\tif (!the_repository->graft_file)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_graft_file;\n+\treturn the_repository->graft_file;\n }\n \n int set_git_dir(const char *path)\n {\n \tif (setenv(GIT_DIR_ENVIRONMENT, path, 1))\n \t\treturn error(\"Could not set GIT_DIR to '%s'\", path);\n+\trepo_set_gitdir(the_repository, path);\n \tsetup_git_env();\n \treturn 0;\n }\ndiff --git a/path.c b/path.c\nindex c1cb1cf62..e4abea083 100644\n--- a/path.c\n+++ b/path.c\n@@ -2,6 +2,7 @@\n  * Utilities for paths and pathnames\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"dir.h\"\n@@ -355,7 +356,7 @@ void report_linked_checkout_garbage(void)\n \tconst struct common_dir *p;\n \tint len;\n \n-\tif (!git_common_dir_env)\n+\tif (!the_repository->different_commondir)\n \t\treturn;\n \tstrbuf_addf(&sb, \"%s/\", get_git_dir());\n \tlen = sb.len;\n@@ -374,17 +375,17 @@ void report_linked_checkout_garbage(void)\n static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n {\n \tconst char *base = buf->buf + git_dir_len;\n-\tif (git_graft_env && is_dir_file(base, \"info\", \"grafts\"))\n+\tif (is_dir_file(base, \"info\", \"grafts\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      get_graft_file(), strlen(get_graft_file()));\n-\telse if (git_index_env && !strcmp(base, \"index\"))\n+\telse if (!strcmp(base, \"index\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      get_index_file(), strlen(get_index_file()));\n-\telse if (git_db_env && dir_prefix(base, \"objects\"))\n+\telse if (dir_prefix(base, \"objects\"))\n \t\treplace_dir(buf, git_dir_len + 7, get_object_directory());\n \telse if (git_hooks_path && dir_prefix(base, \"hooks\"))\n \t\treplace_dir(buf, git_dir_len + 5, git_hooks_path);\n-\telse if (git_common_dir_env)\n+\telse if (the_repository->different_commondir)\n \t\tupdate_common_dir(buf, git_dir_len, NULL);\n }\n \ndiff --git a/setup.c b/setup.c\nindex b477faa44..860507e1f 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"dir.h\"\n #include \"string-list.h\"\n@@ -398,6 +399,11 @@ void setup_work_tree(void)\n \tif (getenv(GIT_WORK_TREE_ENVIRONMENT))\n \t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, \".\", 1);\n \n+\t/*\n+\t * NEEDSWORK: this call can essentially be set_git_dir(get_git_dir())\n+\t * which can cause some problems when trying to free the old value of\n+\t * gitdir.\n+\t */\n \tset_git_dir(remove_leading_path(git_dir, work_tree));\n \tinitialized = 1;\n }\n@@ -1108,8 +1114,15 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t * the user has set GIT_DIR.  It may be beneficial to disallow bogus\n \t * GIT_DIR values at some point in the future.\n \t */\n-\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT))\n-\t\tsetup_git_env();\n+\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT)) {\n+\t\tif (!the_repository->gitdir) {\n+\t\t\tconst char *gitdir = getenv(GIT_DIR_ENVIRONMENT);\n+\t\t\tif (!gitdir)\n+\t\t\t\tgitdir = DEFAULT_GIT_DIR_ENVIRONMENT;\n+\t\t\trepo_set_gitdir(the_repository, gitdir);\n+\t\t\tsetup_git_env();\n+\t\t}\n+\t}\n \n \tstrbuf_release(&dir);\n \tstrbuf_release(&gitdir);\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322771","messageId":"20170620191951.84791-11-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 10/20] path: convert do_git_path to take a 'struct repository'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:41Z","receivedAt":"2017-06-20T19:23:24Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"In preparation to adding 'git_path' like functions which operate on a\n'struct repository' convert 'do_git_path' to take a 'struct repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 42 ++++++++++++++++++++++++++++--------------\n 1 file changed, 28 insertions(+), 14 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 9be6804a9..76a872297 100644\n--- a/path.c\n+++ b/path.c\n@@ -371,33 +371,47 @@ void report_linked_checkout_garbage(void)\n \tstrbuf_release(&sb);\n }\n \n-static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n+static void adjust_git_path(const struct repository *repo,\n+\t\t\t    struct strbuf *buf, int git_dir_len)\n {\n \tconst char *base = buf->buf + git_dir_len;\n \tif (is_dir_file(base, \"info\", \"grafts\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n-\t\t\t      get_graft_file(), strlen(get_graft_file()));\n+\t\t\t      repo->graft_file, strlen(repo->graft_file));\n \telse if (!strcmp(base, \"index\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n-\t\t\t      get_index_file(), strlen(get_index_file()));\n+\t\t\t      repo->index_file, strlen(repo->index_file));\n \telse if (dir_prefix(base, \"objects\"))\n-\t\treplace_dir(buf, git_dir_len + 7, get_object_directory());\n+\t\treplace_dir(buf, git_dir_len + 7, repo->objectdir);\n \telse if (git_hooks_path && dir_prefix(base, \"hooks\"))\n \t\treplace_dir(buf, git_dir_len + 5, git_hooks_path);\n-\telse if (the_repository->different_commondir)\n-\t\tupdate_common_dir(buf, git_dir_len, get_git_common_dir());\n+\telse if (repo->different_commondir)\n+\t\tupdate_common_dir(buf, git_dir_len, repo->commondir);\n }\n \n-static void do_git_path(const struct worktree *wt, struct strbuf *buf,\n+static void strbuf_worktree_gitdir(struct strbuf *buf,\n+\t\t\t\t   const struct repository *repo,\n+\t\t\t\t   const struct worktree *wt)\n+{\n+\tif (!wt)\n+\t\tstrbuf_addstr(buf, repo->gitdir);\n+\telse if (!wt->id)\n+\t\tstrbuf_addstr(buf, repo->commondir);\n+\telse\n+\t\tstrbuf_git_common_path(buf, repo, \"worktrees/%s\", wt->id);\n+}\n+\n+static void do_git_path(const struct repository *repo,\n+\t\t\tconst struct worktree *wt, struct strbuf *buf,\n \t\t\tconst char *fmt, va_list args)\n {\n \tint gitdir_len;\n-\tstrbuf_addstr(buf, get_worktree_git_dir(wt));\n+\tstrbuf_worktree_gitdir(buf, repo, wt);\n \tif (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))\n \t\tstrbuf_addch(buf, '/');\n \tgitdir_len = buf->len;\n \tstrbuf_vaddf(buf, fmt, args);\n-\tadjust_git_path(buf, gitdir_len);\n+\tadjust_git_path(repo, buf, gitdir_len);\n \tstrbuf_cleanup_path(buf);\n }\n \n@@ -406,7 +420,7 @@ char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n \tva_list args;\n \tstrbuf_reset(buf);\n \tva_start(args, fmt);\n-\tdo_git_path(NULL, buf, fmt, args);\n+\tdo_git_path(the_repository, NULL, buf, fmt, args);\n \tva_end(args);\n \treturn buf->buf;\n }\n@@ -415,7 +429,7 @@ void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)\n {\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_path(NULL, sb, fmt, args);\n+\tdo_git_path(the_repository, NULL, sb, fmt, args);\n \tva_end(args);\n }\n \n@@ -424,7 +438,7 @@ const char *git_path(const char *fmt, ...)\n \tstruct strbuf *pathname = get_pathname();\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_path(NULL, pathname, fmt, args);\n+\tdo_git_path(the_repository, NULL, pathname, fmt, args);\n \tva_end(args);\n \treturn pathname->buf;\n }\n@@ -434,7 +448,7 @@ char *git_pathdup(const char *fmt, ...)\n \tstruct strbuf path = STRBUF_INIT;\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_path(NULL, &path, fmt, args);\n+\tdo_git_path(the_repository, NULL, &path, fmt, args);\n \tva_end(args);\n \treturn strbuf_detach(&path, NULL);\n }\n@@ -465,7 +479,7 @@ const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)\n \tstruct strbuf *pathname = get_pathname();\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_path(wt, pathname, fmt, args);\n+\tdo_git_path(the_repository, wt, pathname, fmt, args);\n \tva_end(args);\n \treturn pathname->buf;\n }\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322772","messageId":"20170620191951.84791-12-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:42Z","receivedAt":"2017-06-20T19:23:25Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"When working with worktrees the git directory is split into two part,\nthe per-worktree gitdir and a commondir which contains things which are\nshared among all worktrees (like the object store).  With this notion of\nhaving a split git directory, 557bd833b (git_path(): be aware of file\nrelocation in $GIT_DIR) and c7b3a3d2f ($GIT_COMMON_DIR: a new\nenvironment variable) changed the way that 'git_path()' functioned so\nthat paths would be adjusted if they referred to files or directories\nthat are stored in the commondir or have been changed via an environment\nvariable.\n\nOne interesting problem with this is the index file as it is not shared\nacross worktrees yet when asking for a path to a specific worktree's\nindex it will be replaced with a path to the current worktree's index.\nIn order to prevent this, teach 'adjuct_git_path' to replace the\npath to the index with the path recorded in a repository (which would be\nthe current, active worktree) only when not asked to construct a path\nfor a specific worktree.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 11 +++++++++--\n 1 file changed, 9 insertions(+), 2 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 76a872297..c6832a30e 100644\n--- a/path.c\n+++ b/path.c\n@@ -372,13 +372,20 @@ void report_linked_checkout_garbage(void)\n }\n \n static void adjust_git_path(const struct repository *repo,\n+\t\t\t    const struct worktree *wt,\n \t\t\t    struct strbuf *buf, int git_dir_len)\n {\n \tconst char *base = buf->buf + git_dir_len;\n \tif (is_dir_file(base, \"info\", \"grafts\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      repo->graft_file, strlen(repo->graft_file));\n-\telse if (!strcmp(base, \"index\"))\n+\t/*\n+\t * Only try to replace the path '$gitdir/index' with the index file\n+\t * recorded in the repository when not constructing a path for a\n+\t * worktree.  This way we can retrieve the correct path to a particular\n+\t * worktree's index file.\n+\t */\n+\telse if (!wt && !strcmp(base, \"index\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      repo->index_file, strlen(repo->index_file));\n \telse if (dir_prefix(base, \"objects\"))\n@@ -411,7 +418,7 @@ static void do_git_path(const struct repository *repo,\n \t\tstrbuf_addch(buf, '/');\n \tgitdir_len = buf->len;\n \tstrbuf_vaddf(buf, fmt, args);\n-\tadjust_git_path(repo, buf, gitdir_len);\n+\tadjust_git_path(repo, wt, buf, gitdir_len);\n \tstrbuf_cleanup_path(buf);\n }\n \n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322773","messageId":"20170620191951.84791-7-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 06/20] environment: store worktree in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:37Z","receivedAt":"2017-06-20T19:23:26Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate 'work_tree' to be stored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n environment.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex aa79ef83e..3fd4b1084 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -96,7 +96,6 @@ int ignore_untracked_cache_config;\n \n /* This is set by setup_git_dir_gently() and/or git_default_config() */\n char *git_work_tree_cfg;\n-static char *work_tree;\n \n static const char *namespace;\n \n@@ -223,19 +222,19 @@ void set_git_work_tree(const char *new_work_tree)\n {\n \tif (git_work_tree_initialized) {\n \t\tnew_work_tree = real_path(new_work_tree);\n-\t\tif (strcmp(new_work_tree, work_tree))\n+\t\tif (strcmp(new_work_tree, the_repository->worktree))\n \t\t\tdie(\"internal error: work tree has already been set\\n\"\n \t\t\t    \"Current worktree: %s\\nNew worktree: %s\",\n-\t\t\t    work_tree, new_work_tree);\n+\t\t\t    the_repository->worktree, new_work_tree);\n \t\treturn;\n \t}\n \tgit_work_tree_initialized = 1;\n-\twork_tree = real_pathdup(new_work_tree, 1);\n+\trepo_set_worktree(the_repository, new_work_tree);\n }\n \n const char *get_git_work_tree(void)\n {\n-\treturn work_tree;\n+\treturn the_repository->worktree;\n }\n \n char *get_object_directory(void)\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322774","messageId":"20170620191951.84791-4-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 03/20] environment: remove namespace_len variable","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:34Z","receivedAt":"2017-06-20T19:23:27Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Use 'skip_prefix' instead of 'starts_with' so that we can drop the need\nto keep around 'namespace_len'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n environment.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex a73b08f5d..e035f6372 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -98,7 +98,6 @@ char *git_work_tree_cfg;\n static char *work_tree;\n \n static const char *namespace;\n-static size_t namespace_len;\n \n static const char *super_prefix;\n \n@@ -190,7 +189,6 @@ void setup_git_env(void)\n \tgit_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base\n \t\t\t\t\t\t\t  : \"refs/replace/\");\n \tnamespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));\n-\tnamespace_len = strlen(namespace);\n \tshallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);\n \tif (shallow_file)\n \t\tset_alternate_shallow_file(shallow_file, 0);\n@@ -231,9 +229,10 @@ const char *get_git_namespace(void)\n \n const char *strip_namespace(const char *namespaced_ref)\n {\n-\tif (!starts_with(namespaced_ref, get_git_namespace()))\n-\t\treturn NULL;\n-\treturn namespaced_ref + namespace_len;\n+\tconst char *out;\n+\tif (skip_prefix(namespaced_ref, get_git_namespace(), &out))\n+\t\treturn out;\n+\treturn NULL;\n }\n \n const char *get_super_prefix(void)\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322775","messageId":"20170620191951.84791-2-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 01/20] setup: don't perform lazy initialization of repository state","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:32Z","receivedAt":"2017-06-20T19:23:29Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Under some circumstances (bogus GIT_DIR value or the discovered gitdir\nis '.git') 'setup_git_directory()' won't initialize key repository\nstate.  This leads to inconsistent state after running the setup code.\nTo account for this inconsistent state, lazy initialization is done once\na caller asks for the repository's gitdir or some other piece of\nrepository state.  This is confusing and can be error prone.\n\nInstead let's tighten the expected outcome of 'setup_git_directory()'\nand ensure that it initializes repository state in all cases that would\nhave been handled by lazy initialization.\n\nThis also lets us drop the requirement to have 'have_git_dir()' check if\nthe environment variable GIT_DIR was set as that will be handled by the\nend of the setup code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h       |  2 ++\n environment.c | 17 ++++++++---------\n setup.c       | 14 ++++++++++++++\n 3 files changed, 24 insertions(+), 9 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 96055c222..7c81749a9 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -462,6 +462,8 @@ static inline enum object_type object_type(unsigned int mode)\n  */\n extern const char * const local_repo_env[];\n \n+extern void setup_git_env(void);\n+\n /*\n  * Returns true iff we have a configured git repository (either via\n  * setup_git_directory, or in the environment via $GIT_DIR).\ndiff --git a/environment.c b/environment.c\nindex d40b21fb7..a73b08f5d 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -160,7 +160,7 @@ static char *git_path_from_env(const char *envvar, const char *git_dir,\n \treturn xstrdup(value);\n }\n \n-static void setup_git_env(void)\n+void setup_git_env(void)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *gitfile;\n@@ -205,28 +205,27 @@ int is_bare_repository(void)\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n-\t\t|| git_dir\n-\t\t|| getenv(GIT_DIR_ENVIRONMENT);\n+\t\t|| git_dir;\n }\n \n const char *get_git_dir(void)\n {\n \tif (!git_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_dir;\n }\n \n const char *get_git_common_dir(void)\n {\n \tif (!git_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_common_dir;\n }\n \n const char *get_git_namespace(void)\n {\n \tif (!namespace)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn namespace;\n }\n \n@@ -276,7 +275,7 @@ const char *get_git_work_tree(void)\n char *get_object_directory(void)\n {\n \tif (!git_object_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_object_dir;\n }\n \n@@ -316,14 +315,14 @@ int odb_pack_keep(const char *name)\n char *get_index_file(void)\n {\n \tif (!git_index_file)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_index_file;\n }\n \n char *get_graft_file(void)\n {\n \tif (!git_graft_file)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_graft_file;\n }\n \ndiff --git a/setup.c b/setup.c\nindex 358fbc2e5..24a738b0d 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1091,6 +1091,20 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \tstartup_info->have_repository = !nongit_ok || !*nongit_ok;\n \tstartup_info->prefix = prefix;\n \n+\t/*\n+\t * Not all paths through the setup code will call 'set_git_dir()' (which\n+\t * directly sets up the environment) so in order to guarantee that the\n+\t * environment is in a consistent state after setup, explicitly setup\n+\t * the environment if we have a repository.\n+\t *\n+\t * NEEDSWORK: currently we allow bogus GIT_DIR values to be set in some\n+\t * code paths so we also need to explicitly setup the environment if\n+\t * the user has set GIT_DIR.  It may be beneficial to disallow bogus\n+\t * GIT_DIR values at some point in the future.\n+\t */\n+\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT))\n+\t\tsetup_git_env();\n+\n \tstrbuf_release(&dir);\n \tstrbuf_release(&gitdir);\n \n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322776","messageId":"20170620191951.84791-14-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 13/20] path: add repo_worktree_path and strbuf_repo_worktree_path","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:44Z","receivedAt":"2017-06-20T19:23:30Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce 'repo_worktree_path' and 'strbuf_repo_worktree_path' which\ntake a repository struct and constructs a path relative to the\nrepository's worktree.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 41 +++++++++++++++++++++++++++++++++++++++++\n path.h |  8 ++++++++\n 2 files changed, 49 insertions(+)\n\ndiff --git a/path.c b/path.c\nindex 3d223e0b2..a32c19547 100644\n--- a/path.c\n+++ b/path.c\n@@ -512,6 +512,47 @@ const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)\n \treturn pathname->buf;\n }\n \n+static void do_worktree_path(const struct repository *repo,\n+\t\t\t     struct strbuf *buf,\n+\t\t\t     const char *fmt, va_list args)\n+{\n+\tstrbuf_addstr(buf, repo->worktree);\n+\tif(buf->len && !is_dir_sep(buf->buf[buf->len - 1]))\n+\t\tstrbuf_addch(buf, '/');\n+\n+\tstrbuf_vaddf(buf, fmt, args);\n+\tstrbuf_cleanup_path(buf);\n+}\n+\n+char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)\n+{\n+\tstruct strbuf path = STRBUF_INIT;\n+\tva_list args;\n+\n+\tif (!repo->worktree)\n+\t\treturn NULL;\n+\n+\tva_start(args, fmt);\n+\tdo_worktree_path(repo, &path, fmt, args);\n+\tva_end(args);\n+\n+\treturn strbuf_detach(&path, NULL);\n+}\n+\n+void strbuf_repo_worktree_path(struct strbuf *sb,\n+\t\t\t       const struct repository *repo,\n+\t\t\t       const char *fmt, ...)\n+{\n+\tva_list args;\n+\n+\tif (!repo->worktree)\n+\t\treturn;\n+\n+\tva_start(args, fmt);\n+\tdo_worktree_path(repo, sb, fmt, args);\n+\tva_end(args);\n+}\n+\n /* Returns 0 on success, negative on failure. */\n static int do_submodule_path(struct strbuf *buf, const char *path,\n \t\t\t     const char *fmt, va_list args)\ndiff --git a/path.h b/path.h\nindex c779c4aa2..9541620c7 100644\n--- a/path.h\n+++ b/path.h\n@@ -43,6 +43,14 @@ extern void strbuf_repo_git_path(struct strbuf *sb,\n \t\t\t\t const char *fmt, ...)\n \t__attribute__((format (printf, 3, 4)));\n \n+extern char *repo_worktree_path(const struct repository *repo,\n+\t\t\t\tconst char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern void strbuf_repo_worktree_path(struct strbuf *sb,\n+\t\t\t\t      const struct repository *repo,\n+\t\t\t\t      const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n+\n extern void report_linked_checkout_garbage(void);\n \n /*\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322777","messageId":"20170620191951.84791-10-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v3 09/20] path: convert strbuf_git_common_path to take a 'struct repository'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T19:19:40Z","receivedAt":"2017-06-20T19:23:31Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c     | 13 ++++++++-----\n path.h     |  8 ++++++--\n worktree.c |  3 ++-\n 3 files changed, 16 insertions(+), 8 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 2434921d8..9be6804a9 100644\n--- a/path.c\n+++ b/path.c\n@@ -524,11 +524,12 @@ int strbuf_git_path_submodule(struct strbuf *buf, const char *path,\n \treturn err;\n }\n \n-static void do_git_common_path(struct strbuf *buf,\n+static void do_git_common_path(const struct repository *repo,\n+\t\t\t       struct strbuf *buf,\n \t\t\t       const char *fmt,\n \t\t\t       va_list args)\n {\n-\tstrbuf_addstr(buf, get_git_common_dir());\n+\tstrbuf_addstr(buf, repo->commondir);\n \tif (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))\n \t\tstrbuf_addch(buf, '/');\n \tstrbuf_vaddf(buf, fmt, args);\n@@ -540,16 +541,18 @@ const char *git_common_path(const char *fmt, ...)\n \tstruct strbuf *pathname = get_pathname();\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_common_path(pathname, fmt, args);\n+\tdo_git_common_path(the_repository, pathname, fmt, args);\n \tva_end(args);\n \treturn pathname->buf;\n }\n \n-void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_git_common_path(struct strbuf *sb,\n+\t\t\t    const struct repository *repo,\n+\t\t\t    const char *fmt, ...)\n {\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_common_path(sb, fmt, args);\n+\tdo_git_common_path(repo, sb, fmt, args);\n \tva_end(args);\n }\n \ndiff --git a/path.h b/path.h\nindex 522cd029b..568d63be5 100644\n--- a/path.h\n+++ b/path.h\n@@ -1,6 +1,8 @@\n #ifndef PATH_H\n #define PATH_H\n \n+struct repository;\n+\n /*\n  * Return a statically allocated filename, either generically (mkpath), in\n  * the repository directory (git_path), or in a submodule's repository\n@@ -17,8 +19,10 @@ extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)\n \t__attribute__((format (printf, 3, 4)));\n extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)\n \t__attribute__((format (printf, 2, 3)));\n-extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n+extern void strbuf_git_common_path(struct strbuf *sb,\n+\t\t\t\t   const struct repository *repo,\n+\t\t\t\t   const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n \t__attribute__((format (printf, 2, 3)));\n extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,\ndiff --git a/worktree.c b/worktree.c\nindex 2801c6d52..e28ffbeb0 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"refs.h\"\n #include \"strbuf.h\"\n #include \"worktree.h\"\n@@ -76,7 +77,7 @@ static struct worktree *get_linked_worktree(const char *id)\n \tif (!id)\n \t\tdie(\"Missing linked worktree name\");\n \n-\tstrbuf_git_common_path(&path, \"worktrees/%s/gitdir\", id);\n+\tstrbuf_git_common_path(&path, the_repository, \"worktrees/%s/gitdir\", id);\n \tif (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)\n \t\t/* invalid gitdir file */\n \t\tgoto done;\n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322778","messageId":"CAGZ79kYmqRQF8gzWBxLFVuu2=ACySfvdxvJJcuRkbX9CmoNYYQ@mail.gmail.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"Re: [PATCH v3 00/20] repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-20T19:23:48Z","receivedAt":"2017-06-20T19:23:54Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Jun 20, 2017 at 12:19 PM, Brandon Williams <bmwill@google.com> wrote:\n> I decided to split up the original series into three parts in order to make\n> review a little bit easier.  As such this series is dependent on on\n> 'bw/config-h' and 'bw/ls-files-sans-the-index' which should be moving into\n> 'next' soon.  Due to this I was able to greatly shrink this series in terms of\n> number of patches so hopefully it is a little easier to review.\n>\n> As before you can find this series at:\n> https://github.com/bmwill/git/tree/repository-object\n\nIf you plan on building 'foreach' on top of Brandons series,\nmaybe start off the latest version here.\n\n>\n> Chagnes in v3:\n...\n>\n>  * Added an additional initialization function to allow initializing a 'struct\n>    repository' as a submodule of another 'struct repository'.\n\nThis one seems relevant for 'foreach'\n"},{"id":"322779","messageId":"CAGZ79kaUiODQm8KsGOAtAoATNW7mci3DRM=RimXXv-6--9NOKw@mail.gmail.com","threadId":"46082","inReplyTo":"20170620191951.84791-5-bmwill@google.com","subject":"Re: [PATCH v3 04/20] repository: introduce the repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-20T19:57:26Z","receivedAt":"2017-06-20T19:57:32Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Jun 20, 2017 at 12:19 PM, Brandon Williams <bmwill@google.com> wrote:\n> Introduce the repository object 'struct repository' which can be used to\n> hold all state pertaining to a git repository.\n>\n> Some of the benefits of object-ifying a repository are:\n>\n>   1. Make the code base more readable and easier to reason about.\n>\n>   2. Allow for working on multiple repositories, specifically\n>      submodules, within the same process.  Currently the process for\n>      working on a submodule involves setting up an argv_array of options\n>      for a particular command and then launching a child process to\n>      execute the command in the context of the submodule.  This is\n>      clunky and can require lots of little hacks in order to ensure\n>      correctness.  Ideally it would be nice to simply pass a repository\n>      and an options struct to a command.\n>\n>   3. Eliminating reliance on global state will make it easier to\n>      enable the use of threading to improve performance.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n\n> +/*\n> + * Initialize 'repo' based on the provided 'gitdir'.\n> + * Return 0 upon success and a non-zero value upon failure.\n\nNon zero or negative? The point of the question is if we want to\nask users of this function to be cautious early on. So in the future,\ndo we want to rather see\n\n    if (repo_init(...))\n        die(\"you're doomed\");\n\nor rather\n\n    int x = repo_init(...);\n    if (x < 0)\n        die(\"you're doomed\");\n    else if (x == 1)\n        warning(\"you're not doomed, but close.\"\\\n             \"Not distimming the gostaks.\")\n    else\n        ; /* we're fine, carry on with life */\n\nI guess we can still refactor later, it's just one\nthing to thing about when introducing an API\nthat will likely be used a lot down the road.\n\n> +struct repository {\n> +       /* Environment */\n> +       /* Path to the git directory */\n> +       char *gitdir;\n> +\n> +       /* Path to the common git directory */\n> +       char *commondir;\n> +\n> +       /* Path to the repository's object store */\n> +       char *objectdir;\n> +\n> +       /* Path to the repository's graft file */\n> +       char *graft_file;\n> +\n> +       /* Path to the current worktree's index file */\n> +       char *index_file;\n> +\n> +       /* Path to the working directory */\n> +       char *worktree;\n> +\n> +       /* Configurations */\n> +       /*\n> +        * Bit used during initialization to indicate if repository state (like\n> +        * the location of the 'objectdir') should be read from the\n> +        * environment.  By default this bit will be set at the begining of\n> +        * 'repo_init()' so that all repositories will ignore the environment.\n> +        * The exception to this is 'the_repository', which doesn't go through\n> +        * the normal 'repo_init()' process.\n> +        */\n> +       unsigned ignore_env:1;\n> +\n> +       /* Indicate if a repository has a different 'commondir' from 'gitdir' */\n> +       unsigned different_commondir:1;\n> +};\n\nI applaud the effort towards documenting what each variable is\nsupposed to contain. But some of them read like\n\n    /* increments i by one */\n    i++;\n\nwhich is considered bad comment style (it doesn't add\nmore information, it just wastes a line), so specifically for\nall the \"Path to X\" comments:\n* Are they absolute path, or relative path?\n  If relative, then relative to what?\n* Can they be NULL? When?\n\n(* Why do we need so many path?\n    Could one of them be constructed using\n    another and then hardcoding a string relative to it?\n    This question may rather be answered in the commit\n    message)\n"},{"id":"322784","messageId":"CAGZ79kY-x-i8U7KYsRRDzp2FjO7X27G2A6zctujx0xuDXi4L5A@mail.gmail.com","threadId":"46082","inReplyTo":"20170620191951.84791-12-bmwill@google.com","subject":"Re: [PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-20T21:10:11Z","receivedAt":"2017-06-20T21:10:21Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Jun 20, 2017 at 12:19 PM, Brandon Williams <bmwill@google.com> wrote:\n> When working with worktrees the git directory is split into two part,\n> the per-worktree gitdir and a commondir which contains things which are\n> shared among all worktrees (like the object store).  With this notion of\n> having a split git directory, 557bd833b (git_path(): be aware of file\n> relocation in $GIT_DIR) and c7b3a3d2f ($GIT_COMMON_DIR: a new\n> environment variable) changed the way that 'git_path()' functioned so\n> that paths would be adjusted if they referred to files or directories\n> that are stored in the commondir or have been changed via an environment\n> variable.\n>\n> One interesting problem with this is the index file as it is not shared\n> across worktrees yet when asking for a path to a specific worktree's\n> index it will be replaced with a path to the current worktree's index.\n> In order to prevent this, teach 'adjuct_git_path' to replace the\n\nadjust_git_path\n\n> path to the index with the path recorded in a repository (which would be\n> the current, active worktree) only when not asked to construct a path\n> for a specific worktree.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  path.c | 11 +++++++++--\n>  1 file changed, 9 insertions(+), 2 deletions(-)\n>\n> diff --git a/path.c b/path.c\n> index 76a872297..c6832a30e 100644\n> --- a/path.c\n> +++ b/path.c\n> @@ -372,13 +372,20 @@ void report_linked_checkout_garbage(void)\n>  }\n>\n>  static void adjust_git_path(const struct repository *repo,\n> +                           const struct worktree *wt,\n>                             struct strbuf *buf, int git_dir_len)\n>  {\n>         const char *base = buf->buf + git_dir_len;\n>         if (is_dir_file(base, \"info\", \"grafts\"))\n>                 strbuf_splice(buf, 0, buf->len,\n>                               repo->graft_file, strlen(repo->graft_file));\n> -       else if (!strcmp(base, \"index\"))\n> +       /*\n> +        * Only try to replace the path '$gitdir/index' with the index file\n> +        * recorded in the repository when not constructing a path for a\n> +        * worktree.  This way we can retrieve the correct path to a particular\n> +        * worktree's index file.\n> +        */\n> +       else if (!wt && !strcmp(base, \"index\"))\n>                 strbuf_splice(buf, 0, buf->len,\n>                               repo->index_file, strlen(repo->index_file));\n>         else if (dir_prefix(base, \"objects\"))\n> @@ -411,7 +418,7 @@ static void do_git_path(const struct repository *repo,\n>                 strbuf_addch(buf, '/');\n>         gitdir_len = buf->len;\n>         strbuf_vaddf(buf, fmt, args);\n> -       adjust_git_path(repo, buf, gitdir_len);\n> +       adjust_git_path(repo, wt, buf, gitdir_len);\n>         strbuf_cleanup_path(buf);\n>  }\n>\n> --\n> 2.13.1.611.g7e3b11ae1-goog\n>\n"},{"id":"322785","messageId":"20170620143130.6816e85f@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170620191951.84791-5-bmwill@google.com","subject":"Re: [PATCH v3 04/20] repository: introduce the repository object","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-20T21:31:30Z","receivedAt":"2017-06-20T21:31:41Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Tue, 20 Jun 2017 12:19:35 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> Introduce the repository object 'struct repository' which can be used to\n> hold all state pertaining to a git repository.\n> \n> Some of the benefits of object-ifying a repository are:\n> \n>   1. Make the code base more readable and easier to reason about.\n> \n>   2. Allow for working on multiple repositories, specifically\n>      submodules, within the same process.  Currently the process for\n>      working on a submodule involves setting up an argv_array of options\n>      for a particular command and then launching a child process to\n>      execute the command in the context of the submodule.  This is\n>      clunky and can require lots of little hacks in order to ensure\n>      correctness.  Ideally it would be nice to simply pass a repository\n>      and an options struct to a command.\n> \n>   3. Eliminating reliance on global state will make it easier to\n>      enable the use of threading to improve performance.\n\nThese would indeed be nice to have.\n\n> +/* called after setting gitdir */\n> +static void repo_setup_env(struct repository *repo)\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\n> +\tif (!repo->gitdir)\n> +\t\tBUG(\"gitdir wasn't set before setting up the environment\");\n> +\n> +\trepo->different_commondir = find_common_dir(&sb, repo->gitdir,\n> +\t\t\t\t\t\t    !repo->ignore_env);\n> +\trepo->commondir = strbuf_detach(&sb, NULL);\n> +\trepo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,\n> +\t\t\t\t\t    \"objects\", !repo->ignore_env);\n> +\trepo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,\n> +\t\t\t\t\t     \"info/grafts\", !repo->ignore_env);\n> +\trepo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,\n> +\t\t\t\t\t     \"index\", !repo->ignore_env);\n> +}\n\nIt seems that this function is only used once in repo_set_gitdir() -\ncould this be inlined there instead? Then you wouldn't need the comment\nand the !repo->gitdir check.\n\n> +static int verify_repo_format(struct repository_format *format,\n> +\t\t\t      const char *commondir)\n> +{\n> +\tint ret = 0;\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\n> +\tstrbuf_addf(&sb, \"%s/config\", commondir);\n> +\tread_repository_format(format, sb.buf);\n> +\tstrbuf_reset(&sb);\n> +\n> +\tif (verify_repository_format(format, &sb) < 0) {\n> +\t\twarning(\"%s\", sb.buf);\n> +\t\tret = -1;\n> +\t}\n> +\n> +\tstrbuf_release(&sb);\n> +\treturn ret;\n> +}\n\nThis function is confusingly named - firstly, there is already a\nverify_repository_format(), and secondly, this function both reads and\nverifies it.\n\n> +void repo_clear(struct repository *repo)\n> +{\n> +\tfree(repo->gitdir);\n> +\trepo->gitdir = NULL;\n> +\tfree(repo->commondir);\n> +\trepo->commondir = NULL;\n> +\tfree(repo->objectdir);\n> +\trepo->objectdir = NULL;\n> +\tfree(repo->graft_file);\n> +\trepo->graft_file = NULL;\n> +\tfree(repo->index_file);\n> +\trepo->index_file = NULL;\n> +\tfree(repo->worktree);\n> +\trepo->worktree = NULL;\n> +\n> +\tmemset(repo, 0, sizeof(*repo));\n> +}\n\nIf you're going to memset, you probably don't need to set everything to\nNULL.\n\n> +\t/* Configurations */\n> +\t/*\n> +\t * Bit used during initialization to indicate if repository state (like\n> +\t * the location of the 'objectdir') should be read from the\n> +\t * environment.  By default this bit will be set at the begining of\n> +\t * 'repo_init()' so that all repositories will ignore the environment.\n> +\t * The exception to this is 'the_repository', which doesn't go through\n> +\t * the normal 'repo_init()' process.\n> +\t */\n> +\tunsigned ignore_env:1;\n\nIf this is only used during initialization, could this be passed as a\nseparate parameter internally instead of having it here?\n"},{"id":"322787","messageId":"20170620215610.GC60134@google.com","threadId":"46082","inReplyTo":"20170620143130.6816e85f@twelve2.svl.corp.google.com","subject":"Re: [PATCH v3 04/20] repository: introduce the repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-20T21:56:10Z","receivedAt":"2017-06-20T21:56:19Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/20, Jonathan Tan wrote:\n> On Tue, 20 Jun 2017 12:19:35 -0700\n> Brandon Williams <bmwill@google.com> wrote:\n> \n> > Introduce the repository object 'struct repository' which can be used to\n> > hold all state pertaining to a git repository.\n> > \n> > Some of the benefits of object-ifying a repository are:\n> > \n> >   1. Make the code base more readable and easier to reason about.\n> > \n> >   2. Allow for working on multiple repositories, specifically\n> >      submodules, within the same process.  Currently the process for\n> >      working on a submodule involves setting up an argv_array of options\n> >      for a particular command and then launching a child process to\n> >      execute the command in the context of the submodule.  This is\n> >      clunky and can require lots of little hacks in order to ensure\n> >      correctness.  Ideally it would be nice to simply pass a repository\n> >      and an options struct to a command.\n> > \n> >   3. Eliminating reliance on global state will make it easier to\n> >      enable the use of threading to improve performance.\n> \n> These would indeed be nice to have.\n> \n> > +/* called after setting gitdir */\n> > +static void repo_setup_env(struct repository *repo)\n> > +{\n> > +\tstruct strbuf sb = STRBUF_INIT;\n> > +\n> > +\tif (!repo->gitdir)\n> > +\t\tBUG(\"gitdir wasn't set before setting up the environment\");\n> > +\n> > +\trepo->different_commondir = find_common_dir(&sb, repo->gitdir,\n> > +\t\t\t\t\t\t    !repo->ignore_env);\n> > +\trepo->commondir = strbuf_detach(&sb, NULL);\n> > +\trepo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,\n> > +\t\t\t\t\t    \"objects\", !repo->ignore_env);\n> > +\trepo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,\n> > +\t\t\t\t\t     \"info/grafts\", !repo->ignore_env);\n> > +\trepo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,\n> > +\t\t\t\t\t     \"index\", !repo->ignore_env);\n> > +}\n> \n> It seems that this function is only used once in repo_set_gitdir() -\n> could this be inlined there instead? Then you wouldn't need the comment\n> and the !repo->gitdir check.\n\nI'd like to keep them separate as it makes things a little clearer in my\nopinion, smaller functions and the like.\n\n> \n> > +static int verify_repo_format(struct repository_format *format,\n> > +\t\t\t      const char *commondir)\n> > +{\n> > +\tint ret = 0;\n> > +\tstruct strbuf sb = STRBUF_INIT;\n> > +\n> > +\tstrbuf_addf(&sb, \"%s/config\", commondir);\n> > +\tread_repository_format(format, sb.buf);\n> > +\tstrbuf_reset(&sb);\n> > +\n> > +\tif (verify_repository_format(format, &sb) < 0) {\n> > +\t\twarning(\"%s\", sb.buf);\n> > +\t\tret = -1;\n> > +\t}\n> > +\n> > +\tstrbuf_release(&sb);\n> > +\treturn ret;\n> > +}\n> \n> This function is confusingly named - firstly, there is already a\n> verify_repository_format(), and secondly, this function both reads and\n> verifies it.\n\nThis one is static to the file, and i don't think its named confusingly\nas it does just what it says it does. I'm trying to limit how much other\ncode I change so I had to make this function.\n\n> \n> > +void repo_clear(struct repository *repo)\n> > +{\n> > +\tfree(repo->gitdir);\n> > +\trepo->gitdir = NULL;\n> > +\tfree(repo->commondir);\n> > +\trepo->commondir = NULL;\n> > +\tfree(repo->objectdir);\n> > +\trepo->objectdir = NULL;\n> > +\tfree(repo->graft_file);\n> > +\trepo->graft_file = NULL;\n> > +\tfree(repo->index_file);\n> > +\trepo->index_file = NULL;\n> > +\tfree(repo->worktree);\n> > +\trepo->worktree = NULL;\n> > +\n> > +\tmemset(repo, 0, sizeof(*repo));\n> > +}\n> \n> If you're going to memset, you probably don't need to set everything to\n> NULL.\n> \n> > +\t/* Configurations */\n> > +\t/*\n> > +\t * Bit used during initialization to indicate if repository state (like\n> > +\t * the location of the 'objectdir') should be read from the\n> > +\t * environment.  By default this bit will be set at the begining of\n> > +\t * 'repo_init()' so that all repositories will ignore the environment.\n> > +\t * The exception to this is 'the_repository', which doesn't go through\n> > +\t * the normal 'repo_init()' process.\n> > +\t */\n> > +\tunsigned ignore_env:1;\n> \n> If this is only used during initialization, could this be passed as a\n> separate parameter internally instead of having it here?\n\nIt would feel a little wonky to be a parameter as 'the_repository' is\ninitialized differently than a repository would normally be.  Theres\nbeen a lot of cleanup to the setup logic but it would need to be cleaned\nup even more to have this be a param.\n\n-- \nBrandon Williams\n"},{"id":"322788","messageId":"20170620145939.1caa78db@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170620191951.84791-6-bmwill@google.com","subject":"Re: [PATCH v3 05/20] environment: place key repository state in the_repository","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-20T21:59:39Z","receivedAt":"2017-06-20T21:59:49Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Tue, 20 Jun 2017 12:19:36 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> Migrate 'git_dir', 'git_common_dir', 'git_object_dir', 'git_index_file',\n> 'git_graft_file', and 'namespace' to be stored in 'the_repository'.\n> \n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  cache.h       |  1 -\n>  environment.c | 58 +++++++++++++---------------------------------------------\n>  path.c        | 11 ++++++-----\n>  setup.c       | 17 +++++++++++++++--\n>  4 files changed, 34 insertions(+), 53 deletions(-)\n> \n> diff --git a/cache.h b/cache.h\n> index 7c81749a9..cd64cbc81 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -771,7 +771,6 @@ extern int core_apply_sparse_checkout;\n>  extern int precomposed_unicode;\n>  extern int protect_hfs;\n>  extern int protect_ntfs;\n> -extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n\nIn the commit message, it is probably worth mentioning commit 557bd83\nwhich added these fields to attempt rewriting a path in do_git_path()\nonly if the appropriate _env flag is set, and that this patch removes\nthis optimization.\n"},{"id":"322789","messageId":"20170620152308.42984ee7@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170620191951.84791-11-bmwill@google.com","subject":"Re: [PATCH v3 10/20] path: convert do_git_path to take a 'struct repository'","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-20T22:23:08Z","receivedAt":"2017-06-20T22:23:20Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Tue, 20 Jun 2017 12:19:41 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> +static void do_git_path(const struct repository *repo,\n> +\t\t\tconst struct worktree *wt, struct strbuf *buf,\n>  \t\t\tconst char *fmt, va_list args)\n>  {\n>  \tint gitdir_len;\n> -\tstrbuf_addstr(buf, get_worktree_git_dir(wt));\n\nWith this change, the get_worktree_git_dir() function no longer seems to\nbe used from outside - could it be marked static?\n\n> +\tstrbuf_worktree_gitdir(buf, repo, wt);\n>  \tif (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))\n>  \t\tstrbuf_addch(buf, '/');\n>  \tgitdir_len = buf->len;\n>  \tstrbuf_vaddf(buf, fmt, args);\n> -\tadjust_git_path(buf, gitdir_len);\n> +\tadjust_git_path(repo, buf, gitdir_len);\n>  \tstrbuf_cleanup_path(buf);\n>  }\n"},{"id":"322791","messageId":"20170620230200.GB60603@aiede.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170620191951.84791-12-bmwill@google.com","subject":"Re: [PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-06-20T23:02:00Z","receivedAt":"2017-06-20T23:02:12Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nBrandon Williams wrote:\n\n> When working with worktrees the git directory is split into two part,\n> the per-worktree gitdir and a commondir which contains things which are\n> shared among all worktrees (like the object store).  With this notion of\n> having a split git directory, 557bd833b (git_path(): be aware of file\n> relocation in $GIT_DIR) and c7b3a3d2f ($GIT_COMMON_DIR: a new\n> environment variable) changed the way that 'git_path()' functioned so\n> that paths would be adjusted if they referred to files or directories\n> that are stored in the commondir or have been changed via an environment\n> variable.\n>\n> One interesting problem with this is the index file as it is not shared\n> across worktrees yet when asking for a path to a specific worktree's\n> index it will be replaced with a path to the current worktree's index.\n> In order to prevent this, teach 'adjuct_git_path' to replace the\n> path to the index with the path recorded in a repository (which would be\n> the current, active worktree) only when not asked to construct a path\n> for a specific worktree.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  path.c | 11 +++++++++--\n>  1 file changed, 9 insertions(+), 2 deletions(-)\n\nThanks --- this is subtle.  I don't think that what this patch does is\nright.  Commenting below.\n\n> --- a/path.c\n> +++ b/path.c\n> @@ -372,13 +372,20 @@ void report_linked_checkout_garbage(void)\n>  }\n>  \n>  static void adjust_git_path(const struct repository *repo,\n> +\t\t\t    const struct worktree *wt,\n>  \t\t\t    struct strbuf *buf, int git_dir_len)\n>  {\n>  \tconst char *base = buf->buf + git_dir_len;\n>  \tif (is_dir_file(base, \"info\", \"grafts\"))\n>  \t\tstrbuf_splice(buf, 0, buf->len,\n>  \t\t\t      repo->graft_file, strlen(repo->graft_file));\n> -\telse if (!strcmp(base, \"index\"))\n> +\t/*\n> +\t * Only try to replace the path '$gitdir/index' with the index file\n> +\t * recorded in the repository when not constructing a path for a\n> +\t * worktree.  This way we can retrieve the correct path to a particular\n> +\t * worktree's index file.\n> +\t */\n> +\telse if (!wt && !strcmp(base, \"index\"))\n>  \t\tstrbuf_splice(buf, 0, buf->len,\n>  \t\t\t      repo->index_file, strlen(repo->index_file));\n\nSome context that may have been missing: GIT_INDEX_FILE is a low-level\ntool to allow script authors to specify an alternate index file to use\nwhen running commands like \"git read-tree\" or \"git checkout-index\".\n\nThe above would make it not take effect for git_path() callers when\n'wt != NULL'.  As a result, if any caller reaches this code path, then\nscripts specifying GIT_INDEX_FILE would stop working when run from a\nworktree that borrows refs and objects from a separate repository.\nI'm pretty sure that such a subtle flip in behavior based on whether\nthey are in \"git worktree\" created worktree or the main working tree\nis not what the end user would intend, so this looks like a step in\nthe wrong direction.\n\nFortunately this code path doesn't actually get called.\n\nIn fact, rewriting git_path(\"index\") in this function feels to me like\na layering violation.  Shouldn't callers be using get_index_file() to\nexpress their intent more clearly?  That's what all current callers\ndo.\n\nIIUC this came up when a patch from nd/prune-in-worktree (e7a6a3b15,\nrevision.c: --indexed-objects add objects from all worktrees), which\nis currently not in pu, introduced a caller that does call\ngit_path(\"index\").  The old behavior of replacing git_path(\"index\")\nwith $GIT_INDEX_FILE when the latter is set was mostly harmless\nbecause typically GIT_INDEX_FILE is not set, especially when people\nare running \"git prune\".  Patch 05/20 (environment: place key\nrepository state in the_repository) made the substitution harmful: now\nwe would use repo->index_file unconditionally instead of allowing the\nordinary worktree-relative resolution as a fallback when\nGIT_INDEX_FILE is unset.\n\nPossible next steps:\n\n 1. I think we should make git_path less magical and discourage\n    callers from relying on it to handle the GIT_INDEX_FILE envvar.\n    We can do that by removing the !strcmp(base, \"index\") case\n    completely.\n\n 2. Optionally, it is possible to be more cautious by keeping the\n    !strcmp(base, \"index\") case and making it call BUG() to force\n    people not to use it.  This would help steer callers toward\n    get_index_file().  But given that the only caller did not actually\n    want GIT_INDEX_FILE substitution, I don't think that that is\n    necessary or useful.\n\n 3. A docstring for git_path should explain the substitutions it\n    currently makes and more straightforward alternatives that callers\n    can use.\n\n 4. Specifying GIT_INDEX_FILE when running \"git prune\" is a\n    meaningless combination.  It would be nice for \"git prune\" to\n    error out to save the user from confusion.\n\n 5. There are likely other commands that don't make sense with\n    GIT_INDEX_FILE.  Tracking them all down to make them print a\n    meaningful error message might be a bit of a slog, though.\n\n>  \telse if (dir_prefix(base, \"objects\"))\n> @@ -411,7 +418,7 @@ static void do_git_path(const struct repository *repo,\n>  \t\tstrbuf_addch(buf, '/');\n>  \tgitdir_len = buf->len;\n>  \tstrbuf_vaddf(buf, fmt, args);\n> -\tadjust_git_path(repo, buf, gitdir_len);\n> +\tadjust_git_path(repo, wt, buf, gitdir_len);\n>  \tstrbuf_cleanup_path(buf);\n>  }\n\nThanks and hope that helps,\nJonathan\n"},{"id":"322793","messageId":"20170621003903.GD60134@google.com","threadId":"46082","inReplyTo":"20170620230200.GB60603@aiede.mtv.corp.google.com","subject":"Re: [PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-21T00:39:03Z","receivedAt":"2017-06-21T00:39:13Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/20, Jonathan Nieder wrote:\n> Hi,\n> \n> Brandon Williams wrote:\n> \n> > When working with worktrees the git directory is split into two part,\n> > the per-worktree gitdir and a commondir which contains things which are\n> > shared among all worktrees (like the object store).  With this notion of\n> > having a split git directory, 557bd833b (git_path(): be aware of file\n> > relocation in $GIT_DIR) and c7b3a3d2f ($GIT_COMMON_DIR: a new\n> > environment variable) changed the way that 'git_path()' functioned so\n> > that paths would be adjusted if they referred to files or directories\n> > that are stored in the commondir or have been changed via an environment\n> > variable.\n> >\n> > One interesting problem with this is the index file as it is not shared\n> > across worktrees yet when asking for a path to a specific worktree's\n> > index it will be replaced with a path to the current worktree's index.\n> > In order to prevent this, teach 'adjuct_git_path' to replace the\n> > path to the index with the path recorded in a repository (which would be\n> > the current, active worktree) only when not asked to construct a path\n> > for a specific worktree.\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  path.c | 11 +++++++++--\n> >  1 file changed, 9 insertions(+), 2 deletions(-)\n> \n> Thanks --- this is subtle.  I don't think that what this patch does is\n> right.  Commenting below.\n> \n> > --- a/path.c\n> > +++ b/path.c\n> > @@ -372,13 +372,20 @@ void report_linked_checkout_garbage(void)\n> >  }\n> >  \n> >  static void adjust_git_path(const struct repository *repo,\n> > +\t\t\t    const struct worktree *wt,\n> >  \t\t\t    struct strbuf *buf, int git_dir_len)\n> >  {\n> >  \tconst char *base = buf->buf + git_dir_len;\n> >  \tif (is_dir_file(base, \"info\", \"grafts\"))\n> >  \t\tstrbuf_splice(buf, 0, buf->len,\n> >  \t\t\t      repo->graft_file, strlen(repo->graft_file));\n> > -\telse if (!strcmp(base, \"index\"))\n> > +\t/*\n> > +\t * Only try to replace the path '$gitdir/index' with the index file\n> > +\t * recorded in the repository when not constructing a path for a\n> > +\t * worktree.  This way we can retrieve the correct path to a particular\n> > +\t * worktree's index file.\n> > +\t */\n> > +\telse if (!wt && !strcmp(base, \"index\"))\n> >  \t\tstrbuf_splice(buf, 0, buf->len,\n> >  \t\t\t      repo->index_file, strlen(repo->index_file));\n> \n> Some context that may have been missing: GIT_INDEX_FILE is a low-level\n> tool to allow script authors to specify an alternate index file to use\n> when running commands like \"git read-tree\" or \"git checkout-index\".\n> \n> The above would make it not take effect for git_path() callers when\n> 'wt != NULL'.  As a result, if any caller reaches this code path, then\n> scripts specifying GIT_INDEX_FILE would stop working when run from a\n> worktree that borrows refs and objects from a separate repository.\n> I'm pretty sure that such a subtle flip in behavior based on whether\n> they are in \"git worktree\" created worktree or the main working tree\n> is not what the end user would intend, so this looks like a step in\n> the wrong direction.\n> \n> Fortunately this code path doesn't actually get called.\n> \n> In fact, rewriting git_path(\"index\") in this function feels to me like\n> a layering violation.  Shouldn't callers be using get_index_file() to\n> express their intent more clearly?  That's what all current callers\n> do.\n> \n> IIUC this came up when a patch from nd/prune-in-worktree (e7a6a3b15,\n> revision.c: --indexed-objects add objects from all worktrees), which\n> is currently not in pu, introduced a caller that does call\n> git_path(\"index\").  The old behavior of replacing git_path(\"index\")\n> with $GIT_INDEX_FILE when the latter is set was mostly harmless\n> because typically GIT_INDEX_FILE is not set, especially when people\n> are running \"git prune\".  Patch 05/20 (environment: place key\n> repository state in the_repository) made the substitution harmful: now\n> we would use repo->index_file unconditionally instead of allowing the\n> ordinary worktree-relative resolution as a fallback when\n> GIT_INDEX_FILE is unset.\n> \n> Possible next steps:\n> \n>  1. I think we should make git_path less magical and discourage\n>     callers from relying on it to handle the GIT_INDEX_FILE envvar.\n>     We can do that by removing the !strcmp(base, \"index\") case\n>     completely.\n\nFrom our conversation off-line it seems like we agree that this is\nprobably the best course of action.  So I'll plan to drop the case\ncompletely since it isn't even used currently.  I'll also go ahead and\ndrop the graft_file one as well since it doesn't make much sense to keep\nit around when it is only queried for once.\n\n> \n>  2. Optionally, it is possible to be more cautious by keeping the\n>     !strcmp(base, \"index\") case and making it call BUG() to force\n>     people not to use it.  This would help steer callers toward\n>     get_index_file().  But given that the only caller did not actually\n>     want GIT_INDEX_FILE substitution, I don't think that that is\n>     necessary or useful.\n> \n>  3. A docstring for git_path should explain the substitutions it\n>     currently makes and more straightforward alternatives that callers\n>     can use.\n> \n>  4. Specifying GIT_INDEX_FILE when running \"git prune\" is a\n>     meaningless combination.  It would be nice for \"git prune\" to\n>     error out to save the user from confusion.\n> \n>  5. There are likely other commands that don't make sense with\n>     GIT_INDEX_FILE.  Tracking them all down to make them print a\n>     meaningful error message might be a bit of a slog, though.\n> \n> >  \telse if (dir_prefix(base, \"objects\"))\n> > @@ -411,7 +418,7 @@ static void do_git_path(const struct repository *repo,\n> >  \t\tstrbuf_addch(buf, '/');\n> >  \tgitdir_len = buf->len;\n> >  \tstrbuf_vaddf(buf, fmt, args);\n> > -\tadjust_git_path(repo, buf, gitdir_len);\n> > +\tadjust_git_path(repo, wt, buf, gitdir_len);\n> >  \tstrbuf_cleanup_path(buf);\n> >  }\n> \n> Thanks and hope that helps,\n> Jonathan\n\n-- \nBrandon Williams\n"},{"id":"322794","messageId":"20170621021024.GC60603@aiede.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170620191951.84791-12-bmwill@google.com","subject":"Re: [PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-06-21T02:10:24Z","receivedAt":"2017-06-21T02:10:34Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi again,\n\nBrandon Williams wrote:\n\n> When working with worktrees the git directory is split into two part,\n> the per-worktree gitdir and a commondir which contains things which are\n> shared among all worktrees (like the object store).  With this notion of\n> having a split git directory, 557bd833b (git_path(): be aware of file\n> relocation in $GIT_DIR) and c7b3a3d2f ($GIT_COMMON_DIR: a new\n> environment variable) changed the way that 'git_path()' functioned so\n> that paths would be adjusted if they referred to files or directories\n> that are stored in the commondir or have been changed via an environment\n> variable.\n>\n> One interesting problem with this is the index file as it is not shared\n> across worktrees yet when asking for a path to a specific worktree's\n> index it will be replaced with a path to the current worktree's index.\n> In order to prevent this, teach 'adjuct_git_path' to replace the\n> path to the index with the path recorded in a repository (which would be\n> the current, active worktree) only when not asked to construct a path\n> for a specific worktree.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  path.c | 11 +++++++++--\n>  1 file changed, 9 insertions(+), 2 deletions(-)\n\nDigging more into it with your help, I ran into v2.5.0-rc0~143^2~34\nand v2.11.0-rc0~15^2 (git-svn: \"git worktree\" awareness, 2016-10-14),\nwhich uses this function:\n\n -\tmy $index = $ENV{GIT_INDEX_FILE} || \"$ENV{GIT_DIR}/index\";\n +\tmy $index = command_oneline(qw(rev-parse --git-path index));\n\nThat rules out my hope of making git_path stop being aware of the index\nat all.\n\nThat also made it a little clearer to me what is going on with this\nfunction.  I had previously misread !wt as meaning that git_dir is\nnot under worktrees/ (or in other words as !wt->id).  Instead, it\nmeans that the caller does not want to use some other work tree in\npreference to git_dir.\n\nWith that piece in place, the patch starts making more sense to me.\nWhen !wt, repo->index_file is going to have the same value as\ngetenv(\"GIT_INDEX_FILE\") ?: buf->buf already, since repo->index_file\nrefers to the current work tree git dir's index file.  When wt != NULL,\nwe don't want to use that file and have requested to grab the index\nfrom a specific work tree git dir instead.\n\nAnd patch 05/20 (environment: place key repository state in\nthe_repository) had no effect since no one calls worktree_git_path\nwith argument \"index\", nor with a user-specified path.\n\nHow about the following?  I found it a little easier to understand.\n\n-- >8 --\nFrom: Brandon Williams <bmwill@google.com>\nSubject: worktree_git_path: do not let GIT_INDEX_FILE override path to index\n\ngit_path (and variants like strbuf_git_path) is designed to behave\nlike a convenience function that produces a string $GIT_DIR/<path>.\nIn the process, callers automatically get support for path relocation\nvariables like $GIT_OBJECT_DIRECTORY:\n\n- git_path(\"index\") is $GIT_INDEX_FILE when set\n- git_path(\"info/grafts\") is $GIT_GRAFTS_FILE when set\n- git_path(\"objects/<foo>\") is $GIT_OBJECT_DIRECTORY/<foo> when set\n- git_path(\"hooks/<foo>\") is <foo> under core.hookspath when set\n- git_path(\"refs/<foo>\") etc (see path.c::common_list) is relative\n  to $GIT_COMMON_DIR instead of $GIT_DIR\n\nworktree_git_path, by comparison, is designed to resolve files in a\nspecific worktree's git dir and should not perform such relocation.\nDo so by skipping the relocation step in worktree_git_path.\n\nFortunately no current callers of worktree_git_path pass such\narguments.  Noticed due to an interaction between two patches under\nreview, one of which introduced such a caller:\n\n* One made \"git prune\" check the index file in each worktree's git dir\n  (using worktree_git_path(wt, \"index\")) for objects not to prune,\n  triggering the unwanted relocation code by mistake and allowing\n  objects reachable from worktree indices to be pruned if\n  GIT_INDEX_FILE is set.\n\n* The other simplified the relocation logic for index, info/grafts,\n  objects, and hooks to happen unconditionally instead of based on\n  whether environment or configuration variables are set, causing the\n  relocation to trigger even when GIT_INDEX_FILE is not set.\n\n[jn: rewrote commit message; skipped all relocations instead of just\n the index]\n\nChange-Id: I2ba0a48a48b7e9a9c2e3ef97648cf53cb913bdd9\nSigned-off-by: Brandon Williams <bmwill@google.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n path.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/path.c b/path.c\nindex c1cb1cf62..4c3a27a8e 100644\n--- a/path.c\n+++ b/path.c\n@@ -397,7 +397,8 @@ static void do_git_path(const struct worktree *wt, struct strbuf *buf,\n \t\tstrbuf_addch(buf, '/');\n \tgitdir_len = buf->len;\n \tstrbuf_vaddf(buf, fmt, args);\n-\tadjust_git_path(buf, gitdir_len);\n+\tif (!wt)\n+\t\tadjust_git_path(buf, gitdir_len);\n \tstrbuf_cleanup_path(buf);\n }\n \n-- \n2.13.1.611.g7e3b11ae1\n\n"},{"id":"322795","messageId":"20170621023004.GD60603@aiede.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170621021024.GC60603@aiede.mtv.corp.google.com","subject":"Re: [PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-06-21T02:30:04Z","receivedAt":"2017-06-21T02:30:14Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Subject: worktree_git_path() should not use file relocation\n\ngit_path is a convenience function that usually produces a string\n$GIT_DIR/<path>.  Since v2.5.0-rc0~143^2~35 (git_path(): be aware of\nfile relocation in $GIT_DIR, 2014-11-30), as a side benefit callers\nget support for path relocation variables like $GIT_OBJECT_DIRECTORY:\n\n- git_path(\"index\") is $GIT_INDEX_FILE when set\n- git_path(\"info/grafts\") is $GIT_GRAFTS_FILE when set\n- git_path(\"objects/<foo>\") is $GIT_OBJECT_DIRECTORY/<foo> when set\n- git_path(\"hooks/<foo>\") is <foo> under core.hookspath when set\n- git_path(\"refs/<foo>\") etc (see path.c::common_list) is relative\n  to $GIT_COMMON_DIR instead of $GIT_DIR\n\nworktree_git_path, by comparison, is designed to resolve files in a\nspecific worktree's git dir.  Unfortunately, it shares code with\ngit_path and performs the same relocation.  The result is that paths\nthat are meant to be relative to the specified worktree's git dir end\nup replaced by paths from environment variables within the current git\ndir.\n\nLuckily, no current callers pass such arguments.  The relocation was\nnoticed when testing the result of merging two patches under review,\none of which introduces a caller:\n\n* The first patch made git prune check the index file in each\n  worktree's git dir (using worktree_git_path(wt, \"index\")) for\n  objects not to prune.  This would trigger the unwanted relocation\n  when GIT_INDEX_FILE is set, causing objects reachable from the\n  index to be pruned.\n\n* The second patch simplified the relocation logic for index,\n  info/grafts, objects, and hooks to happen unconditionally instead of\n  based on whether environment or configuration variables are set.\n  This caused the relocation to trigger even when GIT_INDEX_FILE is\n  not set.\n\n[jn: rewrote commit message; skipping all relocation instead of just\n GIT_INDEX_FILE]\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nJonathan Nieder wrote:\n\n> How about the following?  I found it a little easier to understand.\n>\n> -- >8 --\n> From: Brandon Williams <bmwill@google.com>\n> Subject: worktree_git_path: do not let GIT_INDEX_FILE override path to index\n[...]\n> Change-Id: I2ba0a48a48b7e9a9c2e3ef97648cf53cb913bdd9\n\nGah, sorry about the stray Change-Id line.  While we're fixing that,\nhere's a version with a slightly clearer commit message.\n\n path.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/path.c b/path.c\nindex c1cb1cf62..4c3a27a8e 100644\n--- a/path.c\n+++ b/path.c\n@@ -397,7 +397,8 @@ static void do_git_path(const struct worktree *wt, struct strbuf *buf,\n \t\tstrbuf_addch(buf, '/');\n \tgitdir_len = buf->len;\n \tstrbuf_vaddf(buf, fmt, args);\n-\tadjust_git_path(buf, gitdir_len);\n+\tif (!wt)\n+\t\tadjust_git_path(buf, gitdir_len);\n \tstrbuf_cleanup_path(buf);\n }\n \n-- \n2.13.1.611.g7e3b11ae1-goog\n\n"},{"id":"322818","messageId":"20170621154330.GA53348@google.com","threadId":"46082","inReplyTo":"20170621021024.GC60603@aiede.mtv.corp.google.com","subject":"Re: [PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-21T15:43:30Z","receivedAt":"2017-06-21T16:39:25Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/20, Jonathan Nieder wrote:\n> Hi again,\n> \n> Brandon Williams wrote:\n> \n> > When working with worktrees the git directory is split into two part,\n> > the per-worktree gitdir and a commondir which contains things which are\n> > shared among all worktrees (like the object store).  With this notion of\n> > having a split git directory, 557bd833b (git_path(): be aware of file\n> > relocation in $GIT_DIR) and c7b3a3d2f ($GIT_COMMON_DIR: a new\n> > environment variable) changed the way that 'git_path()' functioned so\n> > that paths would be adjusted if they referred to files or directories\n> > that are stored in the commondir or have been changed via an environment\n> > variable.\n> >\n> > One interesting problem with this is the index file as it is not shared\n> > across worktrees yet when asking for a path to a specific worktree's\n> > index it will be replaced with a path to the current worktree's index.\n> > In order to prevent this, teach 'adjuct_git_path' to replace the\n> > path to the index with the path recorded in a repository (which would be\n> > the current, active worktree) only when not asked to construct a path\n> > for a specific worktree.\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  path.c | 11 +++++++++--\n> >  1 file changed, 9 insertions(+), 2 deletions(-)\n> \n> Digging more into it with your help, I ran into v2.5.0-rc0~143^2~34\n> and v2.11.0-rc0~15^2 (git-svn: \"git worktree\" awareness, 2016-10-14),\n> which uses this function:\n> \n>  -\tmy $index = $ENV{GIT_INDEX_FILE} || \"$ENV{GIT_DIR}/index\";\n>  +\tmy $index = command_oneline(qw(rev-parse --git-path index));\n> \n> That rules out my hope of making git_path stop being aware of the index\n> at all.\n> \n> That also made it a little clearer to me what is going on with this\n> function.  I had previously misread !wt as meaning that git_dir is\n> not under worktrees/ (or in other words as !wt->id).  Instead, it\n> means that the caller does not want to use some other work tree in\n> preference to git_dir.\n> \n> With that piece in place, the patch starts making more sense to me.\n> When !wt, repo->index_file is going to have the same value as\n> getenv(\"GIT_INDEX_FILE\") ?: buf->buf already, since repo->index_file\n> refers to the current work tree git dir's index file.  When wt != NULL,\n> we don't want to use that file and have requested to grab the index\n> from a specific work tree git dir instead.\n> \n> And patch 05/20 (environment: place key repository state in\n> the_repository) had no effect since no one calls worktree_git_path\n> with argument \"index\", nor with a user-specified path.\n> \n> How about the following?  I found it a little easier to understand.\n\nSo your suggestion is to completely avoid doing any location when asking\nfor a worktree_git_path, I guess those code paths which request those\npaths should be aware enough that if they need something in commondir to\nuse git_common_path instead.  My only worry is that it may be difficult\nto catch misuse of worktree_git_path during code review, at least that\nwas one of the motivating factors for originally respecting\nGIT_INDEX_FILE and the like.\n\n> \n> -- >8 --\n> From: Brandon Williams <bmwill@google.com>\n> Subject: worktree_git_path: do not let GIT_INDEX_FILE override path to index\n> \n> git_path (and variants like strbuf_git_path) is designed to behave\n> like a convenience function that produces a string $GIT_DIR/<path>.\n> In the process, callers automatically get support for path relocation\n> variables like $GIT_OBJECT_DIRECTORY:\n> \n> - git_path(\"index\") is $GIT_INDEX_FILE when set\n> - git_path(\"info/grafts\") is $GIT_GRAFTS_FILE when set\n> - git_path(\"objects/<foo>\") is $GIT_OBJECT_DIRECTORY/<foo> when set\n> - git_path(\"hooks/<foo>\") is <foo> under core.hookspath when set\n> - git_path(\"refs/<foo>\") etc (see path.c::common_list) is relative\n>   to $GIT_COMMON_DIR instead of $GIT_DIR\n> \n> worktree_git_path, by comparison, is designed to resolve files in a\n> specific worktree's git dir and should not perform such relocation.\n> Do so by skipping the relocation step in worktree_git_path.\n> \n> Fortunately no current callers of worktree_git_path pass such\n> arguments.  Noticed due to an interaction between two patches under\n> review, one of which introduced such a caller:\n> \n> * One made \"git prune\" check the index file in each worktree's git dir\n>   (using worktree_git_path(wt, \"index\")) for objects not to prune,\n>   triggering the unwanted relocation code by mistake and allowing\n>   objects reachable from worktree indices to be pruned if\n>   GIT_INDEX_FILE is set.\n> \n> * The other simplified the relocation logic for index, info/grafts,\n>   objects, and hooks to happen unconditionally instead of based on\n>   whether environment or configuration variables are set, causing the\n>   relocation to trigger even when GIT_INDEX_FILE is not set.\n> \n> [jn: rewrote commit message; skipped all relocations instead of just\n>  the index]\n> \n> Change-Id: I2ba0a48a48b7e9a9c2e3ef97648cf53cb913bdd9\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>\n> ---\n>  path.c | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n> \n> diff --git a/path.c b/path.c\n> index c1cb1cf62..4c3a27a8e 100644\n> --- a/path.c\n> +++ b/path.c\n> @@ -397,7 +397,8 @@ static void do_git_path(const struct worktree *wt, struct strbuf *buf,\n>  \t\tstrbuf_addch(buf, '/');\n>  \tgitdir_len = buf->len;\n>  \tstrbuf_vaddf(buf, fmt, args);\n> -\tadjust_git_path(buf, gitdir_len);\n> +\tif (!wt)\n> +\t\tadjust_git_path(buf, gitdir_len);\n>  \tstrbuf_cleanup_path(buf);\n>  }\n>  \n> -- \n> 2.13.1.611.g7e3b11ae1\n> \n\n-- \nBrandon Williams\n"},{"id":"322827","messageId":"20170621175740.GE60603@aiede.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170621154330.GA53348@google.com","subject":"Re: [PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-06-21T17:57:40Z","receivedAt":"2017-06-21T17:57:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Brandon Williams wrote:\n\n> So your suggestion is to completely avoid doing any location when asking\n> for a worktree_git_path, I guess those code paths which request those\n> paths should be aware enough that if they need something in commondir to\n> use git_common_path instead.  My only worry is that it may be difficult\n> to catch misuse of worktree_git_path during code review, at least that\n> was one of the motivating factors for originally respecting\n> GIT_INDEX_FILE and the like.\n\nCorrect: I'm saying that when someone calls worktree_git_path, the\nintent is to resolve a path within the worktree git directory.  File\nrelocation just gets in the way of that.\n\nI am not too worried about misuse because the only reason to call\nworktree_git_path is to access a worktree-specific file like HEAD or\nindex.\n\nThanks,\nJonathan\n"},{"id":"322841","messageId":"xmqqmv91p477.fsf@gitster.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170621175740.GE60603@aiede.mtv.corp.google.com","subject":"Re: [PATCH v3 11/20] path: construct correct path to a worktree's index","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-21T18:48:28Z","receivedAt":"2017-06-21T18:48:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Brandon Williams wrote:\n>\n>> So your suggestion is to completely avoid doing any location when asking\n>> for a worktree_git_path, I guess those code paths which request those\n>> paths should be aware enough that if they need something in commondir to\n>> use git_common_path instead.  My only worry is that it may be difficult\n>> to catch misuse of worktree_git_path during code review, at least that\n>> was one of the motivating factors for originally respecting\n>> GIT_INDEX_FILE and the like.\n>\n> Correct: I'm saying that when someone calls worktree_git_path, the\n> intent is to resolve a path within the worktree git directory.  File\n> relocation just gets in the way of that.\n>\n> I am not too worried about misuse because the only reason to call\n> worktree_git_path is to access a worktree-specific file like HEAD or\n> index.\n\nUntil somebody has a brilliant idea \"git_path() can be implemented\nin terms of worktree_git_path()---give it the current worktree!\" ;-)\n\nJust joking.  I agree with the general direction you've shown in the\nthread.\n\nThanks.\n"},{"id":"322868","messageId":"20170621212019.GB53348@google.com","threadId":"46082","inReplyTo":"20170620152308.42984ee7@twelve2.svl.corp.google.com","subject":"Re: [PATCH v3 10/20] path: convert do_git_path to take a 'struct repository'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-21T21:20:19Z","receivedAt":"2017-06-21T21:20:39Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/20, Jonathan Tan wrote:\n> On Tue, 20 Jun 2017 12:19:41 -0700\n> Brandon Williams <bmwill@google.com> wrote:\n> \n> > +static void do_git_path(const struct repository *repo,\n> > +\t\t\tconst struct worktree *wt, struct strbuf *buf,\n> >  \t\t\tconst char *fmt, va_list args)\n> >  {\n> >  \tint gitdir_len;\n> > -\tstrbuf_addstr(buf, get_worktree_git_dir(wt));\n> \n> With this change, the get_worktree_git_dir() function no longer seems to\n> be used from outside - could it be marked static?\n\nProbably?  But you could argue that it is ok to be part of the public\nAPI.  As in it may be ok to leave as is because some future caller may\nwant it at some point.\n\n> \n> > +\tstrbuf_worktree_gitdir(buf, repo, wt);\n> >  \tif (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))\n> >  \t\tstrbuf_addch(buf, '/');\n> >  \tgitdir_len = buf->len;\n> >  \tstrbuf_vaddf(buf, fmt, args);\n> > -\tadjust_git_path(buf, gitdir_len);\n> > +\tadjust_git_path(repo, buf, gitdir_len);\n> >  \tstrbuf_cleanup_path(buf);\n> >  }\n\n-- \nBrandon Williams\n"},{"id":"322871","messageId":"20170621212709.GC53348@google.com","threadId":"46082","inReplyTo":"CAGZ79kaUiODQm8KsGOAtAoATNW7mci3DRM=RimXXv-6--9NOKw@mail.gmail.com","subject":"Re: [PATCH v3 04/20] repository: introduce the repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-21T21:27:09Z","receivedAt":"2017-06-21T21:27:28Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/20, Stefan Beller wrote:\n> On Tue, Jun 20, 2017 at 12:19 PM, Brandon Williams <bmwill@google.com> wrote:\n> > Introduce the repository object 'struct repository' which can be used to\n> > hold all state pertaining to a git repository.\n> >\n> > Some of the benefits of object-ifying a repository are:\n> >\n> >   1. Make the code base more readable and easier to reason about.\n> >\n> >   2. Allow for working on multiple repositories, specifically\n> >      submodules, within the same process.  Currently the process for\n> >      working on a submodule involves setting up an argv_array of options\n> >      for a particular command and then launching a child process to\n> >      execute the command in the context of the submodule.  This is\n> >      clunky and can require lots of little hacks in order to ensure\n> >      correctness.  Ideally it would be nice to simply pass a repository\n> >      and an options struct to a command.\n> >\n> >   3. Eliminating reliance on global state will make it easier to\n> >      enable the use of threading to improve performance.\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> \n> > +/*\n> > + * Initialize 'repo' based on the provided 'gitdir'.\n> > + * Return 0 upon success and a non-zero value upon failure.\n> \n> Non zero or negative? The point of the question is if we want to\n> ask users of this function to be cautious early on. So in the future,\n> do we want to rather see\n> \n>     if (repo_init(...))\n>         die(\"you're doomed\");\n> \n> or rather\n> \n>     int x = repo_init(...);\n>     if (x < 0)\n>         die(\"you're doomed\");\n>     else if (x == 1)\n>         warning(\"you're not doomed, but close.\"\\\n>              \"Not distimming the gostaks.\")\n>     else\n>         ; /* we're fine, carry on with life */\n> \n> I guess we can still refactor later, it's just one\n> thing to thing about when introducing an API\n> that will likely be used a lot down the road.\n\nI'm not sure what we want right now, hence why I left it a little more\nvague.  At this point in time all the relevant callers I can think of\n(or rather potential callers) don't care about the failure and just want\nto know if it succeeded.  I think it would be ok to do a small refactor\nat a later time if we really needed to provide the reason for the\nfailure.  Unless of course someone feels strongly enough that it needs\nto be addressed right now.  If we did address it now then we would need\na group of #define's or maybe an enum to describe the failure modes.\n\n> \n> > +struct repository {\n> > +       /* Environment */\n> > +       /* Path to the git directory */\n> > +       char *gitdir;\n> > +\n> > +       /* Path to the common git directory */\n> > +       char *commondir;\n> > +\n> > +       /* Path to the repository's object store */\n> > +       char *objectdir;\n> > +\n> > +       /* Path to the repository's graft file */\n> > +       char *graft_file;\n> > +\n> > +       /* Path to the current worktree's index file */\n> > +       char *index_file;\n> > +\n> > +       /* Path to the working directory */\n> > +       char *worktree;\n> > +\n> > +       /* Configurations */\n> > +       /*\n> > +        * Bit used during initialization to indicate if repository state (like\n> > +        * the location of the 'objectdir') should be read from the\n> > +        * environment.  By default this bit will be set at the begining of\n> > +        * 'repo_init()' so that all repositories will ignore the environment.\n> > +        * The exception to this is 'the_repository', which doesn't go through\n> > +        * the normal 'repo_init()' process.\n> > +        */\n> > +       unsigned ignore_env:1;\n> > +\n> > +       /* Indicate if a repository has a different 'commondir' from 'gitdir' */\n> > +       unsigned different_commondir:1;\n> > +};\n> \n> I applaud the effort towards documenting what each variable is\n> supposed to contain. But some of them read like\n> \n>     /* increments i by one */\n>     i++;\n> \n> which is considered bad comment style (it doesn't add\n> more information, it just wastes a line), so specifically for\n> all the \"Path to X\" comments:\n> * Are they absolute path, or relative path?\n>   If relative, then relative to what?\n> * Can they be NULL? When?\n> \n> (* Why do we need so many path?\n>     Could one of them be constructed using\n>     another and then hardcoding a string relative to it?\n>     This question may rather be answered in the commit\n>     message)\n\nThanks for pointing this out.  I'll work a little bit more on the\ncomments to be more descriptive.  I do think that all field names should\nprobably be commented though.\n\n-- \nBrandon Williams\n"},{"id":"322872","messageId":"CAGZ79kY6hAj318ePRQjdbqoZxYPDuqiLrbEEGi4t7xJYE28zQQ@mail.gmail.com","threadId":"46082","inReplyTo":"20170621212709.GC53348@google.com","subject":"Re: [PATCH v3 04/20] repository: introduce the repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-21T21:31:13Z","receivedAt":"2017-06-21T21:31:28Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":">> I guess we can still refactor later, it's just one\n>> thing to thing about when introducing an API\n>> that will likely be used a lot down the road.\n>\n> I'm not sure what we want right now, hence why I left it a little more\n> vague.  At this point in time all the relevant callers I can think of\n> (or rather potential callers) don't care about the failure and just want\n> to know if it succeeded.  I think it would be ok to do a small refactor\n> at a later time if we really needed to provide the reason for the\n> failure.  Unless of course someone feels strongly enough that it needs\n> to be addressed right now.  If we did address it now then we would need\n> a group of #define's or maybe an enum to describe the failure modes.\n\nI do not feel strongly, just wanted to draw your attention to it.\nAnd having thought about it, refactoring down the road is likely quite cheap,\nso this was a useless bikeshedding attempt.\n\n>>\n>> I applaud the effort towards documenting what each variable is\n>> supposed to contain. But some of them read like\n>>\n>>     /* increments i by one */\n>>     i++;\n>>\n>> which is considered bad comment style (it doesn't add\n>> more information, it just wastes a line), so specifically for\n>> all the \"Path to X\" comments:\n>> * Are they absolute path, or relative path?\n>>   If relative, then relative to what?\n>> * Can they be NULL? When?\n>>\n>> (* Why do we need so many path?\n>>     Could one of them be constructed using\n>>     another and then hardcoding a string relative to it?\n>>     This question may rather be answered in the commit\n>>     message)\n>\n> Thanks for pointing this out.  I'll work a little bit more on the\n> comments to be more descriptive.  I do think that all field names should\n> probably be commented though.\n\nThanks!\nStefan\n"},{"id":"322891","messageId":"20170621154837.566b67ac@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170620191951.84791-21-bmwill@google.com","subject":"Re: [PATCH v3 20/20] ls-files: use repository object","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-21T22:48:37Z","receivedAt":"2017-06-21T22:48:47Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Tue, 20 Jun 2017 12:19:51 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> -static void show_ce_entry(const struct index_state *istate,\n> -\t\t\t  const char *tag, const struct cache_entry *ce)\n> +static void show_ce(struct repository *repo, struct dir_struct *dir,\n> +\t\t    const struct cache_entry *ce, const char *fullname,\n> +\t\t    const char *tag)\n\nThis function is getting complicated - in particular, it's getting a\n\"fullname\" which is, in a sense, redundant with \"repo\" and \"ce\" (but\nthat seems necessary for efficiency). Maybe add a comment describing the\nfunction?\n\n[snip]\n\n> @@ -651,8 +610,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n>  \tif (require_work_tree && !is_inside_work_tree())\n>  \t\tsetup_work_tree();\n>  \n> -\tif (recurse_submodules)\n> -\t\tcompile_submodule_options(argv, &dir, show_tag);\n> +\tif (recurse_submodules) {\n> +\t\trepo_read_gitmodules(the_repository);\n> +\t}\n\nNo need for braces.\n"},{"id":"322892","messageId":"20170621155059.3ae2c601@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170620191951.84791-16-bmwill@google.com","subject":"Re: [PATCH v3 15/20] repository: add index_state to struct repo","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-21T22:50:59Z","receivedAt":"2017-06-21T22:51:09Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Tue, 20 Jun 2017 12:19:46 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> +int repo_read_index(struct repository *repo)\n> +{\n> +\tif (!repo->index)\n> +\t\trepo->index = xcalloc(1, sizeof(struct index_state));\n\nsizeof(*repo->index)?\n\n[snip]\n\n> +\t/* Repository's in-memory index */\n> +\tstruct index_state *index;\n> +\n\nMight be worth commenting that repo_read_index() can populate this.\n"},{"id":"322893","messageId":"20170621225403.GH53348@google.com","threadId":"46082","inReplyTo":"20170621155059.3ae2c601@twelve2.svl.corp.google.com","subject":"Re: [PATCH v3 15/20] repository: add index_state to struct repo","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-21T22:54:03Z","receivedAt":"2017-06-21T22:54:10Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/21, Jonathan Tan wrote:\n> On Tue, 20 Jun 2017 12:19:46 -0700\n> Brandon Williams <bmwill@google.com> wrote:\n> \n> > +int repo_read_index(struct repository *repo)\n> > +{\n> > +\tif (!repo->index)\n> > +\t\trepo->index = xcalloc(1, sizeof(struct index_state));\n> \n> sizeof(*repo->index)?\n\nIs there a reason to prefer one versus the other? Either way I can\nchange.\n\n> \n> [snip]\n> \n> > +\t/* Repository's in-memory index */\n> > +\tstruct index_state *index;\n> > +\n> \n> Might be worth commenting that repo_read_index() can populate this.\n\n-- \nBrandon Williams\n"},{"id":"322894","messageId":"20170621160007.4976187d@twelve2.svl.corp.google.com","threadId":"46082","inReplyTo":"20170620191951.84791-20-bmwill@google.com","subject":"Re: [PATCH v3 19/20] repository: enable initialization of submodules","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2017-06-21T23:00:07Z","receivedAt":"2017-06-21T23:00:19Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"On Tue, 20 Jun 2017 12:19:50 -0700\nBrandon Williams <bmwill@google.com> wrote:\n\n> Introduce 'repo_submodule_init()' which performs initialization of a\n> 'struct repository' as a submodule of another 'struct repository'.\n> \n> The resulting submodule can be in one of three states:\n> \n>   1. The submodule is initialized and has a worktree.\n> \n>   2. The submodule is initialized but does not have a worktree.  This\n>      would occur when the submodule's gitdir is present in the\n>      superproject's 'gitdir/modules/' directory yet the submodule has not\n>      been checked out in superproject's worktree.\n\nIn a recent proposal [1] to update the submodule documentation, an\n\"initialized submodule\" is one that has a working directory, which seems\nto have a different meaning of \"initialized\" (to the paragraphs above).\n\nOr did you mean the \"struct repository\" is initialized etc.? In which\ncase, it does not seem strange to me that a repository is initialized\nbut does not have a worktree, since bare repositories are like that too.\n\n[1] https://public-inbox.org/git/20170621173756.4444-1-sbeller@google.com/\n\n>   3. The submodule remains uninitialized due to an error in the\n>      initialization process or there is no matching submodule at the\n>      provided path in the superproject.\n> \n> Signed-off-by: Brandon Williams <bmwill@google.com>\n\n[snip]\n\n> +/*\n> + * Initialize 'submodule' as the submodule given by 'path' in parent repository\n> + * 'superproject'.\n> + * Return 0 upon success and a non-zero value upon failure.\n> + */\n> +int repo_submodule_init(struct repository *submodule,\n> +\t\t\tstruct repository *superproject,\n> +\t\t\tconst char *path)\n> +{\n> +\tconst struct submodule *sub;\n> +\tstruct strbuf submodule_path = STRBUF_INIT;\n> +\tint ret = 0;\n> +\n> +\tsub = submodule_from_cache(superproject, null_sha1, path);\n> +\tif (!sub) {\n> +\t\tret = -1;\n> +\t\tgoto out;\n> +\t}\n> +\n> +\tstrbuf_repo_worktree_path(&submodule_path, superproject, \"%s\", path);\n> +\n> +\tif (repo_init(submodule, submodule_path.buf, submodule_path.buf)) {\n\nThis works because the 2nd parameter (git_dir) can take in either the\nGit directory itself or its parent, but it does make the call site look\nstrange. Would it be a good idea to make it mandatory to specify the Git\ndirectory? That would make call sites clearer but require more code\nthere.\n\n> +\t\tstrbuf_reset(&submodule_path);\n> +\t\tstrbuf_repo_git_path(&submodule_path, superproject,\n> +\t\t\t\t     \"modules/%s\", sub->name);\n> +\n> +\t\tif (repo_init(submodule, submodule_path.buf, NULL)) {\n> +\t\t\tret = -1;\n> +\t\t\tgoto out;\n> +\t\t}\n> +\t}\n> +\n> +\tsubmodule->submodule_prefix = xstrfmt(\"%s%s/\",\n> +\t\t\t\t\t      superproject->submodule_prefix ?\n> +\t\t\t\t\t      superproject->submodule_prefix :\n> +\t\t\t\t\t      \"\", path);\n> +\n> +out:\n> +\tstrbuf_release(&submodule_path);\n> +\treturn ret;\n> +}\n"},{"id":"322895","messageId":"CAGZ79kaCLO=CVZLtc3BF8WHXPtO06oaa8RmsXYB6kUHU8ty1Rg@mail.gmail.com","threadId":"46082","inReplyTo":"20170621225403.GH53348@google.com","subject":"Re: [PATCH v3 15/20] repository: add index_state to struct repo","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-21T23:00:11Z","receivedAt":"2017-06-21T23:00:22Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Jun 21, 2017 at 3:54 PM, Brandon Williams <bmwill@google.com> wrote:\n> On 06/21, Jonathan Tan wrote:\n>> On Tue, 20 Jun 2017 12:19:46 -0700\n>> Brandon Williams <bmwill@google.com> wrote:\n>>\n>> > +int repo_read_index(struct repository *repo)\n>> > +{\n>> > +   if (!repo->index)\n>> > +           repo->index = xcalloc(1, sizeof(struct index_state));\n>>\n>> sizeof(*repo->index)?\n>\n> Is there a reason to prefer one versus the other? Either way I can\n> change.\n\nIf repo->index changes its type, then we do not need to fix it here\nstrictly. We may fix surrounding code, but not necessarily, e.g.\nwhen the type change is a cast to a wider type (subclass so to speak),\nso e.g. *repo->index is made to be:\n\n    struct new_index {\n      struct index_state index;\n      int more_state\n    };\n\nthen this area of code would just work fine, no maintenance burden.\n"},{"id":"322897","messageId":"20170621230910.GI53348@google.com","threadId":"46082","inReplyTo":"20170621160007.4976187d@twelve2.svl.corp.google.com","subject":"Re: [PATCH v3 19/20] repository: enable initialization of submodules","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-21T23:09:10Z","receivedAt":"2017-06-21T23:09:18Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/21, Jonathan Tan wrote:\n> On Tue, 20 Jun 2017 12:19:50 -0700\n> Brandon Williams <bmwill@google.com> wrote:\n> \n> > Introduce 'repo_submodule_init()' which performs initialization of a\n> > 'struct repository' as a submodule of another 'struct repository'.\n> > \n> > The resulting submodule can be in one of three states:\n> > \n> >   1. The submodule is initialized and has a worktree.\n> > \n> >   2. The submodule is initialized but does not have a worktree.  This\n> >      would occur when the submodule's gitdir is present in the\n> >      superproject's 'gitdir/modules/' directory yet the submodule has not\n> >      been checked out in superproject's worktree.\n> \n> In a recent proposal [1] to update the submodule documentation, an\n> \"initialized submodule\" is one that has a working directory, which seems\n> to have a different meaning of \"initialized\" (to the paragraphs above).\n> \n> Or did you mean the \"struct repository\" is initialized etc.? In which\n> case, it does not seem strange to me that a repository is initialized\n> but does not have a worktree, since bare repositories are like that too.\n\nYes \"initialization\" only refers to the state of the 'struct\nrepository'.\n\n> \n> [1] https://public-inbox.org/git/20170621173756.4444-1-sbeller@google.com/\n> \n> >   3. The submodule remains uninitialized due to an error in the\n> >      initialization process or there is no matching submodule at the\n> >      provided path in the superproject.\n> > \n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> \n> [snip]\n> \n> > +/*\n> > + * Initialize 'submodule' as the submodule given by 'path' in parent repository\n> > + * 'superproject'.\n> > + * Return 0 upon success and a non-zero value upon failure.\n> > + */\n> > +int repo_submodule_init(struct repository *submodule,\n> > +\t\t\tstruct repository *superproject,\n> > +\t\t\tconst char *path)\n> > +{\n> > +\tconst struct submodule *sub;\n> > +\tstruct strbuf submodule_path = STRBUF_INIT;\n> > +\tint ret = 0;\n> > +\n> > +\tsub = submodule_from_cache(superproject, null_sha1, path);\n> > +\tif (!sub) {\n> > +\t\tret = -1;\n> > +\t\tgoto out;\n> > +\t}\n> > +\n> > +\tstrbuf_repo_worktree_path(&submodule_path, superproject, \"%s\", path);\n> > +\n> > +\tif (repo_init(submodule, submodule_path.buf, submodule_path.buf)) {\n> \n> This works because the 2nd parameter (git_dir) can take in either the\n> Git directory itself or its parent, but it does make the call site look\n> strange. Would it be a good idea to make it mandatory to specify the Git\n> directory? That would make call sites clearer but require more code\n> there.\n\nCorrect, The idea was to make it easy for callers to initialize\nrepositories...but you may have convinced me to change that and require\nand exact path to the gitdir.  That would actually make the repo_init\ncode cleaner too.  Originally I was worried that extra boiler plate code\nwould be needed everytime we wanted to init a submodule, but then I\nintroduced this funciton so the extra logic would be contained in this\nfunction.\n\n> \n> > +\t\tstrbuf_reset(&submodule_path);\n> > +\t\tstrbuf_repo_git_path(&submodule_path, superproject,\n> > +\t\t\t\t     \"modules/%s\", sub->name);\n> > +\n> > +\t\tif (repo_init(submodule, submodule_path.buf, NULL)) {\n> > +\t\t\tret = -1;\n> > +\t\t\tgoto out;\n> > +\t\t}\n> > +\t}\n> > +\n> > +\tsubmodule->submodule_prefix = xstrfmt(\"%s%s/\",\n> > +\t\t\t\t\t      superproject->submodule_prefix ?\n> > +\t\t\t\t\t      superproject->submodule_prefix :\n> > +\t\t\t\t\t      \"\", path);\n> > +\n> > +out:\n> > +\tstrbuf_release(&submodule_path);\n> > +\treturn ret;\n> > +}\n\n-- \nBrandon Williams\n"},{"id":"322941","messageId":"20170622184348.56497-1-bmwill@google.com","threadId":"46082","inReplyTo":"20170620191951.84791-1-bmwill@google.com","subject":"[PATCH v4 00/20] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:28Z","receivedAt":"2017-06-22T18:44:08Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"As before you can find this series at:\nhttps://github.com/bmwill/git/tree/repository-object\n\nChanges in v4:\n\n* Patch 11 is slightly different and turns off all path relocation when a\n  worktree is provided instead of just for the index file (Thanks for the help\n  Jonathan Nieder).\n* 'repo_init()' has a tighter API and now requires that the provided gitdir is\n  a path to the gitdir instead of either a path to the gitdir or path to the\n  worktree (which has a .git file or directory) (Thanks Jonathan Tan).\n* Minor comment and commit message chagnes\n\nNote: Like v3 this series is dependent on on 'bw/config-h' and\n      'bw/ls-files-sans-the-index'\n\nBrandon Williams (20):\n  setup: don't perform lazy initialization of repository state\n  setup: add comment indicating a hack\n  environment: remove namespace_len variable\n  repository: introduce the repository object\n  environment: place key repository state in the_repository\n  environment: store worktree in the_repository\n  path: create path.h\n  path: always pass in commondir to update_common_dir\n  path: convert strbuf_git_common_path to take a 'struct repository'\n  path: convert do_git_path to take a 'struct repository'\n  path: worktree_git_path() should not use file relocation\n  path: add repo_git_path and strbuf_repo_git_path\n  path: add repo_worktree_path and strbuf_repo_worktree_path\n  config: read config from a repository object\n  repository: add index_state to struct repo\n  submodule-config: store the_submodule_cache in the_repository\n  submodule: add repo_read_gitmodules\n  submodule: convert is_submodule_initialized to work on a repository\n  repository: enable initialization of submodules\n  ls-files: use repository object\n\n Makefile                               |   1 +\n builtin/grep.c                         |   3 +-\n builtin/ls-files.c                     | 192 +++++++++++---------------\n builtin/submodule--helper.c            |   9 +-\n cache.h                                |  62 +--------\n config.c                               | 216 +++++++++++++++++++----------\n config.h                               |  24 ++++\n environment.c                          |  91 ++++---------\n git.c                                  |   2 +-\n path.c                                 | 130 ++++++++++++++----\n path.h                                 |  82 +++++++++++\n repository.c                           | 242 +++++++++++++++++++++++++++++++++\n repository.h                           |  97 +++++++++++++\n setup.c                                |  33 +++++\n submodule-config.c                     |  70 +++++++---\n submodule-config.h                     |  10 ++\n submodule.c                            |  35 +++--\n submodule.h                            |   4 +-\n t/t3007-ls-files-recurse-submodules.sh |  39 ++++++\n worktree.c                             |   3 +-\n 20 files changed, 972 insertions(+), 373 deletions(-)\n create mode 100644 path.h\n create mode 100644 repository.c\n create mode 100644 repository.h\n\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322942","messageId":"20170622184348.56497-2-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 01/20] setup: don't perform lazy initialization of repository state","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:29Z","receivedAt":"2017-06-22T18:44:10Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Under some circumstances (bogus GIT_DIR value or the discovered gitdir\nis '.git') 'setup_git_directory()' won't initialize key repository\nstate.  This leads to inconsistent state after running the setup code.\nTo account for this inconsistent state, lazy initialization is done once\na caller asks for the repository's gitdir or some other piece of\nrepository state.  This is confusing and can be error prone.\n\nInstead let's tighten the expected outcome of 'setup_git_directory()'\nand ensure that it initializes repository state in all cases that would\nhave been handled by lazy initialization.\n\nThis also lets us drop the requirement to have 'have_git_dir()' check if\nthe environment variable GIT_DIR was set as that will be handled by the\nend of the setup code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h       |  2 ++\n environment.c | 17 ++++++++---------\n setup.c       | 14 ++++++++++++++\n 3 files changed, 24 insertions(+), 9 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 96055c222..7c81749a9 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -462,6 +462,8 @@ static inline enum object_type object_type(unsigned int mode)\n  */\n extern const char * const local_repo_env[];\n \n+extern void setup_git_env(void);\n+\n /*\n  * Returns true iff we have a configured git repository (either via\n  * setup_git_directory, or in the environment via $GIT_DIR).\ndiff --git a/environment.c b/environment.c\nindex d40b21fb7..a73b08f5d 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -160,7 +160,7 @@ static char *git_path_from_env(const char *envvar, const char *git_dir,\n \treturn xstrdup(value);\n }\n \n-static void setup_git_env(void)\n+void setup_git_env(void)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *gitfile;\n@@ -205,28 +205,27 @@ int is_bare_repository(void)\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n-\t\t|| git_dir\n-\t\t|| getenv(GIT_DIR_ENVIRONMENT);\n+\t\t|| git_dir;\n }\n \n const char *get_git_dir(void)\n {\n \tif (!git_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_dir;\n }\n \n const char *get_git_common_dir(void)\n {\n \tif (!git_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_common_dir;\n }\n \n const char *get_git_namespace(void)\n {\n \tif (!namespace)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn namespace;\n }\n \n@@ -276,7 +275,7 @@ const char *get_git_work_tree(void)\n char *get_object_directory(void)\n {\n \tif (!git_object_dir)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_object_dir;\n }\n \n@@ -316,14 +315,14 @@ int odb_pack_keep(const char *name)\n char *get_index_file(void)\n {\n \tif (!git_index_file)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_index_file;\n }\n \n char *get_graft_file(void)\n {\n \tif (!git_graft_file)\n-\t\tsetup_git_env();\n+\t\tBUG(\"git environment hasn't been setup\");\n \treturn git_graft_file;\n }\n \ndiff --git a/setup.c b/setup.c\nindex 358fbc2e5..24a738b0d 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1091,6 +1091,20 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \tstartup_info->have_repository = !nongit_ok || !*nongit_ok;\n \tstartup_info->prefix = prefix;\n \n+\t/*\n+\t * Not all paths through the setup code will call 'set_git_dir()' (which\n+\t * directly sets up the environment) so in order to guarantee that the\n+\t * environment is in a consistent state after setup, explicitly setup\n+\t * the environment if we have a repository.\n+\t *\n+\t * NEEDSWORK: currently we allow bogus GIT_DIR values to be set in some\n+\t * code paths so we also need to explicitly setup the environment if\n+\t * the user has set GIT_DIR.  It may be beneficial to disallow bogus\n+\t * GIT_DIR values at some point in the future.\n+\t */\n+\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT))\n+\t\tsetup_git_env();\n+\n \tstrbuf_release(&dir);\n \tstrbuf_release(&gitdir);\n \n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322943","messageId":"20170622184348.56497-3-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 02/20] setup: add comment indicating a hack","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:30Z","receivedAt":"2017-06-22T18:44:12Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"'GIT_TOPLEVEL_PREFIX_ENVIRONMENT' was added in (b58a68c1c setup: allow\nfor prefix to be passed to git commands) to aid in fixing a bug where\n'ls-files' and 'grep' were not able to properly recurse when called from\nwithin a subdirectory.  Add a 'NEEDSWORK' comment indicating that this\nenvvar should be removed once 'ls-files' and 'grep' can recurse\nin-process.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n setup.c | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/setup.c b/setup.c\nindex 24a738b0d..b477faa44 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1079,6 +1079,12 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t\tdie(\"BUG: unhandled setup_git_directory_1() result\");\n \t}\n \n+\t/*\n+\t * NEEDSWORK: This was a hack in order to get ls-files and grep to have\n+\t * properly formated output when recursing submodules.  Once ls-files\n+\t * and grep have been changed to perform this recursing in-process this\n+\t * needs to be removed.\n+\t */\n \tenv_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT);\n \tif (env_prefix)\n \t\tprefix = env_prefix;\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322944","messageId":"20170622184348.56497-5-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 04/20] repository: introduce the repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:32Z","receivedAt":"2017-06-22T18:44:14Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce the repository object 'struct repository' which can be used to\nhold all state pertaining to a git repository.\n\nSome of the benefits of object-ifying a repository are:\n\n  1. Make the code base more readable and easier to reason about.\n\n  2. Allow for working on multiple repositories, specifically\n     submodules, within the same process.  Currently the process for\n     working on a submodule involves setting up an argv_array of options\n     for a particular command and then launching a child process to\n     execute the command in the context of the submodule.  This is\n     clunky and can require lots of little hacks in order to ensure\n     correctness.  Ideally it would be nice to simply pass a repository\n     and an options struct to a command.\n\n  3. Eliminating reliance on global state will make it easier to\n     enable the use of threading to improve performance.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Makefile     |   1 +\n repository.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n repository.h |  64 ++++++++++++++++++++++++\n 3 files changed, 224 insertions(+)\n create mode 100644 repository.c\n create mode 100644 repository.h\n\ndiff --git a/Makefile b/Makefile\nindex f48480163..32e4efc71 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -839,6 +839,7 @@ LIB_OBJS += refs/ref-cache.o\n LIB_OBJS += ref-filter.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\n+LIB_OBJS += repository.o\n LIB_OBJS += rerere.o\n LIB_OBJS += resolve-undo.o\n LIB_OBJS += revision.o\ndiff --git a/repository.c b/repository.c\nnew file mode 100644\nindex 000000000..cf440405a\n--- /dev/null\n+++ b/repository.c\n@@ -0,0 +1,159 @@\n+#include \"cache.h\"\n+#include \"repository.h\"\n+\n+/* The main repository */\n+static struct repository the_repo;\n+struct repository *the_repository = &the_repo;\n+\n+static char *git_path_from_env(const char *envvar, const char *git_dir,\n+\t\t\t       const char *path, int fromenv)\n+{\n+\tif (fromenv) {\n+\t\tconst char *value = getenv(envvar);\n+\t\tif (value)\n+\t\t\treturn xstrdup(value);\n+\t}\n+\n+\treturn xstrfmt(\"%s/%s\", git_dir, path);\n+}\n+\n+static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)\n+{\n+\tif (fromenv) {\n+\t\tconst char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n+\t\tif (value) {\n+\t\t\tstrbuf_addstr(sb, value);\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\n+\treturn get_common_dir_noenv(sb, gitdir);\n+}\n+\n+static void repo_setup_env(struct repository *repo)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\trepo->different_commondir = find_common_dir(&sb, repo->gitdir,\n+\t\t\t\t\t\t    !repo->ignore_env);\n+\trepo->commondir = strbuf_detach(&sb, NULL);\n+\trepo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,\n+\t\t\t\t\t    \"objects\", !repo->ignore_env);\n+\trepo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,\n+\t\t\t\t\t     \"info/grafts\", !repo->ignore_env);\n+\trepo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,\n+\t\t\t\t\t     \"index\", !repo->ignore_env);\n+}\n+\n+void repo_set_gitdir(struct repository *repo, const char *path)\n+{\n+\tconst char *gitfile = read_gitfile(path);\n+\n+\t/*\n+\t * NEEDSWORK: Eventually we want to be able to free gitdir and the rest\n+\t * of the environment before reinitializing it again, but we have some\n+\t * crazy code paths where we try to set gitdir with the current gitdir\n+\t * and we don't want to free gitdir before copying the passed in value.\n+\t */\n+\trepo->gitdir = xstrdup(gitfile ? gitfile : path);\n+\n+\trepo_setup_env(repo);\n+}\n+\n+/*\n+ * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.\n+ * Return 0 upon success and a non-zero value upon failure.\n+ */\n+static int repo_init_gitdir(struct repository *repo, const char *gitdir)\n+{\n+\tint ret = 0;\n+\tint error = 0;\n+\tchar *abspath = NULL;\n+\tconst char *resolved_gitdir;\n+\n+\tabspath = real_pathdup(gitdir, 0);\n+\tif (!abspath) {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\t/* 'gitdir' must reference the gitdir directly */\n+\tresolved_gitdir = resolve_gitdir_gently(abspath, &error);\n+\tif (!resolved_gitdir) {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\trepo_set_gitdir(repo, resolved_gitdir);\n+\n+out:\n+\tfree(abspath);\n+\treturn ret;\n+}\n+\n+void repo_set_worktree(struct repository *repo, const char *path)\n+{\n+\trepo->worktree = real_pathdup(path, 1);\n+}\n+\n+static int read_and_verify_repository_format(struct repository_format *format,\n+\t\t\t\t\t     const char *commondir)\n+{\n+\tint ret = 0;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tstrbuf_addf(&sb, \"%s/config\", commondir);\n+\tread_repository_format(format, sb.buf);\n+\tstrbuf_reset(&sb);\n+\n+\tif (verify_repository_format(format, &sb) < 0) {\n+\t\twarning(\"%s\", sb.buf);\n+\t\tret = -1;\n+\t}\n+\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n+/*\n+ * Initialize 'repo' based on the provided 'gitdir'.\n+ * Return 0 upon success and a non-zero value upon failure.\n+ */\n+int repo_init(struct repository *repo, const char *gitdir, const char *worktree)\n+{\n+\tstruct repository_format format;\n+\tmemset(repo, 0, sizeof(*repo));\n+\n+\trepo->ignore_env = 1;\n+\n+\tif (repo_init_gitdir(repo, gitdir))\n+\t\tgoto error;\n+\n+\tif (read_and_verify_repository_format(&format, repo->commondir))\n+\t\tgoto error;\n+\n+\tif (worktree)\n+\t\trepo_set_worktree(repo, worktree);\n+\n+\treturn 0;\n+\n+error:\n+\trepo_clear(repo);\n+\treturn -1;\n+}\n+\n+void repo_clear(struct repository *repo)\n+{\n+\tfree(repo->gitdir);\n+\trepo->gitdir = NULL;\n+\tfree(repo->commondir);\n+\trepo->commondir = NULL;\n+\tfree(repo->objectdir);\n+\trepo->objectdir = NULL;\n+\tfree(repo->graft_file);\n+\trepo->graft_file = NULL;\n+\tfree(repo->index_file);\n+\trepo->index_file = NULL;\n+\tfree(repo->worktree);\n+\trepo->worktree = NULL;\n+}\ndiff --git a/repository.h b/repository.h\nnew file mode 100644\nindex 000000000..0a1db9633\n--- /dev/null\n+++ b/repository.h\n@@ -0,0 +1,64 @@\n+#ifndef REPOSITORY_H\n+#define REPOSITORY_H\n+\n+struct repository {\n+\t/* Environment */\n+\t/*\n+\t * Path to the git directory.\n+\t * Cannot be NULL after initialization.\n+\t */\n+\tchar *gitdir;\n+\n+\t/*\n+\t * Path to the common git directory.\n+\t * Cannot be NULL after initialization.\n+\t */\n+\tchar *commondir;\n+\n+\t/*\n+\t * Path to the repository's object store.\n+\t * Cannot be NULL after initialization.\n+\t */\n+\tchar *objectdir;\n+\n+\t/*\n+\t * Path to the repository's graft file.\n+\t * Cannot be NULL after initialization.\n+\t */\n+\tchar *graft_file;\n+\n+\t/*\n+\t * Path to the current worktree's index file.\n+\t * Cannot be NULL after initialization.\n+\t */\n+\tchar *index_file;\n+\n+\t/*\n+\t * Path to the working directory.\n+\t * A NULL value indicates that there is no working directory.\n+\t */\n+\tchar *worktree;\n+\n+\t/* Configurations */\n+\t/*\n+\t * Bit used during initialization to indicate if repository state (like\n+\t * the location of the 'objectdir') should be read from the\n+\t * environment.  By default this bit will be set at the begining of\n+\t * 'repo_init()' so that all repositories will ignore the environment.\n+\t * The exception to this is 'the_repository', which doesn't go through\n+\t * the normal 'repo_init()' process.\n+\t */\n+\tunsigned ignore_env:1;\n+\n+\t/* Indicate if a repository has a different 'commondir' from 'gitdir' */\n+\tunsigned different_commondir:1;\n+};\n+\n+extern struct repository *the_repository;\n+\n+extern void repo_set_gitdir(struct repository *repo, const char *path);\n+extern void repo_set_worktree(struct repository *repo, const char *path);\n+extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);\n+extern void repo_clear(struct repository *repo);\n+\n+#endif /* REPOSITORY_H */\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322945","messageId":"20170622184348.56497-6-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 05/20] environment: place key repository state in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:33Z","receivedAt":"2017-06-22T18:44:18Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate 'git_dir', 'git_common_dir', 'git_object_dir', 'git_index_file',\n'git_graft_file', and 'namespace' to be stored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h       |  1 -\n environment.c | 58 +++++++++++++---------------------------------------------\n path.c        | 11 ++++++-----\n setup.c       | 17 +++++++++++++++--\n 4 files changed, 34 insertions(+), 53 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 7c81749a9..cd64cbc81 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -771,7 +771,6 @@ extern int core_apply_sparse_checkout;\n extern int precomposed_unicode;\n extern int protect_hfs;\n extern int protect_ntfs;\n-extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n \n /*\n  * Include broken refs in all ref iterations, which will\ndiff --git a/environment.c b/environment.c\nindex e035f6372..aa79ef83e 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,7 @@\n  * are.\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"refs.h\"\n #include \"fmt-merge-msg.h\"\n@@ -101,10 +102,6 @@ static const char *namespace;\n \n static const char *super_prefix;\n \n-static const char *git_dir, *git_common_dir;\n-static char *git_object_dir, *git_index_file, *git_graft_file;\n-int git_db_env, git_index_env, git_graft_env, git_common_dir_env;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -148,41 +145,11 @@ static char *expand_namespace(const char *raw_namespace)\n \treturn strbuf_detach(&buf, NULL);\n }\n \n-static char *git_path_from_env(const char *envvar, const char *git_dir,\n-\t\t\t       const char *path, int *fromenv)\n-{\n-\tconst char *value = getenv(envvar);\n-\tif (!value)\n-\t\treturn xstrfmt(\"%s/%s\", git_dir, path);\n-\tif (fromenv)\n-\t\t*fromenv = 1;\n-\treturn xstrdup(value);\n-}\n-\n void setup_git_env(void)\n {\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *gitfile;\n \tconst char *shallow_file;\n \tconst char *replace_ref_base;\n \n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n-\tif (!git_dir) {\n-\t\tif (!startup_info->have_repository)\n-\t\t\tBUG(\"setup_git_env called without repository\");\n-\t\tgit_dir = DEFAULT_GIT_DIR_ENVIRONMENT;\n-\t}\n-\tgitfile = read_gitfile(git_dir);\n-\tgit_dir = xstrdup(gitfile ? gitfile : git_dir);\n-\tif (get_common_dir(&sb, git_dir))\n-\t\tgit_common_dir_env = 1;\n-\tgit_common_dir = strbuf_detach(&sb, NULL);\n-\tgit_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,\n-\t\t\t\t\t   \"objects\", &git_db_env);\n-\tgit_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,\n-\t\t\t\t\t   \"index\", &git_index_env);\n-\tgit_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, git_common_dir,\n-\t\t\t\t\t   \"info/grafts\", &git_graft_env);\n \tif (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))\n \t\tcheck_replace_refs = 0;\n \treplace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);\n@@ -203,21 +170,21 @@ int is_bare_repository(void)\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n-\t\t|| git_dir;\n+\t\t|| the_repository->gitdir;\n }\n \n const char *get_git_dir(void)\n {\n-\tif (!git_dir)\n+\tif (!the_repository->gitdir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_dir;\n+\treturn the_repository->gitdir;\n }\n \n const char *get_git_common_dir(void)\n {\n-\tif (!git_dir)\n+\tif (!the_repository->commondir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_common_dir;\n+\treturn the_repository->commondir;\n }\n \n const char *get_git_namespace(void)\n@@ -273,9 +240,9 @@ const char *get_git_work_tree(void)\n \n char *get_object_directory(void)\n {\n-\tif (!git_object_dir)\n+\tif (!the_repository->objectdir)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_object_dir;\n+\treturn the_repository->objectdir;\n }\n \n int odb_mkstemp(struct strbuf *template, const char *pattern)\n@@ -313,22 +280,23 @@ int odb_pack_keep(const char *name)\n \n char *get_index_file(void)\n {\n-\tif (!git_index_file)\n+\tif (!the_repository->index_file)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_index_file;\n+\treturn the_repository->index_file;\n }\n \n char *get_graft_file(void)\n {\n-\tif (!git_graft_file)\n+\tif (!the_repository->graft_file)\n \t\tBUG(\"git environment hasn't been setup\");\n-\treturn git_graft_file;\n+\treturn the_repository->graft_file;\n }\n \n int set_git_dir(const char *path)\n {\n \tif (setenv(GIT_DIR_ENVIRONMENT, path, 1))\n \t\treturn error(\"Could not set GIT_DIR to '%s'\", path);\n+\trepo_set_gitdir(the_repository, path);\n \tsetup_git_env();\n \treturn 0;\n }\ndiff --git a/path.c b/path.c\nindex c1cb1cf62..e4abea083 100644\n--- a/path.c\n+++ b/path.c\n@@ -2,6 +2,7 @@\n  * Utilities for paths and pathnames\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"dir.h\"\n@@ -355,7 +356,7 @@ void report_linked_checkout_garbage(void)\n \tconst struct common_dir *p;\n \tint len;\n \n-\tif (!git_common_dir_env)\n+\tif (!the_repository->different_commondir)\n \t\treturn;\n \tstrbuf_addf(&sb, \"%s/\", get_git_dir());\n \tlen = sb.len;\n@@ -374,17 +375,17 @@ void report_linked_checkout_garbage(void)\n static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n {\n \tconst char *base = buf->buf + git_dir_len;\n-\tif (git_graft_env && is_dir_file(base, \"info\", \"grafts\"))\n+\tif (is_dir_file(base, \"info\", \"grafts\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      get_graft_file(), strlen(get_graft_file()));\n-\telse if (git_index_env && !strcmp(base, \"index\"))\n+\telse if (!strcmp(base, \"index\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n \t\t\t      get_index_file(), strlen(get_index_file()));\n-\telse if (git_db_env && dir_prefix(base, \"objects\"))\n+\telse if (dir_prefix(base, \"objects\"))\n \t\treplace_dir(buf, git_dir_len + 7, get_object_directory());\n \telse if (git_hooks_path && dir_prefix(base, \"hooks\"))\n \t\treplace_dir(buf, git_dir_len + 5, git_hooks_path);\n-\telse if (git_common_dir_env)\n+\telse if (the_repository->different_commondir)\n \t\tupdate_common_dir(buf, git_dir_len, NULL);\n }\n \ndiff --git a/setup.c b/setup.c\nindex b477faa44..860507e1f 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"dir.h\"\n #include \"string-list.h\"\n@@ -398,6 +399,11 @@ void setup_work_tree(void)\n \tif (getenv(GIT_WORK_TREE_ENVIRONMENT))\n \t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, \".\", 1);\n \n+\t/*\n+\t * NEEDSWORK: this call can essentially be set_git_dir(get_git_dir())\n+\t * which can cause some problems when trying to free the old value of\n+\t * gitdir.\n+\t */\n \tset_git_dir(remove_leading_path(git_dir, work_tree));\n \tinitialized = 1;\n }\n@@ -1108,8 +1114,15 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t * the user has set GIT_DIR.  It may be beneficial to disallow bogus\n \t * GIT_DIR values at some point in the future.\n \t */\n-\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT))\n-\t\tsetup_git_env();\n+\tif (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT)) {\n+\t\tif (!the_repository->gitdir) {\n+\t\t\tconst char *gitdir = getenv(GIT_DIR_ENVIRONMENT);\n+\t\t\tif (!gitdir)\n+\t\t\t\tgitdir = DEFAULT_GIT_DIR_ENVIRONMENT;\n+\t\t\trepo_set_gitdir(the_repository, gitdir);\n+\t\t\tsetup_git_env();\n+\t\t}\n+\t}\n \n \tstrbuf_release(&dir);\n \tstrbuf_release(&gitdir);\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322946","messageId":"20170622184348.56497-4-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 03/20] environment: remove namespace_len variable","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:31Z","receivedAt":"2017-06-22T18:44:21Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Use 'skip_prefix' instead of 'starts_with' so that we can drop the need\nto keep around 'namespace_len'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n environment.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex a73b08f5d..e035f6372 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -98,7 +98,6 @@ char *git_work_tree_cfg;\n static char *work_tree;\n \n static const char *namespace;\n-static size_t namespace_len;\n \n static const char *super_prefix;\n \n@@ -190,7 +189,6 @@ void setup_git_env(void)\n \tgit_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base\n \t\t\t\t\t\t\t  : \"refs/replace/\");\n \tnamespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));\n-\tnamespace_len = strlen(namespace);\n \tshallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);\n \tif (shallow_file)\n \t\tset_alternate_shallow_file(shallow_file, 0);\n@@ -231,9 +229,10 @@ const char *get_git_namespace(void)\n \n const char *strip_namespace(const char *namespaced_ref)\n {\n-\tif (!starts_with(namespaced_ref, get_git_namespace()))\n-\t\treturn NULL;\n-\treturn namespaced_ref + namespace_len;\n+\tconst char *out;\n+\tif (skip_prefix(namespaced_ref, get_git_namespace(), &out))\n+\t\treturn out;\n+\treturn NULL;\n }\n \n const char *get_super_prefix(void)\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322947","messageId":"20170622184348.56497-10-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 09/20] path: convert strbuf_git_common_path to take a 'struct repository'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:37Z","receivedAt":"2017-06-22T18:44:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c     | 13 ++++++++-----\n path.h     |  8 ++++++--\n worktree.c |  3 ++-\n 3 files changed, 16 insertions(+), 8 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 2434921d8..9be6804a9 100644\n--- a/path.c\n+++ b/path.c\n@@ -524,11 +524,12 @@ int strbuf_git_path_submodule(struct strbuf *buf, const char *path,\n \treturn err;\n }\n \n-static void do_git_common_path(struct strbuf *buf,\n+static void do_git_common_path(const struct repository *repo,\n+\t\t\t       struct strbuf *buf,\n \t\t\t       const char *fmt,\n \t\t\t       va_list args)\n {\n-\tstrbuf_addstr(buf, get_git_common_dir());\n+\tstrbuf_addstr(buf, repo->commondir);\n \tif (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))\n \t\tstrbuf_addch(buf, '/');\n \tstrbuf_vaddf(buf, fmt, args);\n@@ -540,16 +541,18 @@ const char *git_common_path(const char *fmt, ...)\n \tstruct strbuf *pathname = get_pathname();\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_common_path(pathname, fmt, args);\n+\tdo_git_common_path(the_repository, pathname, fmt, args);\n \tva_end(args);\n \treturn pathname->buf;\n }\n \n-void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_git_common_path(struct strbuf *sb,\n+\t\t\t    const struct repository *repo,\n+\t\t\t    const char *fmt, ...)\n {\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_common_path(sb, fmt, args);\n+\tdo_git_common_path(repo, sb, fmt, args);\n \tva_end(args);\n }\n \ndiff --git a/path.h b/path.h\nindex 522cd029b..568d63be5 100644\n--- a/path.h\n+++ b/path.h\n@@ -1,6 +1,8 @@\n #ifndef PATH_H\n #define PATH_H\n \n+struct repository;\n+\n /*\n  * Return a statically allocated filename, either generically (mkpath), in\n  * the repository directory (git_path), or in a submodule's repository\n@@ -17,8 +19,10 @@ extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)\n \t__attribute__((format (printf, 3, 4)));\n extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)\n \t__attribute__((format (printf, 2, 3)));\n-extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n+extern void strbuf_git_common_path(struct strbuf *sb,\n+\t\t\t\t   const struct repository *repo,\n+\t\t\t\t   const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n \t__attribute__((format (printf, 2, 3)));\n extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,\ndiff --git a/worktree.c b/worktree.c\nindex 2801c6d52..e28ffbeb0 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"refs.h\"\n #include \"strbuf.h\"\n #include \"worktree.h\"\n@@ -76,7 +77,7 @@ static struct worktree *get_linked_worktree(const char *id)\n \tif (!id)\n \t\tdie(\"Missing linked worktree name\");\n \n-\tstrbuf_git_common_path(&path, \"worktrees/%s/gitdir\", id);\n+\tstrbuf_git_common_path(&path, the_repository, \"worktrees/%s/gitdir\", id);\n \tif (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)\n \t\t/* invalid gitdir file */\n \t\tgoto done;\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322948","messageId":"20170622184348.56497-9-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 08/20] path: always pass in commondir to update_common_dir","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:36Z","receivedAt":"2017-06-22T18:44:24Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Instead of passing in 'NULL' and having 'update_common_dir()' query for\nthe commondir, have the callers of 'update_common_dir()' be responsible\nfor providing the commondir.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 41c861c96..2434921d8 100644\n--- a/path.c\n+++ b/path.c\n@@ -345,8 +345,6 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len,\n {\n \tchar *base = buf->buf + git_dir_len;\n \tinit_common_trie();\n-\tif (!common_dir)\n-\t\tcommon_dir = get_git_common_dir();\n \tif (trie_find(&common_trie, base, check_common, NULL) > 0)\n \t\treplace_dir(buf, git_dir_len, common_dir);\n }\n@@ -387,7 +385,7 @@ static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n \telse if (git_hooks_path && dir_prefix(base, \"hooks\"))\n \t\treplace_dir(buf, git_dir_len + 5, git_hooks_path);\n \telse if (the_repository->different_commondir)\n-\t\tupdate_common_dir(buf, git_dir_len, NULL);\n+\t\tupdate_common_dir(buf, git_dir_len, get_git_common_dir());\n }\n \n static void do_git_path(const struct worktree *wt, struct strbuf *buf,\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322949","messageId":"20170622184348.56497-8-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 07/20] path: create path.h","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:35Z","receivedAt":"2017-06-22T18:44:25Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Move all path related declarations from cache.h to a new path.h header\nfile.  This makes cache.h smaller and makes it easier to add new path\nrelated functions.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h | 59 +----------------------------------------------------------\n path.c  |  1 +\n path.h  | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 64 insertions(+), 58 deletions(-)\n create mode 100644 path.h\n\ndiff --git a/cache.h b/cache.h\nindex cd64cbc81..c958fc3ce 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -11,6 +11,7 @@\n #include \"string-list.h\"\n #include \"pack-revindex.h\"\n #include \"hash.h\"\n+#include \"path.h\"\n \n #ifndef platform_SHA_CTX\n /*\n@@ -892,64 +893,6 @@ extern void check_repository_format(void);\n #define DATA_CHANGED    0x0020\n #define TYPE_CHANGED    0x0040\n \n-/*\n- * Return a statically allocated filename, either generically (mkpath), in\n- * the repository directory (git_path), or in a submodule's repository\n- * directory (git_path_submodule). In all cases, note that the result\n- * may be overwritten by another call to _any_ of the functions. Consider\n- * using the safer \"dup\" or \"strbuf\" formats below (in some cases, the\n- * unsafe versions have already been removed).\n- */\n-extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n-extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n-extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n-\n-extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)\n-\t__attribute__((format (printf, 3, 4)));\n-extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n-extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n-extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n-extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,\n-\t\t\t\t     const char *fmt, ...)\n-\t__attribute__((format (printf, 3, 4)));\n-extern char *git_pathdup(const char *fmt, ...)\n-\t__attribute__((format (printf, 1, 2)));\n-extern char *mkpathdup(const char *fmt, ...)\n-\t__attribute__((format (printf, 1, 2)));\n-extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)\n-\t__attribute__((format (printf, 2, 3)));\n-\n-extern void report_linked_checkout_garbage(void);\n-\n-/*\n- * You can define a static memoized git path like:\n- *\n- *    static GIT_PATH_FUNC(git_path_foo, \"FOO\");\n- *\n- * or use one of the global ones below.\n- */\n-#define GIT_PATH_FUNC(func, filename) \\\n-\tconst char *func(void) \\\n-\t{ \\\n-\t\tstatic char *ret; \\\n-\t\tif (!ret) \\\n-\t\t\tret = git_pathdup(filename); \\\n-\t\treturn ret; \\\n-\t}\n-\n-const char *git_path_cherry_pick_head(void);\n-const char *git_path_revert_head(void);\n-const char *git_path_squash_msg(void);\n-const char *git_path_merge_msg(void);\n-const char *git_path_merge_rr(void);\n-const char *git_path_merge_mode(void);\n-const char *git_path_merge_head(void);\n-const char *git_path_fetch_head(void);\n-const char *git_path_shallow(void);\n-\n /*\n  * Return the name of the file in the local object database that would\n  * be used to store a loose object with the specified sha1.  The\ndiff --git a/path.c b/path.c\nindex e4abea083..41c861c96 100644\n--- a/path.c\n+++ b/path.c\n@@ -8,6 +8,7 @@\n #include \"dir.h\"\n #include \"worktree.h\"\n #include \"submodule-config.h\"\n+#include \"path.h\"\n \n static int get_st_mode_bits(const char *path, int *mode)\n {\ndiff --git a/path.h b/path.h\nnew file mode 100644\nindex 000000000..522cd029b\n--- /dev/null\n+++ b/path.h\n@@ -0,0 +1,62 @@\n+#ifndef PATH_H\n+#define PATH_H\n+\n+/*\n+ * Return a statically allocated filename, either generically (mkpath), in\n+ * the repository directory (git_path), or in a submodule's repository\n+ * directory (git_path_submodule). In all cases, note that the result\n+ * may be overwritten by another call to _any_ of the functions. Consider\n+ * using the safer \"dup\" or \"strbuf\" formats below (in some cases, the\n+ * unsafe versions have already been removed).\n+ */\n+extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n+extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n+extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n+\n+extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n+extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,\n+\t\t\t\t     const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n+extern char *git_pathdup(const char *fmt, ...)\n+\t__attribute__((format (printf, 1, 2)));\n+extern char *mkpathdup(const char *fmt, ...)\n+\t__attribute__((format (printf, 1, 2)));\n+extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+\n+extern void report_linked_checkout_garbage(void);\n+\n+/*\n+ * You can define a static memoized git path like:\n+ *\n+ *    static GIT_PATH_FUNC(git_path_foo, \"FOO\");\n+ *\n+ * or use one of the global ones below.\n+ */\n+#define GIT_PATH_FUNC(func, filename) \\\n+\tconst char *func(void) \\\n+\t{ \\\n+\t\tstatic char *ret; \\\n+\t\tif (!ret) \\\n+\t\t\tret = git_pathdup(filename); \\\n+\t\treturn ret; \\\n+\t}\n+\n+const char *git_path_cherry_pick_head(void);\n+const char *git_path_revert_head(void);\n+const char *git_path_squash_msg(void);\n+const char *git_path_merge_msg(void);\n+const char *git_path_merge_rr(void);\n+const char *git_path_merge_mode(void);\n+const char *git_path_merge_head(void);\n+const char *git_path_fetch_head(void);\n+const char *git_path_shallow(void);\n+\n+#endif /* PATH_H */\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322950","messageId":"20170622184348.56497-7-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 06/20] environment: store worktree in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:34Z","receivedAt":"2017-06-22T18:44:29Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Migrate 'work_tree' to be stored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n environment.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex aa79ef83e..3fd4b1084 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -96,7 +96,6 @@ int ignore_untracked_cache_config;\n \n /* This is set by setup_git_dir_gently() and/or git_default_config() */\n char *git_work_tree_cfg;\n-static char *work_tree;\n \n static const char *namespace;\n \n@@ -223,19 +222,19 @@ void set_git_work_tree(const char *new_work_tree)\n {\n \tif (git_work_tree_initialized) {\n \t\tnew_work_tree = real_path(new_work_tree);\n-\t\tif (strcmp(new_work_tree, work_tree))\n+\t\tif (strcmp(new_work_tree, the_repository->worktree))\n \t\t\tdie(\"internal error: work tree has already been set\\n\"\n \t\t\t    \"Current worktree: %s\\nNew worktree: %s\",\n-\t\t\t    work_tree, new_work_tree);\n+\t\t\t    the_repository->worktree, new_work_tree);\n \t\treturn;\n \t}\n \tgit_work_tree_initialized = 1;\n-\twork_tree = real_pathdup(new_work_tree, 1);\n+\trepo_set_worktree(the_repository, new_work_tree);\n }\n \n const char *get_git_work_tree(void)\n {\n-\treturn work_tree;\n+\treturn the_repository->worktree;\n }\n \n char *get_object_directory(void)\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322951","messageId":"20170622184348.56497-12-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 11/20] path: worktree_git_path() should not use file relocation","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:39Z","receivedAt":"2017-06-22T18:44:34Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"git_path is a convenience function that usually produces a string\n$GIT_DIR/<path>.  Since v2.5.0-rc0~143^2~35 (git_path(): be aware of\nfile relocation in $GIT_DIR, 2014-11-30), as a side benefit callers\nget support for path relocation variables like $GIT_OBJECT_DIRECTORY:\n\n- git_path(\"index\") is $GIT_INDEX_FILE when set\n- git_path(\"info/grafts\") is $GIT_GRAFTS_FILE when set\n- git_path(\"objects/<foo>\") is $GIT_OBJECT_DIRECTORY/<foo> when set\n- git_path(\"hooks/<foo>\") is <foo> under core.hookspath when set\n- git_path(\"refs/<foo>\") etc (see path.c::common_list) is relative\n  to $GIT_COMMON_DIR instead of $GIT_DIR\n\nworktree_git_path, by comparison, is designed to resolve files in a\nspecific worktree's git dir.  Unfortunately, it shares code with\ngit_path and performs the same relocation.  The result is that paths\nthat are meant to be relative to the specified worktree's git dir end\nup replaced by paths from environment variables within the current git\ndir.\n\nLuckily, no current callers pass such arguments.  The relocation was\nnoticed when testing the result of merging two patches under review,\none of which introduces a caller:\n\n* The first patch made git prune check the index file in each\n  worktree's git dir (using worktree_git_path(wt, \"index\")) for\n  objects not to prune.  This would trigger the unwanted relocation\n  when GIT_INDEX_FILE is set, causing objects reachable from the\n  index to be pruned.\n\n* The second patch simplified the relocation logic for index,\n  info/grafts, objects, and hooks to happen unconditionally instead of\n  based on whether environment or configuration variables are set.\n  This caused the relocation to trigger even when GIT_INDEX_FILE is\n  not set.\n\n[jn: rewrote commit message; skipping all relocation instead of just\n GIT_INDEX_FILE]\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n path.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/path.c b/path.c\nindex 76a872297..2bdd0044f 100644\n--- a/path.c\n+++ b/path.c\n@@ -411,7 +411,8 @@ static void do_git_path(const struct repository *repo,\n \t\tstrbuf_addch(buf, '/');\n \tgitdir_len = buf->len;\n \tstrbuf_vaddf(buf, fmt, args);\n-\tadjust_git_path(repo, buf, gitdir_len);\n+\tif (!wt)\n+\t\tadjust_git_path(repo, buf, gitdir_len);\n \tstrbuf_cleanup_path(buf);\n }\n \n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322952","messageId":"20170622184348.56497-17-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 16/20] submodule-config: store the_submodule_cache in the_repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:44Z","receivedAt":"2017-06-22T18:44:36Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Refactor how 'the_submodule_cache' is handled so that it can be stored\ninside of a repository object.  Also migrate 'the_submodule_cache' to be\nstored in 'the_repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n repository.c       |  6 +++++\n repository.h       |  4 ++++\n submodule-config.c | 70 ++++++++++++++++++++++++++++++++++++++++--------------\n submodule-config.h | 10 ++++++++\n 4 files changed, 72 insertions(+), 18 deletions(-)\n\ndiff --git a/repository.c b/repository.c\nindex 6f6f4d91e..358c17517 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"repository.h\"\n #include \"config.h\"\n+#include \"submodule-config.h\"\n \n /* The main repository */\n static struct repository the_repo;\n@@ -164,6 +165,11 @@ void repo_clear(struct repository *repo)\n \t\trepo->config = NULL;\n \t}\n \n+\tif (repo->submodule_cache) {\n+\t\tsubmodule_cache_free(repo->submodule_cache);\n+\t\trepo->submodule_cache = NULL;\n+\t}\n+\n \tif (repo->index) {\n \t\tdiscard_index(repo->index);\n \t\tfree(repo->index);\ndiff --git a/repository.h b/repository.h\nindex 3a41568aa..c40738ceb 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -3,6 +3,7 @@\n \n struct config_set;\n struct index_state;\n+struct submodule_cache;\n \n struct repository {\n \t/* Environment */\n@@ -50,6 +51,9 @@ struct repository {\n \t */\n \tstruct config_set *config;\n \n+\t/* Repository's submodule config as defined by '.gitmodules' */\n+\tstruct submodule_cache *submodule_cache;\n+\n \t/*\n \t * Repository's in-memory index.\n \t * 'repo_read_index()' can be used to populate 'index'.\ndiff --git a/submodule-config.c b/submodule-config.c\nindex d8f8d5ea3..37cfcceb9 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n@@ -15,6 +16,7 @@\n struct submodule_cache {\n \tstruct hashmap for_path;\n \tstruct hashmap for_name;\n+\tunsigned initialized:1;\n };\n \n /*\n@@ -31,9 +33,6 @@ enum lookup_type {\n \tlookup_path\n };\n \n-static struct submodule_cache the_submodule_cache;\n-static int is_cache_init;\n-\n static int config_path_cmp(const struct submodule_entry *a,\n \t\t\t   const struct submodule_entry *b,\n \t\t\t   const void *unused)\n@@ -50,10 +49,16 @@ static int config_name_cmp(const struct submodule_entry *a,\n \t       hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);\n }\n \n-static void cache_init(struct submodule_cache *cache)\n+static struct submodule_cache *submodule_cache_alloc(void)\n+{\n+\treturn xcalloc(1, sizeof(struct submodule_cache));\n+}\n+\n+static void submodule_cache_init(struct submodule_cache *cache)\n {\n \thashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);\n \thashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);\n+\tcache->initialized = 1;\n }\n \n static void free_one_config(struct submodule_entry *entry)\n@@ -65,11 +70,14 @@ static void free_one_config(struct submodule_entry *entry)\n \tfree(entry->config);\n }\n \n-static void cache_free(struct submodule_cache *cache)\n+static void submodule_cache_clear(struct submodule_cache *cache)\n {\n \tstruct hashmap_iter iter;\n \tstruct submodule_entry *entry;\n \n+\tif (!cache->initialized)\n+\t\treturn;\n+\n \t/*\n \t * We iterate over the name hash here to be symmetric with the\n \t * allocation of struct submodule entries. Each is allocated by\n@@ -81,6 +89,13 @@ static void cache_free(struct submodule_cache *cache)\n \n \thashmap_free(&cache->for_path, 1);\n \thashmap_free(&cache->for_name, 1);\n+\tcache->initialized = 0;\n+}\n+\n+void submodule_cache_free(struct submodule_cache *cache)\n+{\n+\tsubmodule_cache_clear(cache);\n+\tfree(cache);\n }\n \n static unsigned int hash_sha1_string(const unsigned char *sha1,\n@@ -494,43 +509,62 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \treturn submodule;\n }\n \n-static void ensure_cache_init(void)\n+static void submodule_cache_check_init(struct repository *repo)\n {\n-\tif (is_cache_init)\n+\tif (repo->submodule_cache && repo->submodule_cache->initialized)\n \t\treturn;\n \n-\tcache_init(&the_submodule_cache);\n-\tis_cache_init = 1;\n+\tif (!repo->submodule_cache)\n+\t\trepo->submodule_cache = submodule_cache_alloc();\n+\n+\tsubmodule_cache_init(repo->submodule_cache);\n }\n \n-int parse_submodule_config_option(const char *var, const char *value)\n+int submodule_config_option(struct repository *repo,\n+\t\t\t    const char *var, const char *value)\n {\n \tstruct parse_config_parameter parameter;\n-\tparameter.cache = &the_submodule_cache;\n+\n+\tsubmodule_cache_check_init(repo);\n+\n+\tparameter.cache = repo->submodule_cache;\n \tparameter.treeish_name = NULL;\n \tparameter.gitmodules_sha1 = null_sha1;\n \tparameter.overwrite = 1;\n \n-\tensure_cache_init();\n \treturn parse_config(var, value, &parameter);\n }\n \n+int parse_submodule_config_option(const char *var, const char *value)\n+{\n+\treturn submodule_config_option(the_repository, var, value);\n+}\n+\n const struct submodule *submodule_from_name(const unsigned char *treeish_name,\n \t\tconst char *name)\n {\n-\tensure_cache_init();\n-\treturn config_from(&the_submodule_cache, treeish_name, name, lookup_name);\n+\tsubmodule_cache_check_init(the_repository);\n+\treturn config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);\n }\n \n const struct submodule *submodule_from_path(const unsigned char *treeish_name,\n \t\tconst char *path)\n {\n-\tensure_cache_init();\n-\treturn config_from(&the_submodule_cache, treeish_name, path, lookup_path);\n+\tsubmodule_cache_check_init(the_repository);\n+\treturn config_from(the_repository->submodule_cache, treeish_name, path, lookup_path);\n+}\n+\n+const struct submodule *submodule_from_cache(struct repository *repo,\n+\t\t\t\t\t     const unsigned char *treeish_name,\n+\t\t\t\t\t     const char *key)\n+{\n+\tsubmodule_cache_check_init(repo);\n+\treturn config_from(repo->submodule_cache, treeish_name,\n+\t\t\t   key, lookup_path);\n }\n \n void submodule_free(void)\n {\n-\tcache_free(&the_submodule_cache);\n-\tis_cache_init = 0;\n+\tif (the_repository->submodule_cache)\n+\t\tsubmodule_cache_clear(the_repository->submodule_cache);\n }\ndiff --git a/submodule-config.h b/submodule-config.h\nindex d434ecdb4..bc45a25e8 100644\n--- a/submodule-config.h\n+++ b/submodule-config.h\n@@ -22,14 +22,24 @@ struct submodule {\n \tint recommend_shallow;\n };\n \n+struct submodule_cache;\n+struct repository;\n+\n+extern void submodule_cache_free(struct submodule_cache *cache);\n+\n extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_submodule_config_option(const char *var, const char *value);\n+extern int submodule_config_option(struct repository *repo,\n+\t\t\t\t   const char *var, const char *value);\n extern const struct submodule *submodule_from_name(\n \t\tconst unsigned char *commit_or_tree, const char *name);\n extern const struct submodule *submodule_from_path(\n \t\tconst unsigned char *commit_or_tree, const char *path);\n+extern const struct submodule *submodule_from_cache(struct repository *repo,\n+\t\t\t\t\t\t    const unsigned char *treeish_name,\n+\t\t\t\t\t\t    const char *key);\n extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,\n \t\t\t\t      unsigned char *gitmodules_sha1,\n \t\t\t\t      struct strbuf *rev);\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322953","messageId":"20170622184348.56497-11-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 10/20] path: convert do_git_path to take a 'struct repository'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:38Z","receivedAt":"2017-06-22T18:44:37Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"In preparation to adding 'git_path' like functions which operate on a\n'struct repository' convert 'do_git_path' to take a 'struct repository'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 42 ++++++++++++++++++++++++++++--------------\n 1 file changed, 28 insertions(+), 14 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 9be6804a9..76a872297 100644\n--- a/path.c\n+++ b/path.c\n@@ -371,33 +371,47 @@ void report_linked_checkout_garbage(void)\n \tstrbuf_release(&sb);\n }\n \n-static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n+static void adjust_git_path(const struct repository *repo,\n+\t\t\t    struct strbuf *buf, int git_dir_len)\n {\n \tconst char *base = buf->buf + git_dir_len;\n \tif (is_dir_file(base, \"info\", \"grafts\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n-\t\t\t      get_graft_file(), strlen(get_graft_file()));\n+\t\t\t      repo->graft_file, strlen(repo->graft_file));\n \telse if (!strcmp(base, \"index\"))\n \t\tstrbuf_splice(buf, 0, buf->len,\n-\t\t\t      get_index_file(), strlen(get_index_file()));\n+\t\t\t      repo->index_file, strlen(repo->index_file));\n \telse if (dir_prefix(base, \"objects\"))\n-\t\treplace_dir(buf, git_dir_len + 7, get_object_directory());\n+\t\treplace_dir(buf, git_dir_len + 7, repo->objectdir);\n \telse if (git_hooks_path && dir_prefix(base, \"hooks\"))\n \t\treplace_dir(buf, git_dir_len + 5, git_hooks_path);\n-\telse if (the_repository->different_commondir)\n-\t\tupdate_common_dir(buf, git_dir_len, get_git_common_dir());\n+\telse if (repo->different_commondir)\n+\t\tupdate_common_dir(buf, git_dir_len, repo->commondir);\n }\n \n-static void do_git_path(const struct worktree *wt, struct strbuf *buf,\n+static void strbuf_worktree_gitdir(struct strbuf *buf,\n+\t\t\t\t   const struct repository *repo,\n+\t\t\t\t   const struct worktree *wt)\n+{\n+\tif (!wt)\n+\t\tstrbuf_addstr(buf, repo->gitdir);\n+\telse if (!wt->id)\n+\t\tstrbuf_addstr(buf, repo->commondir);\n+\telse\n+\t\tstrbuf_git_common_path(buf, repo, \"worktrees/%s\", wt->id);\n+}\n+\n+static void do_git_path(const struct repository *repo,\n+\t\t\tconst struct worktree *wt, struct strbuf *buf,\n \t\t\tconst char *fmt, va_list args)\n {\n \tint gitdir_len;\n-\tstrbuf_addstr(buf, get_worktree_git_dir(wt));\n+\tstrbuf_worktree_gitdir(buf, repo, wt);\n \tif (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))\n \t\tstrbuf_addch(buf, '/');\n \tgitdir_len = buf->len;\n \tstrbuf_vaddf(buf, fmt, args);\n-\tadjust_git_path(buf, gitdir_len);\n+\tadjust_git_path(repo, buf, gitdir_len);\n \tstrbuf_cleanup_path(buf);\n }\n \n@@ -406,7 +420,7 @@ char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n \tva_list args;\n \tstrbuf_reset(buf);\n \tva_start(args, fmt);\n-\tdo_git_path(NULL, buf, fmt, args);\n+\tdo_git_path(the_repository, NULL, buf, fmt, args);\n \tva_end(args);\n \treturn buf->buf;\n }\n@@ -415,7 +429,7 @@ void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)\n {\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_path(NULL, sb, fmt, args);\n+\tdo_git_path(the_repository, NULL, sb, fmt, args);\n \tva_end(args);\n }\n \n@@ -424,7 +438,7 @@ const char *git_path(const char *fmt, ...)\n \tstruct strbuf *pathname = get_pathname();\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_path(NULL, pathname, fmt, args);\n+\tdo_git_path(the_repository, NULL, pathname, fmt, args);\n \tva_end(args);\n \treturn pathname->buf;\n }\n@@ -434,7 +448,7 @@ char *git_pathdup(const char *fmt, ...)\n \tstruct strbuf path = STRBUF_INIT;\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_path(NULL, &path, fmt, args);\n+\tdo_git_path(the_repository, NULL, &path, fmt, args);\n \tva_end(args);\n \treturn strbuf_detach(&path, NULL);\n }\n@@ -465,7 +479,7 @@ const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)\n \tstruct strbuf *pathname = get_pathname();\n \tva_list args;\n \tva_start(args, fmt);\n-\tdo_git_path(wt, pathname, fmt, args);\n+\tdo_git_path(the_repository, wt, pathname, fmt, args);\n \tva_end(args);\n \treturn pathname->buf;\n }\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322954","messageId":"20170622184348.56497-19-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 18/20] submodule: convert is_submodule_initialized to work on a repository","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:46Z","receivedAt":"2017-06-22T18:44:41Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'is_submodule_initialized()' to take a repository object and\nwhile we're at it, lets rename the function to 'is_submodule_active()'\nand remove the NEEDSWORK comment.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/grep.c              |  3 ++-\n builtin/submodule--helper.c |  9 +++++----\n submodule.c                 | 20 ++++++++------------\n submodule.h                 |  2 +-\n 4 files changed, 16 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex f61a9d938..e3ba1d98e 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -4,6 +4,7 @@\n  * Copyright (c) 2006 Junio C Hamano\n  */\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"blob.h\"\n #include \"tree.h\"\n@@ -643,7 +644,7 @@ static int grep_submodule_launch(struct grep_opt *opt,\n static int grep_submodule(struct grep_opt *opt, const struct object_id *oid,\n \t\t\t  const char *filename, const char *path)\n {\n-\tif (!is_submodule_initialized(path))\n+\tif (!is_submodule_active(the_repository, path))\n \t\treturn 0;\n \tif (!is_submodule_populated_gently(path, NULL)) {\n \t\t/*\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 8517032b3..e1b06c41d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1,4 +1,5 @@\n #include \"builtin.h\"\n+#include \"repository.h\"\n #include \"cache.h\"\n #include \"config.h\"\n #include \"parse-options.h\"\n@@ -280,7 +281,7 @@ static void module_list_active(struct module_list *list)\n \tfor (i = 0; i < list->nr; i++) {\n \t\tconst struct cache_entry *ce = list->entries[i];\n \n-\t\tif (!is_submodule_initialized(ce->name))\n+\t\tif (!is_submodule_active(the_repository, ce->name))\n \t\t\tcontinue;\n \n \t\tALLOC_GROW(active_modules.entries,\n@@ -362,7 +363,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t *\n \t * Set active flag for the submodule being initialized\n \t */\n-\tif (!is_submodule_initialized(path)) {\n+\tif (!is_submodule_active(the_repository, path)) {\n \t\tstrbuf_reset(&sb);\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n@@ -817,7 +818,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \t}\n \n \t/* Check if the submodule has been initialized. */\n-\tif (!is_submodule_initialized(ce->name)) {\n+\tif (!is_submodule_active(the_repository, ce->name)) {\n \t\tnext_submodule_warn_missing(suc, out, displaypath);\n \t\tgoto cleanup;\n \t}\n@@ -1193,7 +1194,7 @@ static int is_active(int argc, const char **argv, const char *prefix)\n \n \tgitmodules_config();\n \n-\treturn !is_submodule_initialized(argv[1]);\n+\treturn !is_submodule_active(the_repository, argv[1]);\n }\n \n #define SUPPORT_SUPER_PREFIX (1<<0)\ndiff --git a/submodule.c b/submodule.c\nindex d0b894772..b23c25311 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -283,21 +283,17 @@ void gitmodules_config_sha1(const unsigned char *commit_sha1)\n }\n \n /*\n- * NEEDSWORK: With the addition of different configuration options to determine\n- * if a submodule is of interests, the validity of this function's name comes\n- * into question.  Once the dust has settled and more concrete terminology is\n- * decided upon, come up with a more proper name for this function.  One\n- * potential candidate could be 'is_submodule_active()'.\n- *\n  * Determine if a submodule has been initialized at a given 'path'\n  */\n-int is_submodule_initialized(const char *path)\n+int is_submodule_active(struct repository *repo, const char *path)\n {\n \tint ret = 0;\n \tchar *key = NULL;\n \tchar *value = NULL;\n \tconst struct string_list *sl;\n-\tconst struct submodule *module = submodule_from_path(null_sha1, path);\n+\tconst struct submodule *module;\n+\n+\tmodule = submodule_from_cache(repo, null_sha1, path);\n \n \t/* early return if there isn't a path->module mapping */\n \tif (!module)\n@@ -305,14 +301,14 @@ int is_submodule_initialized(const char *path)\n \n \t/* submodule.<name>.active is set */\n \tkey = xstrfmt(\"submodule.%s.active\", module->name);\n-\tif (!git_config_get_bool(key, &ret)) {\n+\tif (!repo_config_get_bool(repo, key, &ret)) {\n \t\tfree(key);\n \t\treturn ret;\n \t}\n \tfree(key);\n \n \t/* submodule.active is set */\n-\tsl = git_config_get_value_multi(\"submodule.active\");\n+\tsl = repo_config_get_value_multi(repo, \"submodule.active\");\n \tif (sl) {\n \t\tstruct pathspec ps;\n \t\tstruct argv_array args = ARGV_ARRAY_INIT;\n@@ -332,7 +328,7 @@ int is_submodule_initialized(const char *path)\n \n \t/* fallback to checking if the URL is set */\n \tkey = xstrfmt(\"submodule.%s.url\", module->name);\n-\tret = !git_config_get_string(key, &value);\n+\tret = !repo_config_get_string(repo, key, &value);\n \n \tfree(value);\n \tfree(key);\n@@ -1532,7 +1528,7 @@ int submodule_move_head(const char *path,\n \tconst struct submodule *sub;\n \tint *error_code_ptr, error_code;\n \n-\tif (!is_submodule_initialized(path))\n+\tif (!is_submodule_active(the_repository, path))\n \t\treturn 0;\n \n \tif (flags & SUBMODULE_MOVE_HEAD_FORCE)\ndiff --git a/submodule.h b/submodule.h\nindex 8a3771ec6..623ce6ad7 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -49,7 +49,7 @@ void load_submodule_cache(void);\n extern void gitmodules_config(void);\n extern void repo_read_gitmodules(struct repository *repo);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n-extern int is_submodule_initialized(const char *path);\n+extern int is_submodule_active(struct repository *repo, const char *path);\n /*\n  * Determine if a submodule has been populated at a given 'path' by checking if\n  * the <path>/.git resolves to a valid git repository.\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322955","messageId":"20170622184348.56497-15-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 14/20] config: read config from a repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:42Z","receivedAt":"2017-06-22T18:44:42Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach the config machinery to read config information from a repository\nobject.  This involves storing a 'struct config_set' inside the\nrepository object and adding a number of functions (repo_config*) to be\nable to query a repository's config.\n\nThe current config API enables lazy-loading of the config.  This means\nthat when 'git_config_get_int()' is called, if the_config_set hasn't\nbeen populated yet, then it will be populated and properly initialized by\nreading the necessary config files (system wide .gitconfig, user's home\n.gitconfig, and the repository's config).  To maintain this paradigm,\nthe new API to read from a repository object's config will also perform\nthis lazy-initialization.\n\nSince both APIs (git_config_get* and repo_config_get*) have the same\nsemantics we can migrate the default config to be stored within\n'the_repository' and just have the 'git_config_get*' family of functions\nredirect to the 'repo_config_get*' functions.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n config.c     | 216 +++++++++++++++++++++++++++++++++++++++--------------------\n config.h     |  24 +++++++\n repository.c |   7 ++\n repository.h |  10 +++\n 4 files changed, 183 insertions(+), 74 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex 6f0f8b30f..be1c640a4 100644\n--- a/config.c\n+++ b/config.c\n@@ -7,6 +7,7 @@\n  */\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"repository.h\"\n #include \"lockfile.h\"\n #include \"exec_cmd.h\"\n #include \"strbuf.h\"\n@@ -72,13 +73,6 @@ static int core_compression_seen;\n static int pack_compression_seen;\n static int zlib_compression_seen;\n \n-/*\n- * Default config_set that contains key-value pairs from the usual set of config\n- * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG\n- * config file and the global /etc/gitconfig)\n- */\n-static struct config_set the_config_set;\n-\n static int config_file_fgetc(struct config_source *conf)\n {\n \treturn getc_unlocked(conf->u.file);\n@@ -1605,31 +1599,6 @@ int config_with_options(config_fn_t fn, void *data,\n \treturn do_git_config_sequence(opts, fn, data);\n }\n \n-static void git_config_raw(config_fn_t fn, void *data)\n-{\n-\tstruct config_options opts = {0};\n-\n-\topts.respect_includes = 1;\n-\tif (have_git_dir()) {\n-\t\topts.commondir = get_git_common_dir();\n-\t\topts.git_dir = get_git_dir();\n-\t}\n-\n-\tif (config_with_options(fn, data, NULL, &opts) < 0)\n-\t\t/*\n-\t\t * config_with_options() normally returns only\n-\t\t * zero, as most errors are fatal, and\n-\t\t * non-fatal potential errors are guarded by \"if\"\n-\t\t * statements that are entered only when no error is\n-\t\t * possible.\n-\t\t *\n-\t\t * If we ever encounter a non-fatal error, it means\n-\t\t * something went really wrong and we should stop\n-\t\t * immediately.\n-\t\t */\n-\t\tdie(_(\"unknown error occurred while reading the configuration files\"));\n-}\n-\n static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)\n {\n \tint i, value_index;\n@@ -1683,14 +1652,6 @@ void read_early_config(config_fn_t cb, void *data)\n \tstrbuf_release(&gitdir);\n }\n \n-static void git_config_check_init(void);\n-\n-void git_config(config_fn_t fn, void *data)\n-{\n-\tgit_config_check_init();\n-\tconfigset_iter(&the_config_set, fn, data);\n-}\n-\n static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)\n {\n \tstruct config_set_element k;\n@@ -1900,87 +1861,194 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha\n \t\treturn 1;\n }\n \n-static void git_config_check_init(void)\n+/* Functions use to read configuration from a repository */\n+static void repo_read_config(struct repository *repo)\n {\n-\tif (the_config_set.hash_initialized)\n+\tstruct config_options opts;\n+\n+\topts.respect_includes = 1;\n+\topts.commondir = repo->commondir;\n+\topts.git_dir = repo->gitdir;\n+\n+\tif (!repo->config)\n+\t\trepo->config = xcalloc(1, sizeof(struct config_set));\n+\telse\n+\t\tgit_configset_clear(repo->config);\n+\n+\tgit_configset_init(repo->config);\n+\n+\tif (config_with_options(config_set_callback, repo->config, NULL, &opts) < 0)\n+\t\t/*\n+\t\t * config_with_options() normally returns only\n+\t\t * zero, as most errors are fatal, and\n+\t\t * non-fatal potential errors are guarded by \"if\"\n+\t\t * statements that are entered only when no error is\n+\t\t * possible.\n+\t\t *\n+\t\t * If we ever encounter a non-fatal error, it means\n+\t\t * something went really wrong and we should stop\n+\t\t * immediately.\n+\t\t */\n+\t\tdie(_(\"unknown error occurred while reading the configuration files\"));\n+}\n+\n+static void git_config_check_init(struct repository *repo)\n+{\n+\tif (repo->config && repo->config->hash_initialized)\n \t\treturn;\n-\tgit_configset_init(&the_config_set);\n-\tgit_config_raw(config_set_callback, &the_config_set);\n+\trepo_read_config(repo);\n }\n \n-void git_config_clear(void)\n+static void repo_config_clear(struct repository *repo)\n {\n-\tif (!the_config_set.hash_initialized)\n+\tif (!repo->config || !repo->config->hash_initialized)\n \t\treturn;\n-\tgit_configset_clear(&the_config_set);\n+\tgit_configset_clear(repo->config);\n }\n \n-int git_config_get_value(const char *key, const char **value)\n+void repo_config(struct repository *repo, config_fn_t fn, void *data)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_value(&the_config_set, key, value);\n+\tgit_config_check_init(repo);\n+\tconfigset_iter(repo->config, fn, data);\n }\n \n-const struct string_list *git_config_get_value_multi(const char *key)\n+int repo_config_get_value(struct repository *repo,\n+\t\t\t  const char *key, const char **value)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_value_multi(&the_config_set, key);\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_value(repo->config, key, value);\n }\n \n-int git_config_get_string_const(const char *key, const char **dest)\n+const struct string_list *repo_config_get_value_multi(struct repository *repo,\n+\t\t\t\t\t\t      const char *key)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_value_multi(repo->config, key);\n+}\n+\n+int repo_config_get_string_const(struct repository *repo,\n+\t\t\t\t const char *key, const char **dest)\n+{\n+\tint ret;\n+\tgit_config_check_init(repo);\n+\tret = git_configset_get_string_const(repo->config, key, dest);\n+\tif (ret < 0)\n+\t\tgit_die_config(key, NULL);\n+\treturn ret;\n+}\n+\n+int repo_config_get_string(struct repository *repo,\n+\t\t\t   const char *key, char **dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn repo_config_get_string_const(repo, key, (const char **)dest);\n+}\n+\n+int repo_config_get_int(struct repository *repo,\n+\t\t\tconst char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_int(repo->config, key, dest);\n+}\n+\n+int repo_config_get_ulong(struct repository *repo,\n+\t\t\t  const char *key, unsigned long *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_ulong(repo->config, key, dest);\n+}\n+\n+int repo_config_get_bool(struct repository *repo,\n+\t\t\t const char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_bool(repo->config, key, dest);\n+}\n+\n+int repo_config_get_bool_or_int(struct repository *repo,\n+\t\t\t\tconst char *key, int *is_bool, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_bool_or_int(repo->config, key, is_bool, dest);\n+}\n+\n+int repo_config_get_maybe_bool(struct repository *repo,\n+\t\t\t       const char *key, int *dest)\n+{\n+\tgit_config_check_init(repo);\n+\treturn git_configset_get_maybe_bool(repo->config, key, dest);\n+}\n+\n+int repo_config_get_pathname(struct repository *repo,\n+\t\t\t     const char *key, const char **dest)\n {\n \tint ret;\n-\tgit_config_check_init();\n-\tret = git_configset_get_string_const(&the_config_set, key, dest);\n+\tgit_config_check_init(repo);\n+\tret = git_configset_get_pathname(repo->config, key, dest);\n \tif (ret < 0)\n \t\tgit_die_config(key, NULL);\n \treturn ret;\n }\n \n+/* Functions used historically to read configuration from 'the_repository' */\n+void git_config(config_fn_t fn, void *data)\n+{\n+\trepo_config(the_repository, fn, data);\n+}\n+\n+void git_config_clear(void)\n+{\n+\trepo_config_clear(the_repository);\n+}\n+\n+int git_config_get_value(const char *key, const char **value)\n+{\n+\treturn repo_config_get_value(the_repository, key, value);\n+}\n+\n+const struct string_list *git_config_get_value_multi(const char *key)\n+{\n+\treturn repo_config_get_value_multi(the_repository, key);\n+}\n+\n+int git_config_get_string_const(const char *key, const char **dest)\n+{\n+\treturn repo_config_get_string_const(the_repository, key, dest);\n+}\n+\n int git_config_get_string(const char *key, char **dest)\n {\n-\tgit_config_check_init();\n-\treturn git_config_get_string_const(key, (const char **)dest);\n+\treturn repo_config_get_string(the_repository, key, dest);\n }\n \n int git_config_get_int(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_int(&the_config_set, key, dest);\n+\treturn repo_config_get_int(the_repository, key, dest);\n }\n \n int git_config_get_ulong(const char *key, unsigned long *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_ulong(&the_config_set, key, dest);\n+\treturn repo_config_get_ulong(the_repository, key, dest);\n }\n \n int git_config_get_bool(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_bool(&the_config_set, key, dest);\n+\treturn repo_config_get_bool(the_repository, key, dest);\n }\n \n int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);\n+\treturn repo_config_get_bool_or_int(the_repository, key, is_bool, dest);\n }\n \n int git_config_get_maybe_bool(const char *key, int *dest)\n {\n-\tgit_config_check_init();\n-\treturn git_configset_get_maybe_bool(&the_config_set, key, dest);\n+\treturn repo_config_get_maybe_bool(the_repository, key, dest);\n }\n \n int git_config_get_pathname(const char *key, const char **dest)\n {\n-\tint ret;\n-\tgit_config_check_init();\n-\tret = git_configset_get_pathname(&the_config_set, key, dest);\n-\tif (ret < 0)\n-\t\tgit_die_config(key, NULL);\n-\treturn ret;\n+\treturn repo_config_get_pathname(the_repository, key, dest);\n }\n \n int git_config_get_expiry(const char *key, const char **output)\ndiff --git a/config.h b/config.h\nindex 9e038cce2..0352da117 100644\n--- a/config.h\n+++ b/config.h\n@@ -163,6 +163,30 @@ extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key,\n extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);\n extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);\n \n+/* Functions for reading a repository's config */\n+struct repository;\n+extern void repo_config(struct repository *repo, config_fn_t fn, void *data);\n+extern int repo_config_get_value(struct repository *repo,\n+\t\t\t\t const char *key, const char **value);\n+extern const struct string_list *repo_config_get_value_multi(struct repository *repo,\n+\t\t\t\t\t\t\t     const char *key);\n+extern int repo_config_get_string_const(struct repository *repo,\n+\t\t\t\t\tconst char *key, const char **dest);\n+extern int repo_config_get_string(struct repository *repo,\n+\t\t\t\t  const char *key, char **dest);\n+extern int repo_config_get_int(struct repository *repo,\n+\t\t\t       const char *key, int *dest);\n+extern int repo_config_get_ulong(struct repository *repo,\n+\t\t\t\t const char *key, unsigned long *dest);\n+extern int repo_config_get_bool(struct repository *repo,\n+\t\t\t\tconst char *key, int *dest);\n+extern int repo_config_get_bool_or_int(struct repository *repo,\n+\t\t\t\t       const char *key, int *is_bool, int *dest);\n+extern int repo_config_get_maybe_bool(struct repository *repo,\n+\t\t\t\t      const char *key, int *dest);\n+extern int repo_config_get_pathname(struct repository *repo,\n+\t\t\t\t    const char *key, const char **dest);\n+\n extern int git_config_get_value(const char *key, const char **value);\n extern const struct string_list *git_config_get_value_multi(const char *key);\n extern void git_config_clear(void);\ndiff --git a/repository.c b/repository.c\nindex cf440405a..686a964ad 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"repository.h\"\n+#include \"config.h\"\n \n /* The main repository */\n static struct repository the_repo;\n@@ -156,4 +157,10 @@ void repo_clear(struct repository *repo)\n \trepo->index_file = NULL;\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n+\n+\tif (repo->config) {\n+\t\tgit_configset_clear(repo->config);\n+\t\tfree(repo->config);\n+\t\trepo->config = NULL;\n+\t}\n }\ndiff --git a/repository.h b/repository.h\nindex 0a1db9633..8ae5e8653 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -1,6 +1,8 @@\n #ifndef REPOSITORY_H\n #define REPOSITORY_H\n \n+struct config_set;\n+\n struct repository {\n \t/* Environment */\n \t/*\n@@ -39,6 +41,14 @@ struct repository {\n \t */\n \tchar *worktree;\n \n+\t/* Subsystems */\n+\t/*\n+\t * Repository's config which contains key-value pairs from the usual\n+\t * set of config files (i.e. repo specific .git/config, user wide\n+\t * ~/.gitconfig, XDG config file and the global /etc/gitconfig)\n+\t */\n+\tstruct config_set *config;\n+\n \t/* Configurations */\n \t/*\n \t * Bit used during initialization to indicate if repository state (like\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322956","messageId":"20170622184348.56497-20-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 19/20] repository: enable initialization of submodules","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:47Z","receivedAt":"2017-06-22T18:44:45Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce 'repo_submodule_init()' which performs initialization of a\n'struct repository' as a submodule of another 'struct repository'.\n\nThe resulting submodule 'struct repository' can be in one of three states:\n\n  1. The submodule is initialized and has a worktree.\n\n  2. The submodule is initialized but does not have a worktree.  This\n     would occur when the submodule's gitdir is present in the\n     superproject's 'gitdir/modules/' directory yet the submodule has not\n     been checked out in superproject's worktree.\n\n  3. The submodule remains uninitialized due to an error in the\n     initialization process or there is no matching submodule at the\n     provided path in the superproject.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n repository.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n repository.h | 10 ++++++++++\n 2 files changed, 64 insertions(+)\n\ndiff --git a/repository.c b/repository.c\nindex 358c17517..edca90740 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -144,6 +144,58 @@ int repo_init(struct repository *repo, const char *gitdir, const char *worktree)\n \treturn -1;\n }\n \n+/*\n+ * Initialize 'submodule' as the submodule given by 'path' in parent repository\n+ * 'superproject'.\n+ * Return 0 upon success and a non-zero value upon failure.\n+ */\n+int repo_submodule_init(struct repository *submodule,\n+\t\t\tstruct repository *superproject,\n+\t\t\tconst char *path)\n+{\n+\tconst struct submodule *sub;\n+\tstruct strbuf gitdir = STRBUF_INIT;\n+\tstruct strbuf worktree = STRBUF_INIT;\n+\tint ret = 0;\n+\n+\tsub = submodule_from_cache(superproject, null_sha1, path);\n+\tif (!sub) {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\tstrbuf_repo_worktree_path(&gitdir, superproject, \"%s/.git\", path);\n+\tstrbuf_repo_worktree_path(&worktree, superproject, \"%s\", path);\n+\n+\tif (repo_init(submodule, gitdir.buf, worktree.buf)) {\n+\t\t/*\n+\t\t * If initilization fails then it may be due to the submodule\n+\t\t * not being populated in the superproject's worktree.  Instead\n+\t\t * we can try to initilize the submodule by finding it's gitdir\n+\t\t * in the superproject's 'modules' directory.  In this case the\n+\t\t * submodule would not have a worktree.\n+\t\t */\n+\t\tstrbuf_reset(&gitdir);\n+\t\tstrbuf_repo_git_path(&gitdir, superproject,\n+\t\t\t\t     \"modules/%s\", sub->name);\n+\n+\t\tif (repo_init(submodule, gitdir.buf, NULL)) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\t}\n+\n+\tsubmodule->submodule_prefix = xstrfmt(\"%s%s/\",\n+\t\t\t\t\t      superproject->submodule_prefix ?\n+\t\t\t\t\t      superproject->submodule_prefix :\n+\t\t\t\t\t      \"\", path);\n+\n+out:\n+\tstrbuf_release(&gitdir);\n+\tstrbuf_release(&worktree);\n+\treturn ret;\n+}\n+\n void repo_clear(struct repository *repo)\n {\n \tfree(repo->gitdir);\n@@ -158,6 +210,8 @@ void repo_clear(struct repository *repo)\n \trepo->index_file = NULL;\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n+\tfree(repo->submodule_prefix);\n+\trepo->submodule_prefix = NULL;\n \n \tif (repo->config) {\n \t\tgit_configset_clear(repo->config);\ndiff --git a/repository.h b/repository.h\nindex c40738ceb..417787f3e 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -43,6 +43,13 @@ struct repository {\n \t */\n \tchar *worktree;\n \n+\t/*\n+\t * Path from the root of the top-level superproject down to this\n+\t * repository.  This is only non-NULL if the repository is initialized\n+\t * as a submodule of another repository.\n+\t */\n+\tchar *submodule_prefix;\n+\n \t/* Subsystems */\n \t/*\n \t * Repository's config which contains key-value pairs from the usual\n@@ -80,6 +87,9 @@ extern struct repository *the_repository;\n extern void repo_set_gitdir(struct repository *repo, const char *path);\n extern void repo_set_worktree(struct repository *repo, const char *path);\n extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);\n+extern int repo_submodule_init(struct repository *submodule,\n+\t\t\t       struct repository *superproject,\n+\t\t\t       const char *path);\n extern void repo_clear(struct repository *repo);\n \n extern int repo_read_index(struct repository *repo);\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322957","messageId":"20170622184348.56497-18-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 17/20] submodule: add repo_read_gitmodules","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:45Z","receivedAt":"2017-06-22T18:44:47Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach the repo object to be able to populate the submodule_cache by\nreading the repository's gitmodules file.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n submodule.c | 15 +++++++++++++++\n submodule.h |  2 ++\n 2 files changed, 17 insertions(+)\n\ndiff --git a/submodule.c b/submodule.c\nindex da0b80549..d0b894772 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n@@ -255,6 +256,20 @@ void gitmodules_config(void)\n \t}\n }\n \n+static int gitmodules_cb(const char *var, const char *value, void *data)\n+{\n+\tstruct repository *repo = data;\n+\treturn submodule_config_option(repo, var, value);\n+}\n+\n+void repo_read_gitmodules(struct repository *repo)\n+{\n+\tchar *gitmodules_path = repo_worktree_path(repo, \".gitmodules\");\n+\n+\tgit_config_from_file(gitmodules_cb, gitmodules_path, repo);\n+\tfree(gitmodules_path);\n+}\n+\n void gitmodules_config_sha1(const unsigned char *commit_sha1)\n {\n \tstruct strbuf rev = STRBUF_INIT;\ndiff --git a/submodule.h b/submodule.h\nindex cbe5c1726..8a3771ec6 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -1,6 +1,7 @@\n #ifndef SUBMODULE_H\n #define SUBMODULE_H\n \n+struct repository;\n struct diff_options;\n struct argv_array;\n struct oid_array;\n@@ -46,6 +47,7 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\n \t\t\t\t\t\t     const char *arg, int unset);\n void load_submodule_cache(void);\n extern void gitmodules_config(void);\n+extern void repo_read_gitmodules(struct repository *repo);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n extern int is_submodule_initialized(const char *path);\n /*\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322958","messageId":"20170622184348.56497-21-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 20/20] ls-files: use repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:48Z","receivedAt":"2017-06-22T18:44:57Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert ls-files to use a repository struct and recurse submodules\ninprocess.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c                     | 192 ++++++++++++++-------------------\n git.c                                  |   2 +-\n t/t3007-ls-files-recurse-submodules.sh |  39 +++++++\n 3 files changed, 118 insertions(+), 115 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex b12d0bb61..b8514a002 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -5,7 +5,9 @@\n  *\n  * Copyright (C) Linus Torvalds, 2005\n  */\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n+#include \"repository.h\"\n #include \"config.h\"\n #include \"quote.h\"\n #include \"dir.h\"\n@@ -32,10 +34,8 @@ static int line_terminator = '\\n';\n static int debug_mode;\n static int show_eol;\n static int recurse_submodules;\n-static struct argv_array submodule_options = ARGV_ARRAY_INIT;\n \n static const char *prefix;\n-static const char *super_prefix;\n static int max_prefix_len;\n static int prefix_len;\n static struct pathspec pathspec;\n@@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,\n \n static void write_name(const char *name)\n {\n-\t/*\n-\t * Prepend the super_prefix to name to construct the full_name to be\n-\t * written.\n-\t */\n-\tstruct strbuf full_name = STRBUF_INIT;\n-\tif (super_prefix) {\n-\t\tstrbuf_addstr(&full_name, super_prefix);\n-\t\tstrbuf_addstr(&full_name, name);\n-\t\tname = full_name.buf;\n-\t}\n-\n \t/*\n \t * With \"--full-name\", prefix_len=0; this caller needs to pass\n \t * an empty string in that case (a NULL is good for \"\").\n \t */\n \twrite_name_quoted_relative(name, prefix_len ? prefix : NULL,\n \t\t\t\t   stdout, line_terminator);\n-\n-\tstrbuf_release(&full_name);\n }\n \n static const char *get_tag(const struct cache_entry *ce, const char *tag)\n@@ -210,83 +197,38 @@ static void show_killed_files(const struct index_state *istate,\n \t}\n }\n \n-/*\n- * Compile an argv_array with all of the options supported by --recurse_submodules\n- */\n-static void compile_submodule_options(const char **argv,\n-\t\t\t\t      const struct dir_struct *dir,\n-\t\t\t\t      int show_tag)\n-{\n-\tif (line_terminator == '\\0')\n-\t\targv_array_push(&submodule_options, \"-z\");\n-\tif (show_tag)\n-\t\targv_array_push(&submodule_options, \"-t\");\n-\tif (show_valid_bit)\n-\t\targv_array_push(&submodule_options, \"-v\");\n-\tif (show_cached)\n-\t\targv_array_push(&submodule_options, \"--cached\");\n-\tif (show_eol)\n-\t\targv_array_push(&submodule_options, \"--eol\");\n-\tif (debug_mode)\n-\t\targv_array_push(&submodule_options, \"--debug\");\n-\n-\t/* Add Pathspecs */\n-\targv_array_push(&submodule_options, \"--\");\n-\tfor (; *argv; argv++)\n-\t\targv_array_push(&submodule_options, *argv);\n-}\n+static void show_files(struct repository *repo, struct dir_struct *dir);\n \n-/**\n- * Recursively call ls-files on a submodule\n- */\n-static void show_gitlink(const struct cache_entry *ce)\n+static void show_submodule(struct repository *superproject,\n+\t\t\t   struct dir_struct *dir, const char *path)\n {\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n-\tint status;\n-\tchar *dir;\n-\n-\tprepare_submodule_repo_env(&cp.env_array);\n-\targv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);\n-\n-\tif (prefix_len)\n-\t\targv_array_pushf(&cp.env_array, \"%s=%s\",\n-\t\t\t\t GIT_TOPLEVEL_PREFIX_ENVIRONMENT,\n-\t\t\t\t prefix);\n-\targv_array_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t\t super_prefix ? super_prefix : \"\",\n-\t\t\t ce->name);\n-\targv_array_push(&cp.args, \"ls-files\");\n-\targv_array_push(&cp.args, \"--recurse-submodules\");\n-\n-\t/* add supported options */\n-\targv_array_pushv(&cp.args, submodule_options.argv);\n-\n-\tcp.git_cmd = 1;\n-\tdir = mkpathdup(\"%s/%s\", get_git_work_tree(), ce->name);\n-\tcp.dir = dir;\n-\tstatus = run_command(&cp);\n-\tfree(dir);\n-\tif (status)\n-\t\texit(status);\n+\tstruct repository submodule;\n+\n+\tif (repo_submodule_init(&submodule, superproject, path))\n+\t\treturn;\n+\n+\tif (repo_read_index(&submodule) < 0)\n+\t\tdie(\"index file corrupt\");\n+\n+\trepo_read_gitmodules(&submodule);\n+\n+\tshow_files(&submodule, dir);\n+\n+\trepo_clear(&submodule);\n }\n \n-static void show_ce_entry(const struct index_state *istate,\n-\t\t\t  const char *tag, const struct cache_entry *ce)\n+static void show_ce(struct repository *repo, struct dir_struct *dir,\n+\t\t    const struct cache_entry *ce, const char *fullname,\n+\t\t    const char *tag)\n {\n-\tstruct strbuf name = STRBUF_INIT;\n-\tint len = max_prefix_len;\n-\tif (super_prefix)\n-\t\tstrbuf_addstr(&name, super_prefix);\n-\tstrbuf_addstr(&name, ce->name);\n-\n-\tif (len > ce_namelen(ce))\n+\tif (max_prefix_len > strlen(fullname))\n \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n \n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t    submodule_path_match(&pathspec, name.buf, ps_matched)) {\n-\t\tshow_gitlink(ce);\n-\t} else if (match_pathspec(&pathspec, name.buf, name.len,\n-\t\t\t\t  len, ps_matched,\n+\t    is_submodule_active(repo, ce->name)) {\n+\t\tshow_submodule(repo, dir, ce->name);\n+\t} else if (match_pathspec(&pathspec, fullname, strlen(fullname),\n+\t\t\t\t  max_prefix_len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n \t\ttag = get_tag(ce, tag);\n@@ -300,12 +242,10 @@ static void show_ce_entry(const struct index_state *istate,\n \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n \t\t\t       ce_stage(ce));\n \t\t}\n-\t\twrite_eolinfo(istate, ce, ce->name);\n-\t\twrite_name(ce->name);\n+\t\twrite_eolinfo(repo->index, ce, fullname);\n+\t\twrite_name(fullname);\n \t\tprint_debug(ce);\n \t}\n-\n-\tstrbuf_release(&name);\n }\n \n static void show_ru_info(const struct index_state *istate)\n@@ -338,59 +278,79 @@ static void show_ru_info(const struct index_state *istate)\n }\n \n static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n-\t\t       const struct cache_entry *ce)\n+\t\t       const char *fullname, const struct cache_entry *ce)\n {\n \tint dtype = ce_to_dtype(ce);\n-\treturn is_excluded(dir, istate, ce->name, &dtype);\n+\treturn is_excluded(dir, istate, fullname, &dtype);\n+}\n+\n+static void construct_fullname(struct strbuf *out, const struct repository *repo,\n+\t\t\t       const struct cache_entry *ce)\n+{\n+\tstrbuf_reset(out);\n+\tif (repo->submodule_prefix)\n+\t\tstrbuf_addstr(out, repo->submodule_prefix);\n+\tstrbuf_addstr(out, ce->name);\n }\n \n-static void show_files(struct index_state *istate, struct dir_struct *dir)\n+static void show_files(struct repository *repo, struct dir_struct *dir)\n {\n \tint i;\n+\tstruct strbuf fullname = STRBUF_INIT;\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others || show_killed) {\n \t\tif (!show_others)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n-\t\tfill_directory(dir, istate, &pathspec);\n+\t\tfill_directory(dir, repo->index, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(istate, dir);\n+\t\t\tshow_other_files(repo->index, dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(istate, dir);\n+\t\t\tshow_killed_files(repo->index, dir);\n \t}\n \tif (show_cached || show_stage) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-\t\t\tshow_ce_entry(istate, ce_stage(ce) ? tag_unmerged :\n-\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);\n+\t\t\tshow_ce(repo, dir, ce, fullname.buf,\n+\t\t\t\tce_stage(ce) ? tag_unmerged :\n+\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree :\n+\t\t\t\t tag_cached));\n \t\t}\n \t}\n \tif (show_deleted || show_modified) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n \t\t\tstruct stat st;\n \t\t\tint err;\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n \t\t\tif (ce_skip_worktree(ce))\n \t\t\t\tcontinue;\n-\t\t\terr = lstat(ce->name, &st);\n+\t\t\terr = lstat(fullname.buf, &st);\n \t\t\tif (show_deleted && err)\n-\t\t\t\tshow_ce_entry(istate, tag_removed, ce);\n-\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n-\t\t\t\tshow_ce_entry(istate, tag_modified, ce);\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed);\n+\t\t\tif (show_modified && ie_modified(repo->index, ce, &st, 0))\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified);\n \t\t}\n \t}\n+\n+\tstrbuf_release(&fullname);\n }\n \n /*\n@@ -615,10 +575,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tprefix = cmd_prefix;\n \tif (prefix)\n \t\tprefix_len = strlen(prefix);\n-\tsuper_prefix = get_super_prefix();\n \tgit_config(git_default_config, NULL);\n \n-\tif (read_cache() < 0)\n+\tif (repo_read_index(the_repository) < 0)\n \t\tdie(\"index file corrupt\");\n \n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n@@ -652,7 +611,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tsetup_work_tree();\n \n \tif (recurse_submodules)\n-\t\tcompile_submodule_options(argv, &dir, show_tag);\n+\t\trepo_read_gitmodules(the_repository);\n \n \tif (recurse_submodules &&\n \t    (show_stage || show_deleted || show_others || show_unmerged ||\n@@ -670,7 +629,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t/*\n \t * Find common prefix for all pathspec's\n \t * This is used as a performance optimization which unfortunately cannot\n-\t * be done when recursing into submodules\n+\t * be done when recursing into submodules because when a pathspec is\n+\t * given which spans repository boundaries you can't simply remove the\n+\t * submodule entry because the pathspec may match something inside the\n+\t * submodule.\n \t */\n \tif (recurse_submodules)\n \t\tmax_prefix = NULL;\n@@ -678,7 +640,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_index(&the_index, max_prefix, max_prefix_len);\n+\tprune_index(the_repository->index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n@@ -699,11 +661,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n-\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n+\t\toverlay_tree_on_index(the_repository->index, with_tree, max_prefix);\n \t}\n-\tshow_files(&the_index, &dir);\n+\n+\tshow_files(the_repository, &dir);\n+\n \tif (show_resolve_undo)\n-\t\tshow_ru_info(&the_index);\n+\t\tshow_ru_info(the_repository->index);\n \n \tif (ps_matched) {\n \t\tint bad;\ndiff --git a/git.c b/git.c\nindex 5be27b07e..489aab4d8 100644\n--- a/git.c\n+++ b/git.c\n@@ -400,7 +400,7 @@ static struct cmd_struct commands[] = {\n \t{ \"init-db\", cmd_init_db },\n \t{ \"interpret-trailers\", cmd_interpret_trailers, RUN_SETUP_GENTLY },\n \t{ \"log\", cmd_log, RUN_SETUP },\n-\t{ \"ls-files\", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"ls-files\", cmd_ls_files, RUN_SETUP },\n \t{ \"ls-remote\", cmd_ls_remote, RUN_SETUP_GENTLY },\n \t{ \"ls-tree\", cmd_ls_tree, RUN_SETUP },\n \t{ \"mailinfo\", cmd_mailinfo, RUN_SETUP_GENTLY },\ndiff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh\nindex ebb956fd1..318b5bce7 100755\n--- a/t/t3007-ls-files-recurse-submodules.sh\n+++ b/t/t3007-ls-files-recurse-submodules.sh\n@@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'inactive submodule' '\n+\ttest_when_finished \"git config --bool submodule.submodule.active true\" &&\n+\ttest_when_finished \"git -C submodule config --bool submodule.subsub.active true\" &&\n+\tgit config --bool submodule.submodule.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tgit config --bool submodule.submodule.active \"true\" &&\n+\tgit -C submodule config --bool submodule.subsub.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule/.gitmodules\n+\tsubmodule/c\n+\tsubmodule/f.TXT\n+\tsubmodule/g.txt\n+\tsubmodule/subsub\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success '--recurse-submodules and pathspecs' '\n \tcat >expect <<-\\EOF &&\n \th.txt\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322959","messageId":"20170622184348.56497-14-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 13/20] path: add repo_worktree_path and strbuf_repo_worktree_path","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:41Z","receivedAt":"2017-06-22T18:45:07Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce 'repo_worktree_path' and 'strbuf_repo_worktree_path' which\ntake a repository struct and constructs a path relative to the\nrepository's worktree.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 41 +++++++++++++++++++++++++++++++++++++++++\n path.h |  8 ++++++++\n 2 files changed, 49 insertions(+)\n\ndiff --git a/path.c b/path.c\nindex ffc0f10fd..e485f9f93 100644\n--- a/path.c\n+++ b/path.c\n@@ -506,6 +506,47 @@ const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)\n \treturn pathname->buf;\n }\n \n+static void do_worktree_path(const struct repository *repo,\n+\t\t\t     struct strbuf *buf,\n+\t\t\t     const char *fmt, va_list args)\n+{\n+\tstrbuf_addstr(buf, repo->worktree);\n+\tif(buf->len && !is_dir_sep(buf->buf[buf->len - 1]))\n+\t\tstrbuf_addch(buf, '/');\n+\n+\tstrbuf_vaddf(buf, fmt, args);\n+\tstrbuf_cleanup_path(buf);\n+}\n+\n+char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)\n+{\n+\tstruct strbuf path = STRBUF_INIT;\n+\tva_list args;\n+\n+\tif (!repo->worktree)\n+\t\treturn NULL;\n+\n+\tva_start(args, fmt);\n+\tdo_worktree_path(repo, &path, fmt, args);\n+\tva_end(args);\n+\n+\treturn strbuf_detach(&path, NULL);\n+}\n+\n+void strbuf_repo_worktree_path(struct strbuf *sb,\n+\t\t\t       const struct repository *repo,\n+\t\t\t       const char *fmt, ...)\n+{\n+\tva_list args;\n+\n+\tif (!repo->worktree)\n+\t\treturn;\n+\n+\tva_start(args, fmt);\n+\tdo_worktree_path(repo, sb, fmt, args);\n+\tva_end(args);\n+}\n+\n /* Returns 0 on success, negative on failure. */\n static int do_submodule_path(struct strbuf *buf, const char *path,\n \t\t\t     const char *fmt, va_list args)\ndiff --git a/path.h b/path.h\nindex c779c4aa2..9541620c7 100644\n--- a/path.h\n+++ b/path.h\n@@ -43,6 +43,14 @@ extern void strbuf_repo_git_path(struct strbuf *sb,\n \t\t\t\t const char *fmt, ...)\n \t__attribute__((format (printf, 3, 4)));\n \n+extern char *repo_worktree_path(const struct repository *repo,\n+\t\t\t\tconst char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern void strbuf_repo_worktree_path(struct strbuf *sb,\n+\t\t\t\t      const struct repository *repo,\n+\t\t\t\t      const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n+\n extern void report_linked_checkout_garbage(void);\n \n /*\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322960","messageId":"20170622184348.56497-13-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 12/20] path: add repo_git_path and strbuf_repo_git_path","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:40Z","receivedAt":"2017-06-22T18:45:09Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce 'repo_git_path' and 'strbuf_repo_git_path' which take a\nrepository struct and constructs a path into the repository's git\ndirectory.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n path.c | 21 +++++++++++++++++++++\n path.h |  8 ++++++++\n 2 files changed, 29 insertions(+)\n\ndiff --git a/path.c b/path.c\nindex 2bdd0044f..ffc0f10fd 100644\n--- a/path.c\n+++ b/path.c\n@@ -416,6 +416,27 @@ static void do_git_path(const struct repository *repo,\n \tstrbuf_cleanup_path(buf);\n }\n \n+char *repo_git_path(const struct repository *repo,\n+\t\t    const char *fmt, ...)\n+{\n+\tstruct strbuf path = STRBUF_INIT;\n+\tva_list args;\n+\tva_start(args, fmt);\n+\tdo_git_path(repo, NULL, &path, fmt, args);\n+\tva_end(args);\n+\treturn strbuf_detach(&path, NULL);\n+}\n+\n+void strbuf_repo_git_path(struct strbuf *sb,\n+\t\t\t  const struct repository *repo,\n+\t\t\t  const char *fmt, ...)\n+{\n+\tva_list args;\n+\tva_start(args, fmt);\n+\tdo_git_path(repo, NULL, sb, fmt, args);\n+\tva_end(args);\n+}\n+\n char *git_path_buf(struct strbuf *buf, const char *fmt, ...)\n {\n \tva_list args;\ndiff --git a/path.h b/path.h\nindex 568d63be5..c779c4aa2 100644\n--- a/path.h\n+++ b/path.h\n@@ -35,6 +35,14 @@ extern char *mkpathdup(const char *fmt, ...)\n extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)\n \t__attribute__((format (printf, 2, 3)));\n \n+extern char *repo_git_path(const struct repository *repo,\n+\t\t\t   const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+extern void strbuf_repo_git_path(struct strbuf *sb,\n+\t\t\t\t const struct repository *repo,\n+\t\t\t\t const char *fmt, ...)\n+\t__attribute__((format (printf, 3, 4)));\n+\n extern void report_linked_checkout_garbage(void);\n \n /*\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322961","messageId":"20170622184348.56497-16-bmwill@google.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"[PATCH v4 15/20] repository: add index_state to struct repo","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T18:43:43Z","receivedAt":"2017-06-22T18:45:15Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n repository.c | 16 ++++++++++++++++\n repository.h |  9 +++++++++\n 2 files changed, 25 insertions(+)\n\ndiff --git a/repository.c b/repository.c\nindex 686a964ad..6f6f4d91e 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -163,4 +163,20 @@ void repo_clear(struct repository *repo)\n \t\tfree(repo->config);\n \t\trepo->config = NULL;\n \t}\n+\n+\tif (repo->index) {\n+\t\tdiscard_index(repo->index);\n+\t\tfree(repo->index);\n+\t\trepo->index = NULL;\n+\t}\n+}\n+\n+int repo_read_index(struct repository *repo)\n+{\n+\tif (!repo->index)\n+\t\trepo->index = xcalloc(1, sizeof(*repo->index));\n+\telse\n+\t\tdiscard_index(repo->index);\n+\n+\treturn read_index_from(repo->index, repo->index_file);\n }\ndiff --git a/repository.h b/repository.h\nindex 8ae5e8653..3a41568aa 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -2,6 +2,7 @@\n #define REPOSITORY_H\n \n struct config_set;\n+struct index_state;\n \n struct repository {\n \t/* Environment */\n@@ -49,6 +50,12 @@ struct repository {\n \t */\n \tstruct config_set *config;\n \n+\t/*\n+\t * Repository's in-memory index.\n+\t * 'repo_read_index()' can be used to populate 'index'.\n+\t */\n+\tstruct index_state *index;\n+\n \t/* Configurations */\n \t/*\n \t * Bit used during initialization to indicate if repository state (like\n@@ -71,4 +78,6 @@ extern void repo_set_worktree(struct repository *repo, const char *path);\n extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);\n extern void repo_clear(struct repository *repo);\n \n+extern int repo_read_index(struct repository *repo);\n+\n #endif /* REPOSITORY_H */\n-- \n2.13.1.704.gde00cce3c-goog\n\n"},{"id":"322974","messageId":"CAGZ79kbrnCx2xxZHyZN+pwgUDY+sEuXAaYKDjKYLcbemsfM5Tg@mail.gmail.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"Re: [PATCH v4 00/20] repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-22T19:42:36Z","receivedAt":"2017-06-22T19:42:41Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, Jun 22, 2017 at 11:43 AM, Brandon Williams <bmwill@google.com> wrote:\n> As before you can find this series at:\n> https://github.com/bmwill/git/tree/repository-object\n>\n> Changes in v4:\n>\n> * Patch 11 is slightly different and turns off all path relocation when a\n>   worktree is provided instead of just for the index file (Thanks for the help\n>   Jonathan Nieder).\n> * 'repo_init()' has a tighter API and now requires that the provided gitdir is\n>   a path to the gitdir instead of either a path to the gitdir or path to the\n>   worktree (which has a .git file or directory) (Thanks Jonathan Tan).\n> * Minor comment and commit message chagnes\n>\n> Note: Like v3 this series is dependent on on 'bw/config-h' and\n>       'bw/ls-files-sans-the-index'\n\nI read the whole series and I consider it\nReviewed-by: Stefan Beller <sbeller@google.com>\n\nThanks,\nStefan\n"},{"id":"322979","messageId":"xmqqshirixrt.fsf@gitster.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170622184348.56497-16-bmwill@google.com","subject":"Re: [PATCH v4 15/20] repository: add index_state to struct repo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-22T20:16:06Z","receivedAt":"2017-06-22T20:16:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brandon Williams <bmwill@google.com> writes:\n\n>  struct repository {\n>  \t/* Environment */\n> @@ -49,6 +50,12 @@ struct repository {\n>  \t */\n>  \tstruct config_set *config;\n>  \n> +\t/*\n> +\t * Repository's in-memory index.\n> +\t * 'repo_read_index()' can be used to populate 'index'.\n> +\t */\n> +\tstruct index_state *index;\n> +\n>  \t/* Configurations */\n>  \t/*\n>  \t * Bit used during initialization to indicate if repository state (like\n> @@ -71,4 +78,6 @@ extern void repo_set_worktree(struct repository *repo, const char *path);\n>  extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);\n>  extern void repo_clear(struct repository *repo);\n>  \n> +extern int repo_read_index(struct repository *repo);\n> +\n>  #endif /* REPOSITORY_H */\n\nWhile you are working on a simple read-only operation like\n\"ls-files\", you can get away with just a singleton (the equivalent\nto \"the_index\" in the repository object world) in-core index\ninstance, and having a way to tell the system to read things into\nthe default thing without having to name what that default thing is\nis a very useful thing to have.  It is a good thing that this only\nneeds \"struct repository *\" and no \"struct index_state *\" parameter.\n\nBut you will need a way to read, update, write it out as a tree,\netc. to a non-default in-core index, once you start doing more\ncomplex things.  The function signature of the lowest level\nprimitive helper for them will be:\n\n    extern int (*)(struct repository *, struct index_state *);\n\nAnd you would want to reserve \"index\" suffix for such a function,\nfollowing the \"if you use the default in-core thing, you do not have\nto pass it as a parameter---just call _cache() convenience macro;\nbut you can explicitly pass it to the underlying _index() function\"\nconvention we established long time ago.\n\nSo I'd suggest renaming the above one that uses the default in-core\nindex instance to\n\n\textern int repo_read_cache(struct repository *);\n\nor you will regret later.\n\n"},{"id":"322986","messageId":"20170622203511.GB124061@google.com","threadId":"46082","inReplyTo":"xmqqshirixrt.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 15/20] repository: add index_state to struct repo","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-06-22T20:35:11Z","receivedAt":"2017-06-22T20:35:19Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/22, Junio C Hamano wrote:\n> Brandon Williams <bmwill@google.com> writes:\n> \n> >  struct repository {\n> >  \t/* Environment */\n> > @@ -49,6 +50,12 @@ struct repository {\n> >  \t */\n> >  \tstruct config_set *config;\n> >  \n> > +\t/*\n> > +\t * Repository's in-memory index.\n> > +\t * 'repo_read_index()' can be used to populate 'index'.\n> > +\t */\n> > +\tstruct index_state *index;\n> > +\n> >  \t/* Configurations */\n> >  \t/*\n> >  \t * Bit used during initialization to indicate if repository state (like\n> > @@ -71,4 +78,6 @@ extern void repo_set_worktree(struct repository *repo, const char *path);\n> >  extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);\n> >  extern void repo_clear(struct repository *repo);\n> >  \n> > +extern int repo_read_index(struct repository *repo);\n> > +\n> >  #endif /* REPOSITORY_H */\n> \n> While you are working on a simple read-only operation like\n> \"ls-files\", you can get away with just a singleton (the equivalent\n> to \"the_index\" in the repository object world) in-core index\n> instance, and having a way to tell the system to read things into\n> the default thing without having to name what that default thing is\n> is a very useful thing to have.  It is a good thing that this only\n> needs \"struct repository *\" and no \"struct index_state *\" parameter.\n> \n> But you will need a way to read, update, write it out as a tree,\n> etc. to a non-default in-core index, once you start doing more\n> complex things.  The function signature of the lowest level\n> primitive helper for them will be:\n> \n>     extern int (*)(struct repository *, struct index_state *);\n> \n> And you would want to reserve \"index\" suffix for such a function,\n> following the \"if you use the default in-core thing, you do not have\n> to pass it as a parameter---just call _cache() convenience macro;\n> but you can explicitly pass it to the underlying _index() function\"\n> convention we established long time ago.\n> \n> So I'd suggest renaming the above one that uses the default in-core\n> index instance to\n> \n> \textern int repo_read_cache(struct repository *);\n> \n> or you will regret later.\n> \n\nThat makes sense.  While at it, would it make sense to ensure that the\n'struct index_state *' which is stored in 'the_repository.index' be\n'&the_index'?\n\n-- \nBrandon Williams\n"},{"id":"323007","messageId":"xmqqziczhdxb.fsf@gitster.mtv.corp.google.com","threadId":"46082","inReplyTo":"20170622203511.GB124061@google.com","subject":"Re: [PATCH v4 15/20] repository: add index_state to struct repo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-22T22:10:08Z","receivedAt":"2017-06-22T22:10:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brandon Williams <bmwill@google.com> writes:\n\n> That makes sense.  While at it, would it make sense to ensure that the\n> 'struct index_state *' which is stored in 'the_repository.index' be\n> '&the_index'?\n\nI was imagining (read: speculating one possible future, without\nthinking things through to judge if it makes sense at all) that\nconceptually most of the current API that works on things in the\ncurrent repository to be implicitly working on the_repository\nsingleton instance in the \"repository object\" world.\n\nWhen that happens, the_index can become a CPP macro that translates\nto \"the_repository.index\", I would think.\n\n"},{"id":"323112","messageId":"dadf3fe7-180b-df3a-f5f5-932905f08335@jeffhostetler.com","threadId":"46082","inReplyTo":"20170622184348.56497-1-bmwill@google.com","subject":"Re: [PATCH v4 00/20] repository object","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-06-23T16:44:53Z","receivedAt":"2017-06-23T16:45:02Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"\n\nOn 6/22/2017 2:43 PM, Brandon Williams wrote:\n> As before you can find this series at:\n> https://github.com/bmwill/git/tree/repository-object\n> \n> Changes in v4:\n> \n> * Patch 11 is slightly different and turns off all path relocation when a\n>    worktree is provided instead of just for the index file (Thanks for the help\n>    Jonathan Nieder).\n> * 'repo_init()' has a tighter API and now requires that the provided gitdir is\n>    a path to the gitdir instead of either a path to the gitdir or path to the\n>    worktree (which has a .git file or directory) (Thanks Jonathan Tan).\n> * Minor comment and commit message chagnes\n> \n> Note: Like v3 this series is dependent on on 'bw/config-h' and\n>        'bw/ls-files-sans-the-index'\n> \n> Brandon Williams (20):\n\nI read thru the v1 and v4 versions.  Very nice.\nAnd thanks for splitting the earlier parts out\ninto independent patches.\n\nI didn't have any complaints, but did want to ACK\nthat I had looked at it.\n\nJeff\n\n"},{"id":"323117","messageId":"xmqq60fmfvtq.fsf@gitster.mtv.corp.google.com","threadId":"46082","inReplyTo":"dadf3fe7-180b-df3a-f5f5-932905f08335@jeffhostetler.com","subject":"Re: [PATCH v4 00/20] repository object","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-23T17:38:41Z","receivedAt":"2017-06-23T17:38:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff Hostetler <git@jeffhostetler.com> writes:\n\n> On 6/22/2017 2:43 PM, Brandon Williams wrote:\n>> As before you can find this series at:\n>> https://github.com/bmwill/git/tree/repository-object\n>>\n>> Changes in v4:\n>>\n>> * Patch 11 is slightly different and turns off all path relocation when a\n>>    worktree is provided instead of just for the index file (Thanks for the help\n>>    Jonathan Nieder).\n>> * 'repo_init()' has a tighter API and now requires that the provided gitdir is\n>>    a path to the gitdir instead of either a path to the gitdir or path to the\n>>    worktree (which has a .git file or directory) (Thanks Jonathan Tan).\n>> * Minor comment and commit message chagnes\n>>\n>> Note: Like v3 this series is dependent on on 'bw/config-h' and\n>>        'bw/ls-files-sans-the-index'\n>>\n>> Brandon Williams (20):\n>\n> I read thru the v1 and v4 versions.  Very nice.\n> And thanks for splitting the earlier parts out\n> into independent patches.\n>\n> I didn't have any complaints, but did want to ACK\n> that I had looked at it.\n\nThanks.\n"}]}