From 8fb572af5f4e3bef2415ac2dba8d76d37235b489 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Wed, 25 Apr 2018 14:37:54 +0000 Subject: [PATCH 001/711] ref-filter: fix outdated comment on in_commit_list The in_commit_list() method does not check the parents of the candidate for containment in the list. Fix the comment that incorrectly states that it does. Reported-by: Jakub Narebski Signed-off-by: Derrick Stolee Signed-off-by: Junio C Hamano --- ref-filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ref-filter.c b/ref-filter.c index cffd8bf3ce72ab..aff24d93beef5a 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1582,7 +1582,7 @@ static int in_commit_list(const struct commit_list *want, struct commit *c) } /* - * Test whether the candidate or one of its parents is contained in the list. + * Test whether the candidate is contained in the list. * Do not recurse to find out, though, but return -1 if inconclusive. */ static enum contains_result contains_test(struct commit *candidate, From 99bf115c879af7e38ef0ca9596fc9db1d6598d5f Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:24 -0700 Subject: [PATCH 002/711] repository: introduce parsed objects field Convert the existing global cache for parsed objects (obj_hash) into repository-specific parsed object caches. Existing code that uses obj_hash are modified to use the parsed object cache of the_repository; future patches will use the parsed object caches of other repositories. Another future use case for a pool of objects is ease of memory management in revision walking: If we can free the rev-list related memory early in pack-objects (e.g. part of repack operation) then it could lower memory pressure significantly when running on large repos. While this has been discussed on the mailing list lately, this series doesn't implement this. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- object.c | 63 +++++++++++++++++++++++++++++++++------------------- object.h | 8 +++++++ repository.c | 7 ++++++ repository.h | 9 ++++++++ 4 files changed, 64 insertions(+), 23 deletions(-) diff --git a/object.c b/object.c index 5044d08e96c287..f7c624a7ba6628 100644 --- a/object.c +++ b/object.c @@ -8,17 +8,14 @@ #include "object-store.h" #include "packfile.h" -static struct object **obj_hash; -static int nr_objs, obj_hash_size; - unsigned int get_max_object_index(void) { - return obj_hash_size; + return the_repository->parsed_objects->obj_hash_size; } struct object *get_indexed_object(unsigned int idx) { - return obj_hash[idx]; + return the_repository->parsed_objects->obj_hash[idx]; } static const char *object_type_strings[] = { @@ -90,15 +87,16 @@ struct object *lookup_object(const unsigned char *sha1) unsigned int i, first; struct object *obj; - if (!obj_hash) + if (!the_repository->parsed_objects->obj_hash) return NULL; - first = i = hash_obj(sha1, obj_hash_size); - while ((obj = obj_hash[i]) != NULL) { + first = i = hash_obj(sha1, + the_repository->parsed_objects->obj_hash_size); + while ((obj = the_repository->parsed_objects->obj_hash[i]) != NULL) { if (!hashcmp(sha1, obj->oid.hash)) break; i++; - if (i == obj_hash_size) + if (i == the_repository->parsed_objects->obj_hash_size) i = 0; } if (obj && i != first) { @@ -107,7 +105,8 @@ struct object *lookup_object(const unsigned char *sha1) * that we do not need to walk the hash table the next * time we look for it. */ - SWAP(obj_hash[i], obj_hash[first]); + SWAP(the_repository->parsed_objects->obj_hash[i], + the_repository->parsed_objects->obj_hash[first]); } return obj; } @@ -124,19 +123,19 @@ static void grow_object_hash(void) * Note that this size must always be power-of-2 to match hash_obj * above. */ - int new_hash_size = obj_hash_size < 32 ? 32 : 2 * obj_hash_size; + int new_hash_size = the_repository->parsed_objects->obj_hash_size < 32 ? 32 : 2 * the_repository->parsed_objects->obj_hash_size; struct object **new_hash; new_hash = xcalloc(new_hash_size, sizeof(struct object *)); - for (i = 0; i < obj_hash_size; i++) { - struct object *obj = obj_hash[i]; + for (i = 0; i < the_repository->parsed_objects->obj_hash_size; i++) { + struct object *obj = the_repository->parsed_objects->obj_hash[i]; if (!obj) continue; insert_obj_hash(obj, new_hash, new_hash_size); } - free(obj_hash); - obj_hash = new_hash; - obj_hash_size = new_hash_size; + free(the_repository->parsed_objects->obj_hash); + the_repository->parsed_objects->obj_hash = new_hash; + the_repository->parsed_objects->obj_hash_size = new_hash_size; } void *create_object(const unsigned char *sha1, void *o) @@ -147,11 +146,12 @@ void *create_object(const unsigned char *sha1, void *o) obj->flags = 0; hashcpy(obj->oid.hash, sha1); - if (obj_hash_size - 1 <= nr_objs * 2) + if (the_repository->parsed_objects->obj_hash_size - 1 <= the_repository->parsed_objects->nr_objs * 2) grow_object_hash(); - insert_obj_hash(obj, obj_hash, obj_hash_size); - nr_objs++; + insert_obj_hash(obj, the_repository->parsed_objects->obj_hash, + the_repository->parsed_objects->obj_hash_size); + the_repository->parsed_objects->nr_objs++; return obj; } @@ -431,8 +431,8 @@ void clear_object_flags(unsigned flags) { int i; - for (i=0; i < obj_hash_size; i++) { - struct object *obj = obj_hash[i]; + for (i=0; i < the_repository->parsed_objects->obj_hash_size; i++) { + struct object *obj = the_repository->parsed_objects->obj_hash[i]; if (obj) obj->flags &= ~flags; } @@ -442,13 +442,20 @@ void clear_commit_marks_all(unsigned int flags) { int i; - for (i = 0; i < obj_hash_size; i++) { - struct object *obj = obj_hash[i]; + for (i = 0; i < the_repository->parsed_objects->obj_hash_size; i++) { + struct object *obj = the_repository->parsed_objects->obj_hash[i]; if (obj && obj->type == OBJ_COMMIT) obj->flags &= ~flags; } } +struct parsed_object_pool *parsed_object_pool_new(void) +{ + struct parsed_object_pool *o = xmalloc(sizeof(*o)); + memset(o, 0, sizeof(*o)); + return o; +} + struct raw_object_store *raw_object_store_new(void) { struct raw_object_store *o = xmalloc(sizeof(*o)); @@ -488,3 +495,13 @@ void raw_object_store_clear(struct raw_object_store *o) close_all_packs(o); o->packed_git = NULL; } + +void parsed_object_pool_clear(struct parsed_object_pool *o) +{ + /* + * TOOD free objects in o->obj_hash. + * + * As objects are allocated in slabs (see alloc.c), we do + * not need to free each object, but each slab instead. + */ +} diff --git a/object.h b/object.h index f13f85b2a94e3a..cecda7da370e28 100644 --- a/object.h +++ b/object.h @@ -1,6 +1,14 @@ #ifndef OBJECT_H #define OBJECT_H +struct parsed_object_pool { + struct object **obj_hash; + int nr_objs, obj_hash_size; +}; + +struct parsed_object_pool *parsed_object_pool_new(void); +void parsed_object_pool_clear(struct parsed_object_pool *o); + struct object_list { struct object *item; struct object_list *next; diff --git a/repository.c b/repository.c index a4848c1bd05e94..c23404677eb0bc 100644 --- a/repository.c +++ b/repository.c @@ -2,6 +2,7 @@ #include "repository.h" #include "object-store.h" #include "config.h" +#include "object.h" #include "submodule-config.h" /* The main repository */ @@ -14,6 +15,8 @@ void initialize_the_repository(void) the_repo.index = &the_index; the_repo.objects = raw_object_store_new(); + the_repo.parsed_objects = parsed_object_pool_new(); + repo_set_hash_algo(&the_repo, GIT_HASH_SHA1); } @@ -143,6 +146,7 @@ static int repo_init(struct repository *repo, memset(repo, 0, sizeof(*repo)); repo->objects = raw_object_store_new(); + repo->parsed_objects = parsed_object_pool_new(); if (repo_init_gitdir(repo, gitdir)) goto error; @@ -226,6 +230,9 @@ void repo_clear(struct repository *repo) raw_object_store_clear(repo->objects); FREE_AND_NULL(repo->objects); + parsed_object_pool_clear(repo->parsed_objects); + FREE_AND_NULL(repo->parsed_objects); + if (repo->config) { git_configset_clear(repo->config); FREE_AND_NULL(repo->config); diff --git a/repository.h b/repository.h index e6e00f541bdc7f..6d199819905f2a 100644 --- a/repository.h +++ b/repository.h @@ -26,6 +26,15 @@ struct repository { */ struct raw_object_store *objects; + /* + * All objects in this repository that have been parsed. This structure + * owns all objects it references, so users of "struct object *" + * generally do not need to free them; instead, when a repository is no + * longer used, call parsed_object_pool_clear() on this structure, which + * is called by the repositories repo_clear on its desconstruction. + */ + struct parsed_object_pool *parsed_objects; + /* The store in which the refs are held. */ struct ref_store *refs; From 68f95d382b51b134b138c91f94adb8d9ef2f557a Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:25 -0700 Subject: [PATCH 003/711] object: add repository argument to create_object Add a repository argument to allow the callers of create_object to be more specific about which repository to act on. This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Signed-off-by: Jonathan Nieder Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- blob.c | 4 +++- commit.c | 3 ++- object.c | 5 +++-- object.h | 3 ++- tag.c | 3 ++- tree.c | 3 ++- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/blob.c b/blob.c index fa2ab4f7a74e50..85c2143f29956a 100644 --- a/blob.c +++ b/blob.c @@ -1,5 +1,6 @@ #include "cache.h" #include "blob.h" +#include "repository.h" const char *blob_type = "blob"; @@ -7,7 +8,8 @@ struct blob *lookup_blob(const struct object_id *oid) { struct object *obj = lookup_object(oid->hash); if (!obj) - return create_object(oid->hash, alloc_blob_node()); + return create_object(the_repository, oid->hash, + alloc_blob_node()); return object_as_type(obj, OBJ_BLOB, 0); } diff --git a/commit.c b/commit.c index ca474a7c112855..9106acf0aadca1 100644 --- a/commit.c +++ b/commit.c @@ -50,7 +50,8 @@ struct commit *lookup_commit(const struct object_id *oid) { struct object *obj = lookup_object(oid->hash); if (!obj) - return create_object(oid->hash, alloc_commit_node()); + return create_object(the_repository, oid->hash, + alloc_commit_node()); return object_as_type(obj, OBJ_COMMIT, 0); } diff --git a/object.c b/object.c index f7c624a7ba6628..2de029275bc0b4 100644 --- a/object.c +++ b/object.c @@ -138,7 +138,7 @@ static void grow_object_hash(void) the_repository->parsed_objects->obj_hash_size = new_hash_size; } -void *create_object(const unsigned char *sha1, void *o) +void *create_object_the_repository(const unsigned char *sha1, void *o) { struct object *obj = o; @@ -178,7 +178,8 @@ struct object *lookup_unknown_object(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) - obj = create_object(sha1, alloc_object_node()); + obj = create_object(the_repository, sha1, + alloc_object_node()); return obj; } diff --git a/object.h b/object.h index cecda7da370e28..2cb0b2410839a2 100644 --- a/object.h +++ b/object.h @@ -93,7 +93,8 @@ extern struct object *get_indexed_object(unsigned int); */ struct object *lookup_object(const unsigned char *sha1); -extern void *create_object(const unsigned char *sha1, void *obj); +#define create_object(r, s, o) create_object_##r(s, o) +extern void *create_object_the_repository(const unsigned char *sha1, void *obj); void *object_as_type(struct object *obj, enum object_type type, int quiet); diff --git a/tag.c b/tag.c index 3d37c1bd251c5f..7150b759d66ec4 100644 --- a/tag.c +++ b/tag.c @@ -93,7 +93,8 @@ struct tag *lookup_tag(const struct object_id *oid) { struct object *obj = lookup_object(oid->hash); if (!obj) - return create_object(oid->hash, alloc_tag_node()); + return create_object(the_repository, oid->hash, + alloc_tag_node()); return object_as_type(obj, OBJ_TAG, 0); } diff --git a/tree.c b/tree.c index 1c68ea586bd30d..63730e3fb46e47 100644 --- a/tree.c +++ b/tree.c @@ -196,7 +196,8 @@ struct tree *lookup_tree(const struct object_id *oid) { struct object *obj = lookup_object(oid->hash); if (!obj) - return create_object(oid->hash, alloc_tree_node()); + return create_object(the_repository, oid->hash, + alloc_tree_node()); return object_as_type(obj, OBJ_TREE, 0); } From c077a4526ba456ada28d16db9c945afd9a4a57de Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Tue, 8 May 2018 12:37:26 -0700 Subject: [PATCH 004/711] object: add repository argument to grow_object_hash Add a repository argument to allow the caller of grow_object_hash to be more specific about which repository to handle. This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Signed-off-by: Jonathan Nieder Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- object.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/object.c b/object.c index 2de029275bc0b4..91edc30770c60c 100644 --- a/object.c +++ b/object.c @@ -116,7 +116,8 @@ struct object *lookup_object(const unsigned char *sha1) * power of 2 (but at least 32). Copy the existing values to the new * hash map. */ -static void grow_object_hash(void) +#define grow_object_hash(r) grow_object_hash_##r() +static void grow_object_hash_the_repository(void) { int i; /* @@ -147,7 +148,7 @@ void *create_object_the_repository(const unsigned char *sha1, void *o) hashcpy(obj->oid.hash, sha1); if (the_repository->parsed_objects->obj_hash_size - 1 <= the_repository->parsed_objects->nr_objs * 2) - grow_object_hash(); + grow_object_hash(the_repository); insert_obj_hash(obj, the_repository->parsed_objects->obj_hash, the_repository->parsed_objects->obj_hash_size); From f0de1d62ae5982630cfb2c713ddcda853b9ee0cf Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:27 -0700 Subject: [PATCH 005/711] alloc: add repository argument to alloc_blob_node This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Use a macro to catch callers passing a repository other than the_repository at compile time. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- alloc.c | 2 +- blob.c | 2 +- cache.h | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/alloc.c b/alloc.c index 12afadfacdd609..6c5c376a25a7f1 100644 --- a/alloc.c +++ b/alloc.c @@ -49,7 +49,7 @@ static inline void *alloc_node(struct alloc_state *s, size_t node_size) } static struct alloc_state blob_state; -void *alloc_blob_node(void) +void *alloc_blob_node_the_repository(void) { struct blob *b = alloc_node(&blob_state, sizeof(struct blob)); b->object.type = OBJ_BLOB; diff --git a/blob.c b/blob.c index 85c2143f29956a..9e64f301895e41 100644 --- a/blob.c +++ b/blob.c @@ -9,7 +9,7 @@ struct blob *lookup_blob(const struct object_id *oid) struct object *obj = lookup_object(oid->hash); if (!obj) return create_object(the_repository, oid->hash, - alloc_blob_node()); + alloc_blob_node(the_repository)); return object_as_type(obj, OBJ_BLOB, 0); } diff --git a/cache.h b/cache.h index 3a4d80e92bf739..2258e61127531b 100644 --- a/cache.h +++ b/cache.h @@ -1764,7 +1764,8 @@ int decode_85(char *dst, const char *line, int linelen); void encode_85(char *buf, const unsigned char *data, int bytes); /* alloc.c */ -extern void *alloc_blob_node(void); +#define alloc_blob_node(r) alloc_blob_node_##r() +extern void *alloc_blob_node_the_repository(void); extern void *alloc_tree_node(void); extern void *alloc_commit_node(void); extern void *alloc_tag_node(void); From cf7203bdc65f11de89d27f52115cb98052c52ce8 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:28 -0700 Subject: [PATCH 006/711] alloc: add repository argument to alloc_tree_node This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Use a macro to catch callers passing a repository other than the_repository at compile time. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- alloc.c | 2 +- cache.h | 3 ++- tree.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/alloc.c b/alloc.c index 6c5c376a25a7f1..2c8d1430758b97 100644 --- a/alloc.c +++ b/alloc.c @@ -57,7 +57,7 @@ void *alloc_blob_node_the_repository(void) } static struct alloc_state tree_state; -void *alloc_tree_node(void) +void *alloc_tree_node_the_repository(void) { struct tree *t = alloc_node(&tree_state, sizeof(struct tree)); t->object.type = OBJ_TREE; diff --git a/cache.h b/cache.h index 2258e61127531b..1717d07a2c5d18 100644 --- a/cache.h +++ b/cache.h @@ -1766,7 +1766,8 @@ void encode_85(char *buf, const unsigned char *data, int bytes); /* alloc.c */ #define alloc_blob_node(r) alloc_blob_node_##r() extern void *alloc_blob_node_the_repository(void); -extern void *alloc_tree_node(void); +#define alloc_tree_node(r) alloc_tree_node_##r() +extern void *alloc_tree_node_the_repository(void); extern void *alloc_commit_node(void); extern void *alloc_tag_node(void); extern void *alloc_object_node(void); diff --git a/tree.c b/tree.c index 63730e3fb46e47..58cf19b4fa8e77 100644 --- a/tree.c +++ b/tree.c @@ -197,7 +197,7 @@ struct tree *lookup_tree(const struct object_id *oid) struct object *obj = lookup_object(oid->hash); if (!obj) return create_object(the_repository, oid->hash, - alloc_tree_node()); + alloc_tree_node(the_repository)); return object_as_type(obj, OBJ_TREE, 0); } From 8ba0e5ec57e4a7da18f735416e3028a9a8b8b1ad Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:29 -0700 Subject: [PATCH 007/711] alloc: add repository argument to alloc_commit_node This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Use a macro to catch callers passing a repository other than the_repository at compile time. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- alloc.c | 2 +- blame.c | 2 +- cache.h | 3 ++- commit.c | 2 +- merge-recursive.c | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/alloc.c b/alloc.c index 2c8d1430758b97..9e2b897ec1dea2 100644 --- a/alloc.c +++ b/alloc.c @@ -88,7 +88,7 @@ unsigned int alloc_commit_index(void) return count++; } -void *alloc_commit_node(void) +void *alloc_commit_node_the_repository(void) { struct commit *c = alloc_node(&commit_state, sizeof(struct commit)); c->object.type = OBJ_COMMIT; diff --git a/blame.c b/blame.c index dfa24473dc6e3d..ba9b18e7542b22 100644 --- a/blame.c +++ b/blame.c @@ -161,7 +161,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, read_cache(); time(&now); - commit = alloc_commit_node(); + commit = alloc_commit_node(the_repository); commit->object.parsed = 1; commit->date = now; parent_tail = &commit->parents; diff --git a/cache.h b/cache.h index 1717d07a2c5d18..bf6e8c87d83d11 100644 --- a/cache.h +++ b/cache.h @@ -1768,7 +1768,8 @@ void encode_85(char *buf, const unsigned char *data, int bytes); extern void *alloc_blob_node_the_repository(void); #define alloc_tree_node(r) alloc_tree_node_##r() extern void *alloc_tree_node_the_repository(void); -extern void *alloc_commit_node(void); +#define alloc_commit_node(r) alloc_commit_node_##r() +extern void *alloc_commit_node_the_repository(void); extern void *alloc_tag_node(void); extern void *alloc_object_node(void); extern void alloc_report(void); diff --git a/commit.c b/commit.c index 9106acf0aadca1..a9a43e79bae3ce 100644 --- a/commit.c +++ b/commit.c @@ -51,7 +51,7 @@ struct commit *lookup_commit(const struct object_id *oid) struct object *obj = lookup_object(oid->hash); if (!obj) return create_object(the_repository, oid->hash, - alloc_commit_node()); + alloc_commit_node(the_repository)); return object_as_type(obj, OBJ_COMMIT, 0); } diff --git a/merge-recursive.c b/merge-recursive.c index 0c0d48624da1d6..6dac8908648827 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -98,7 +98,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two, static struct commit *make_virtual_commit(struct tree *tree, const char *comment) { - struct commit *commit = alloc_commit_node(); + struct commit *commit = alloc_commit_node(the_repository); set_merge_remote_desc(commit, comment, (struct object *)commit); commit->tree = tree; From a0bd9086bb66fa8cb84bd4fac6441699121e1327 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:30 -0700 Subject: [PATCH 008/711] alloc: add repository argument to alloc_tag_node This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Use a macro to catch callers passing a repository other than the_repository at compile time. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- alloc.c | 2 +- cache.h | 3 ++- tag.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/alloc.c b/alloc.c index 9e2b897ec1dea2..290250e3595c23 100644 --- a/alloc.c +++ b/alloc.c @@ -65,7 +65,7 @@ void *alloc_tree_node_the_repository(void) } static struct alloc_state tag_state; -void *alloc_tag_node(void) +void *alloc_tag_node_the_repository(void) { struct tag *t = alloc_node(&tag_state, sizeof(struct tag)); t->object.type = OBJ_TAG; diff --git a/cache.h b/cache.h index bf6e8c87d83d11..32f340cde59728 100644 --- a/cache.h +++ b/cache.h @@ -1770,7 +1770,8 @@ extern void *alloc_blob_node_the_repository(void); extern void *alloc_tree_node_the_repository(void); #define alloc_commit_node(r) alloc_commit_node_##r() extern void *alloc_commit_node_the_repository(void); -extern void *alloc_tag_node(void); +#define alloc_tag_node(r) alloc_tag_node_##r() +extern void *alloc_tag_node_the_repository(void); extern void *alloc_object_node(void); extern void alloc_report(void); extern unsigned int alloc_commit_index(void); diff --git a/tag.c b/tag.c index 7150b759d66ec4..02ef4eaafc0d38 100644 --- a/tag.c +++ b/tag.c @@ -94,7 +94,7 @@ struct tag *lookup_tag(const struct object_id *oid) struct object *obj = lookup_object(oid->hash); if (!obj) return create_object(the_repository, oid->hash, - alloc_tag_node()); + alloc_tag_node(the_repository)); return object_as_type(obj, OBJ_TAG, 0); } From 13e3fdcb767fe860953f8c27eb1985bd5d15674d Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:31 -0700 Subject: [PATCH 009/711] alloc: add repository argument to alloc_object_node This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Use a macro to catch callers passing a repository other than the_repository at compile time. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- alloc.c | 2 +- cache.h | 3 ++- object.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/alloc.c b/alloc.c index 290250e3595c23..f031ce422d95d0 100644 --- a/alloc.c +++ b/alloc.c @@ -73,7 +73,7 @@ void *alloc_tag_node_the_repository(void) } static struct alloc_state object_state; -void *alloc_object_node(void) +void *alloc_object_node_the_repository(void) { struct object *obj = alloc_node(&object_state, sizeof(union any_object)); obj->type = OBJ_NONE; diff --git a/cache.h b/cache.h index 32f340cde59728..2d60359a96412b 100644 --- a/cache.h +++ b/cache.h @@ -1772,7 +1772,8 @@ extern void *alloc_tree_node_the_repository(void); extern void *alloc_commit_node_the_repository(void); #define alloc_tag_node(r) alloc_tag_node_##r() extern void *alloc_tag_node_the_repository(void); -extern void *alloc_object_node(void); +#define alloc_object_node(r) alloc_object_node_##r() +extern void *alloc_object_node_the_repository(void); extern void alloc_report(void); extern unsigned int alloc_commit_index(void); diff --git a/object.c b/object.c index 91edc30770c60c..b8c3f923c515cb 100644 --- a/object.c +++ b/object.c @@ -180,7 +180,7 @@ struct object *lookup_unknown_object(const unsigned char *sha1) struct object *obj = lookup_object(sha1); if (!obj) obj = create_object(the_repository, sha1, - alloc_object_node()); + alloc_object_node(the_repository)); return obj; } From 17bfe87369a726ebf3b1156ffd38c014bbd67e88 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:32 -0700 Subject: [PATCH 010/711] alloc: add repository argument to alloc_report This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Use a macro to catch callers passing a repository other than the_repository at compile time. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- alloc.c | 2 +- cache.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/alloc.c b/alloc.c index f031ce422d95d0..28b85b221441b9 100644 --- a/alloc.c +++ b/alloc.c @@ -105,7 +105,7 @@ static void report(const char *name, unsigned int count, size_t size) #define REPORT(name, type) \ report(#name, name##_state.count, name##_state.count * sizeof(type) >> 10) -void alloc_report(void) +void alloc_report_the_repository(void) { REPORT(blob, struct blob); REPORT(tree, struct tree); diff --git a/cache.h b/cache.h index 2d60359a96412b..01cc207d218f6c 100644 --- a/cache.h +++ b/cache.h @@ -1774,7 +1774,8 @@ extern void *alloc_commit_node_the_repository(void); extern void *alloc_tag_node_the_repository(void); #define alloc_object_node(r) alloc_object_node_##r() extern void *alloc_object_node_the_repository(void); -extern void alloc_report(void); +#define alloc_report(r) alloc_report_##r() +extern void alloc_report_the_repository(void); extern unsigned int alloc_commit_index(void); /* pkt-line.c */ From dd5d9deb0155a27cb2d74d1a0faf0af84ef5f355 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:33 -0700 Subject: [PATCH 011/711] alloc: add repository argument to alloc_commit_index This is a small mechanical change; it doesn't change the implementation to handle repositories other than the_repository yet. Use a macro to catch callers passing a repository other than the_repository at compile time. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- alloc.c | 4 ++-- cache.h | 3 ++- object.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/alloc.c b/alloc.c index 28b85b221441b9..277dadd221b3a6 100644 --- a/alloc.c +++ b/alloc.c @@ -82,7 +82,7 @@ void *alloc_object_node_the_repository(void) static struct alloc_state commit_state; -unsigned int alloc_commit_index(void) +unsigned int alloc_commit_index_the_repository(void) { static unsigned int count; return count++; @@ -92,7 +92,7 @@ void *alloc_commit_node_the_repository(void) { struct commit *c = alloc_node(&commit_state, sizeof(struct commit)); c->object.type = OBJ_COMMIT; - c->index = alloc_commit_index(); + c->index = alloc_commit_index(the_repository); return c; } diff --git a/cache.h b/cache.h index 01cc207d218f6c..0e6c5dd5639c80 100644 --- a/cache.h +++ b/cache.h @@ -1776,7 +1776,8 @@ extern void *alloc_tag_node_the_repository(void); extern void *alloc_object_node_the_repository(void); #define alloc_report(r) alloc_report_##r() extern void alloc_report_the_repository(void); -extern unsigned int alloc_commit_index(void); +#define alloc_commit_index(r) alloc_commit_index_##r() +extern unsigned int alloc_commit_index_the_repository(void); /* pkt-line.c */ void packet_trace_identity(const char *prog); diff --git a/object.c b/object.c index b8c3f923c515cb..a365a910859f74 100644 --- a/object.c +++ b/object.c @@ -162,7 +162,7 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet) return obj; else if (obj->type == OBJ_NONE) { if (type == OBJ_COMMIT) - ((struct commit *)obj)->index = alloc_commit_index(); + ((struct commit *)obj)->index = alloc_commit_index(the_repository); obj->type = type; return obj; } From 346a817a7271b58811a8004fa225ab88bc94e9c3 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:34 -0700 Subject: [PATCH 012/711] object: allow grow_object_hash to handle arbitrary repositories Reviewed-by: Jonathan Tan Signed-off-by: Jonathan Nieder Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- object.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/object.c b/object.c index a365a910859f74..0fcd6f6df42d73 100644 --- a/object.c +++ b/object.c @@ -116,27 +116,27 @@ struct object *lookup_object(const unsigned char *sha1) * power of 2 (but at least 32). Copy the existing values to the new * hash map. */ -#define grow_object_hash(r) grow_object_hash_##r() -static void grow_object_hash_the_repository(void) +static void grow_object_hash(struct repository *r) { int i; /* * Note that this size must always be power-of-2 to match hash_obj * above. */ - int new_hash_size = the_repository->parsed_objects->obj_hash_size < 32 ? 32 : 2 * the_repository->parsed_objects->obj_hash_size; + int new_hash_size = r->parsed_objects->obj_hash_size < 32 ? 32 : 2 * r->parsed_objects->obj_hash_size; struct object **new_hash; new_hash = xcalloc(new_hash_size, sizeof(struct object *)); - for (i = 0; i < the_repository->parsed_objects->obj_hash_size; i++) { - struct object *obj = the_repository->parsed_objects->obj_hash[i]; + for (i = 0; i < r->parsed_objects->obj_hash_size; i++) { + struct object *obj = r->parsed_objects->obj_hash[i]; + if (!obj) continue; insert_obj_hash(obj, new_hash, new_hash_size); } - free(the_repository->parsed_objects->obj_hash); - the_repository->parsed_objects->obj_hash = new_hash; - the_repository->parsed_objects->obj_hash_size = new_hash_size; + free(r->parsed_objects->obj_hash); + r->parsed_objects->obj_hash = new_hash; + r->parsed_objects->obj_hash_size = new_hash_size; } void *create_object_the_repository(const unsigned char *sha1, void *o) From 341e45e46bba094ef1274957ef5891f43e91b344 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 8 May 2018 12:37:35 -0700 Subject: [PATCH 013/711] object: allow create_object to handle arbitrary repositories Reviewed-by: Jonathan Tan Signed-off-by: Jonathan Nieder Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- object.c | 12 ++++++------ object.h | 3 +-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/object.c b/object.c index 0fcd6f6df42d73..49b952e92997e3 100644 --- a/object.c +++ b/object.c @@ -139,7 +139,7 @@ static void grow_object_hash(struct repository *r) r->parsed_objects->obj_hash_size = new_hash_size; } -void *create_object_the_repository(const unsigned char *sha1, void *o) +void *create_object(struct repository *r, const unsigned char *sha1, void *o) { struct object *obj = o; @@ -147,12 +147,12 @@ void *create_object_the_repository(const unsigned char *sha1, void *o) obj->flags = 0; hashcpy(obj->oid.hash, sha1); - if (the_repository->parsed_objects->obj_hash_size - 1 <= the_repository->parsed_objects->nr_objs * 2) - grow_object_hash(the_repository); + if (r->parsed_objects->obj_hash_size - 1 <= r->parsed_objects->nr_objs * 2) + grow_object_hash(r); - insert_obj_hash(obj, the_repository->parsed_objects->obj_hash, - the_repository->parsed_objects->obj_hash_size); - the_repository->parsed_objects->nr_objs++; + insert_obj_hash(obj, r->parsed_objects->obj_hash, + r->parsed_objects->obj_hash_size); + r->parsed_objects->nr_objs++; return obj; } diff --git a/object.h b/object.h index 2cb0b2410839a2..b41d7a3accbab8 100644 --- a/object.h +++ b/object.h @@ -93,8 +93,7 @@ extern struct object *get_indexed_object(unsigned int); */ struct object *lookup_object(const unsigned char *sha1); -#define create_object(r, s, o) create_object_##r(s, o) -extern void *create_object_the_repository(const unsigned char *sha1, void *obj); +extern void *create_object(struct repository *r, const unsigned char *sha1, void *obj); void *object_as_type(struct object *obj, enum object_type type, int quiet); From c033a2f62dda774de8cccc83b7f1918377995d6c Mon Sep 17 00:00:00 2001 From: Prathamesh Chavan Date: Tue, 8 May 2018 17:29:49 -0700 Subject: [PATCH 014/711] submodule foreach: correct '$path' in nested submodules from a subdirectory When running 'git submodule foreach --recursive' from a subdirectory of your repository, nested submodules get a bogus value for $path: For a submodule 'sub' that contains a nested submodule 'nested', running 'git -C dir submodule foreach echo $path' from the root of the superproject would report path='../nested' for the nested submodule. The first part '../' is derived from the logic computing the relative path from $pwd to the root of the superproject. The second part is the submodule path inside the submodule. This value is of little use and is hard to document. Also, in git-submodule.txt, $path is documented to be the "name of the submodule directory relative to the superproject", but "the superproject" is ambiguous. To resolve both these issues, we could: (a) Change "the superproject" to "its immediate superproject", so $path would be "nested" instead of "../nested". (b) Change "the superproject" to "the superproject the original command was run from", so $path would be "sub/nested" instead of "../nested". (c) Change "the superproject" to "the directory the original command was run from", so $path would be "../sub/nested" instead of "../nested". The behavior for (c) was attempted to be introduced in 091a6eb0fe (submodule: drop the top-level requirement, 2013-06-16) with the intent for $path to be relative from $pwd to the submodule worktree, but that did not work for nested submodules, as the intermittent submodules were not included in the path. If we were to fix the meaning of the $path using (a), we would break any existing submodule user that runs foreach from non-root of the superproject as the non-nested submodule '../sub' would change its path to 'sub'. If we were to fix the meaning of $path using (b), then we would break any user that uses nested submodules (even from the root directory) as the 'nested' would become 'sub/nested'. If we were to fix the meaning of $path using (c), then we would break the same users as in (b) as 'nested' would become 'sub/nested' from the root directory of the superproject. All groups can be found in the wild. The author has no data if one group outweighs the other by large margin, and offending each one seems equally bad at first. However in the authors imagination it is better to go with (a) as running from a sub directory sounds like it is carried out by a human rather than by some automation task. With a human on the keyboard the feedback loop is short and the changed behavior can be adapted to quickly unlike some automation that can break silently. Discussed-with: Ramsay Jones Signed-off-by: Prathamesh Chavan Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- git-submodule.sh | 1 - t/t7407-submodule-foreach.sh | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index 24914963ca23c8..331d71c908bf22 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -345,7 +345,6 @@ cmd_foreach() prefix="$prefix$sm_path/" sanitize_submodule_env cd "$sm_path" && - sm_path=$(git submodule--helper relative-path "$sm_path" "$wt_prefix") && # we make $path available to scripts ... path=$sm_path && if test $# -eq 1 diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 6ba5daf42ee870..5144cc6926be3c 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -82,9 +82,9 @@ test_expect_success 'test basic "submodule foreach" usage' ' cat >expect <expect <../../actual + ) && + test_i18ncmp expect actual +' cat > expect < Date: Tue, 8 May 2018 17:29:50 -0700 Subject: [PATCH 015/711] submodule foreach: document '$sm_path' instead of '$path' As using a variable '$path' may be harmful to users due to capitalization issues, see 64394e3ae9 (git-submodule.sh: Don't use $path variable in eval_gettext string, 2012-04-17). Adjust the documentation to advocate for using $sm_path, which contains the same value. We still make the 'path' variable available and document it as a deprecated synonym of 'sm_path'. Discussed-with: Ramsay Jones Signed-off-by: Stefan Beller Signed-off-by: Prathamesh Chavan Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 630999f41a902d..066c7b6c18e994 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -183,12 +183,15 @@ information too. foreach [--recursive] :: Evaluates an arbitrary shell command in each checked out submodule. - The command has access to the variables $name, $path, $sha1 and + The command has access to the variables $name, $sm_path, $sha1 and $toplevel: $name is the name of the relevant submodule section in `.gitmodules`, - $path is the name of the submodule directory relative to the - superproject, $sha1 is the commit as recorded in the superproject, - and $toplevel is the absolute path to the top-level of the superproject. + $sm_path is the path of the submodule as recorded in the immediate + superproject, $sha1 is the commit as recorded in the immediate + superproject, and $toplevel is the absolute path to the top-level + of the immediate superproject. + Note that to avoid conflicts with '$PATH' on Windows, the '$path' + variable is now a deprecated synonym of '$sm_path' variable. Any submodules defined in the superproject but not checked out are ignored by this command. Unless given `--quiet`, foreach prints the name of each submodule before evaluating the command. From b6f7ac8fd561d6df9c76009898daf96a93765ffc Mon Sep 17 00:00:00 2001 From: Prathamesh Chavan Date: Tue, 8 May 2018 17:29:51 -0700 Subject: [PATCH 016/711] submodule foreach: document variable '$displaypath' It was observed that the variable '$displaypath' was accessible but undocumented. Hence, document it. Discussed-with: Ramsay Jones Signed-off-by: Stefan Beller Signed-off-by: Prathamesh Chavan Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 8 +++++--- t/t7407-submodule-foreach.sh | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 066c7b6c18e994..500dfdafd1641d 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -183,11 +183,13 @@ information too. foreach [--recursive] :: Evaluates an arbitrary shell command in each checked out submodule. - The command has access to the variables $name, $sm_path, $sha1 and - $toplevel: + The command has access to the variables $name, $sm_path, $displaypath, + $sha1 and $toplevel: $name is the name of the relevant submodule section in `.gitmodules`, $sm_path is the path of the submodule as recorded in the immediate - superproject, $sha1 is the commit as recorded in the immediate + superproject, $displaypath contains the relative path from the + current working directory to the submodules root directory, + $sha1 is the commit as recorded in the immediate superproject, and $toplevel is the absolute path to the top-level of the immediate superproject. Note that to avoid conflicts with '$PATH' on Windows, the '$path' diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 5144cc6926be3c..77729ac4aa1873 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -82,16 +82,16 @@ test_expect_success 'test basic "submodule foreach" usage' ' cat >expect <../../actual + git submodule foreach "echo \$toplevel-\$name-\$sm_path-\$displaypath-\$sha1" >../../actual ) && test_i18ncmp expect actual ' @@ -206,25 +206,25 @@ submodulesha1=$(cd clone2/nested1/nested2/nested3/submodule && git rev-parse HEA cat >expect <../../actual + git submodule foreach --recursive "echo toplevel: \$toplevel name: \$name path: \$sm_path displaypath: \$displaypath hash: \$sha1" >../../actual ) && test_i18ncmp expect actual ' From fc1b9243cd5d51ae455272f1f953d4002294edee Mon Sep 17 00:00:00 2001 From: Prathamesh Chavan Date: Thu, 10 May 2018 14:25:01 -0700 Subject: [PATCH 017/711] submodule: port submodule subcommand 'foreach' from shell to C This aims to make git-submodule foreach a builtin. 'foreach' is ported to the submodule--helper, and submodule--helper is called from git-submodule.sh. Helped-by: Brandon Williams Mentored-by: Christian Couder Mentored-by: Stefan Beller Signed-off-by: Prathamesh Chavan Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- builtin/submodule--helper.c | 144 ++++++++++++++++++++++++++++++++++++ git-submodule.sh | 39 +--------- 2 files changed, 145 insertions(+), 38 deletions(-) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index c2403a915ffe29..4002026d1acdbc 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -439,6 +439,149 @@ static void for_each_listed_submodule(const struct module_list *list, fn(list->entries[i], cb_data); } +struct cb_foreach { + int argc; + const char **argv; + const char *prefix; + int quiet; + int recursive; +}; +#define CB_FOREACH_INIT { 0 } + +static void runcommand_in_submodule_cb(const struct cache_entry *list_item, + void *cb_data) +{ + struct cb_foreach *info = cb_data; + const char *path = list_item->name; + const struct object_id *ce_oid = &list_item->oid; + + const struct submodule *sub; + struct child_process cp = CHILD_PROCESS_INIT; + char *displaypath; + + displaypath = get_submodule_displaypath(path, info->prefix); + + sub = submodule_from_path(the_repository, &null_oid, path); + + if (!sub) + die(_("No url found for submodule path '%s' in .gitmodules"), + displaypath); + + if (!is_submodule_populated_gently(path, NULL)) + goto cleanup; + + prepare_submodule_repo_env(&cp.env_array); + + /* + * For the purpose of executing in the submodule, + * separate shell is used for the purpose of running the + * child process. + */ + cp.use_shell = 1; + cp.dir = path; + + /* + * NEEDSWORK: the command currently has access to the variables $name, + * $sm_path, $displaypath, $sha1 and $toplevel only when the command + * contains a single argument. This is done for maintaining a faithful + * translation from shell script. + */ + if (info->argc == 1) { + char *toplevel = xgetcwd(); + struct strbuf sb = STRBUF_INIT; + + argv_array_pushf(&cp.env_array, "name=%s", sub->name); + argv_array_pushf(&cp.env_array, "sm_path=%s", path); + argv_array_pushf(&cp.env_array, "displaypath=%s", displaypath); + argv_array_pushf(&cp.env_array, "sha1=%s", + oid_to_hex(ce_oid)); + argv_array_pushf(&cp.env_array, "toplevel=%s", toplevel); + + /* + * Since the path variable was accessible from the script + * before porting, it is also made available after porting. + * The environment variable "PATH" has a very special purpose + * on windows. And since environment variables are + * case-insensitive in windows, it interferes with the + * existing PATH variable. Hence, to avoid that, we expose + * path via the args argv_array and not via env_array. + */ + sq_quote_buf(&sb, path); + argv_array_pushf(&cp.args, "path=%s; %s", + sb.buf, info->argv[0]); + strbuf_release(&sb); + free(toplevel); + } else { + argv_array_pushv(&cp.args, info->argv); + } + + if (!info->quiet) + printf(_("Entering '%s'\n"), displaypath); + + if (info->argv[0] && run_command(&cp)) + die(_("run_command returned non-zero status for %s\n."), + displaypath); + + if (info->recursive) { + struct child_process cpr = CHILD_PROCESS_INIT; + + cpr.git_cmd = 1; + cpr.dir = path; + prepare_submodule_repo_env(&cpr.env_array); + + argv_array_pushl(&cpr.args, "--super-prefix", NULL); + argv_array_pushf(&cpr.args, "%s/", displaypath); + argv_array_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive", + NULL); + + if (info->quiet) + argv_array_push(&cpr.args, "--quiet"); + + argv_array_pushv(&cpr.args, info->argv); + + if (run_command(&cpr)) + die(_("run_command returned non-zero status while" + "recursing in the nested submodules of %s\n."), + displaypath); + } + +cleanup: + free(displaypath); +} + +static int module_foreach(int argc, const char **argv, const char *prefix) +{ + struct cb_foreach info = CB_FOREACH_INIT; + struct pathspec pathspec; + struct module_list list = MODULE_LIST_INIT; + + struct option module_foreach_options[] = { + OPT__QUIET(&info.quiet, N_("Suppress output of entering each submodule command")), + OPT_BOOL(0, "recursive", &info.recursive, + N_("Recurse into nested submodules")), + OPT_END() + }; + + const char *const git_submodule_helper_usage[] = { + N_("git submodule--helper foreach [--quiet] [--recursive] "), + NULL + }; + + argc = parse_options(argc, argv, prefix, module_foreach_options, + git_submodule_helper_usage, PARSE_OPT_KEEP_UNKNOWN); + + if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0) + return 1; + + info.argc = argc; + info.argv = argv; + info.prefix = prefix; + + for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info); + + return 0; +} + struct init_cb { const char *prefix; unsigned int flags; @@ -1841,6 +1984,7 @@ static struct cmd_struct commands[] = { {"relative-path", resolve_relative_path, 0}, {"resolve-relative-url", resolve_relative_url, 0}, {"resolve-relative-url-test", resolve_relative_url_test, 0}, + {"foreach", module_foreach, SUPPORT_SUPER_PREFIX}, {"init", module_init, SUPPORT_SUPER_PREFIX}, {"status", module_status, SUPPORT_SUPER_PREFIX}, {"print-default-remote", print_default_remote, 0}, diff --git a/git-submodule.sh b/git-submodule.sh index 331d71c908bf22..cba585f0754bdc 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -323,44 +323,7 @@ cmd_foreach() shift done - toplevel=$(pwd) - - # dup stdin so that it can be restored when running the external - # command in the subshell (and a recursive call to this function) - exec 3<&0 - - { - git submodule--helper list --prefix "$wt_prefix" || - echo "#unmatched" $? - } | - while read -r mode sha1 stage sm_path - do - die_if_unmatched "$mode" "$sha1" - if test -e "$sm_path"/.git - then - displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix") - say "$(eval_gettext "Entering '\$displaypath'")" - name=$(git submodule--helper name "$sm_path") - ( - prefix="$prefix$sm_path/" - sanitize_submodule_env - cd "$sm_path" && - # we make $path available to scripts ... - path=$sm_path && - if test $# -eq 1 - then - eval "$1" - else - "$@" - fi && - if test -n "$recursive" - then - cmd_foreach "--recursive" "$@" - fi - ) <&3 3<&- || - die "$(eval_gettext "Stopping at '\$displaypath'; script returned non-zero status.")" - fi - done + git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} "$@" } # From 14ba97f81c7b94e10d591b363688a073023f332d Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 15 May 2018 14:48:42 -0700 Subject: [PATCH 018/711] alloc: allow arbitrary repositories for alloc functions We have to convert all of the alloc functions at once, because alloc_report uses a funky macro for reporting. It is better for the sake of mechanical conversion to convert multiple functions at once rather than changing the structure of the reporting function. We record all memory allocation in alloc.c, and free them in clear_alloc_state, which is called for all repositories except the_repository. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- alloc.c | 65 ++++++++++++++++++++++++++++++----------------- alloc.h | 19 ++++++++++++++ blame.c | 1 + blob.c | 1 + cache.h | 16 ------------ commit.c | 12 +++++++++ commit.h | 6 +++++ merge-recursive.c | 1 + object.c | 42 ++++++++++++++++++++++++++++-- object.h | 8 ++++++ tag.c | 9 +++++++ tag.h | 1 + tree.c | 1 + 13 files changed, 140 insertions(+), 42 deletions(-) create mode 100644 alloc.h diff --git a/alloc.c b/alloc.c index 277dadd221b3a6..714df633169df5 100644 --- a/alloc.c +++ b/alloc.c @@ -4,8 +4,7 @@ * Copyright (C) 2006 Linus Torvalds * * The standard malloc/free wastes too much space for objects, partly because - * it maintains all the allocation infrastructure (which isn't needed, since - * we never free an object descriptor anyway), but even more because it ends + * it maintains all the allocation infrastructure, but even more because it ends * up with maximal alignment because it doesn't know what the object alignment * for the new allocation is. */ @@ -15,6 +14,7 @@ #include "tree.h" #include "commit.h" #include "tag.h" +#include "alloc.h" #define BLOCKING 1024 @@ -30,8 +30,27 @@ struct alloc_state { int count; /* total number of nodes allocated */ int nr; /* number of nodes left in current allocation */ void *p; /* first free node in current allocation */ + + /* bookkeeping of allocations */ + void **slabs; + int slab_nr, slab_alloc; }; +void *allocate_alloc_state(void) +{ + return xcalloc(1, sizeof(struct alloc_state)); +} + +void clear_alloc_state(struct alloc_state *s) +{ + while (s->slab_nr > 0) { + s->slab_nr--; + free(s->slabs[s->slab_nr]); + } + + FREE_AND_NULL(s->slabs); +} + static inline void *alloc_node(struct alloc_state *s, size_t node_size) { void *ret; @@ -39,60 +58,57 @@ static inline void *alloc_node(struct alloc_state *s, size_t node_size) if (!s->nr) { s->nr = BLOCKING; s->p = xmalloc(BLOCKING * node_size); + + ALLOC_GROW(s->slabs, s->slab_nr + 1, s->slab_alloc); + s->slabs[s->slab_nr++] = s->p; } s->nr--; s->count++; ret = s->p; s->p = (char *)s->p + node_size; memset(ret, 0, node_size); + return ret; } -static struct alloc_state blob_state; -void *alloc_blob_node_the_repository(void) +void *alloc_blob_node(struct repository *r) { - struct blob *b = alloc_node(&blob_state, sizeof(struct blob)); + struct blob *b = alloc_node(r->parsed_objects->blob_state, sizeof(struct blob)); b->object.type = OBJ_BLOB; return b; } -static struct alloc_state tree_state; -void *alloc_tree_node_the_repository(void) +void *alloc_tree_node(struct repository *r) { - struct tree *t = alloc_node(&tree_state, sizeof(struct tree)); + struct tree *t = alloc_node(r->parsed_objects->tree_state, sizeof(struct tree)); t->object.type = OBJ_TREE; return t; } -static struct alloc_state tag_state; -void *alloc_tag_node_the_repository(void) +void *alloc_tag_node(struct repository *r) { - struct tag *t = alloc_node(&tag_state, sizeof(struct tag)); + struct tag *t = alloc_node(r->parsed_objects->tag_state, sizeof(struct tag)); t->object.type = OBJ_TAG; return t; } -static struct alloc_state object_state; -void *alloc_object_node_the_repository(void) +void *alloc_object_node(struct repository *r) { - struct object *obj = alloc_node(&object_state, sizeof(union any_object)); + struct object *obj = alloc_node(r->parsed_objects->object_state, sizeof(union any_object)); obj->type = OBJ_NONE; return obj; } -static struct alloc_state commit_state; - -unsigned int alloc_commit_index_the_repository(void) +unsigned int alloc_commit_index(struct repository *r) { - static unsigned int count; - return count++; + return r->parsed_objects->commit_count++; } -void *alloc_commit_node_the_repository(void) +void *alloc_commit_node(struct repository *r) { - struct commit *c = alloc_node(&commit_state, sizeof(struct commit)); + struct commit *c = alloc_node(r->parsed_objects->commit_state, sizeof(struct commit)); c->object.type = OBJ_COMMIT; - c->index = alloc_commit_index(the_repository); + c->index = alloc_commit_index(r); return c; } @@ -103,9 +119,10 @@ static void report(const char *name, unsigned int count, size_t size) } #define REPORT(name, type) \ - report(#name, name##_state.count, name##_state.count * sizeof(type) >> 10) + report(#name, r->parsed_objects->name##_state->count, \ + r->parsed_objects->name##_state->count * sizeof(type) >> 10) -void alloc_report_the_repository(void) +void alloc_report(struct repository *r) { REPORT(blob, struct blob); REPORT(tree, struct tree); diff --git a/alloc.h b/alloc.h new file mode 100644 index 00000000000000..3e4e828db48e2b --- /dev/null +++ b/alloc.h @@ -0,0 +1,19 @@ +#ifndef ALLOC_H +#define ALLOC_H + +struct tree; +struct commit; +struct tag; + +void *alloc_blob_node(struct repository *r); +void *alloc_tree_node(struct repository *r); +void *alloc_commit_node(struct repository *r); +void *alloc_tag_node(struct repository *r); +void *alloc_object_node(struct repository *r); +void alloc_report(struct repository *r); +unsigned int alloc_commit_index(struct repository *r); + +void *allocate_alloc_state(void); +void clear_alloc_state(struct alloc_state *s); + +#endif diff --git a/blame.c b/blame.c index ba9b18e7542b22..3a11f1ce52baeb 100644 --- a/blame.c +++ b/blame.c @@ -6,6 +6,7 @@ #include "diffcore.h" #include "tag.h" #include "blame.h" +#include "alloc.h" void blame_origin_decref(struct blame_origin *o) { diff --git a/blob.c b/blob.c index 9e64f301895e41..458dafa811edf7 100644 --- a/blob.c +++ b/blob.c @@ -1,6 +1,7 @@ #include "cache.h" #include "blob.h" #include "repository.h" +#include "alloc.h" const char *blob_type = "blob"; diff --git a/cache.h b/cache.h index 0e6c5dd5639c80..c75559b7d38a22 100644 --- a/cache.h +++ b/cache.h @@ -1763,22 +1763,6 @@ extern const char *excludes_file; int decode_85(char *dst, const char *line, int linelen); void encode_85(char *buf, const unsigned char *data, int bytes); -/* alloc.c */ -#define alloc_blob_node(r) alloc_blob_node_##r() -extern void *alloc_blob_node_the_repository(void); -#define alloc_tree_node(r) alloc_tree_node_##r() -extern void *alloc_tree_node_the_repository(void); -#define alloc_commit_node(r) alloc_commit_node_##r() -extern void *alloc_commit_node_the_repository(void); -#define alloc_tag_node(r) alloc_tag_node_##r() -extern void *alloc_tag_node_the_repository(void); -#define alloc_object_node(r) alloc_object_node_##r() -extern void *alloc_object_node_the_repository(void); -#define alloc_report(r) alloc_report_##r() -extern void alloc_report_the_repository(void); -#define alloc_commit_index(r) alloc_commit_index_##r() -extern unsigned int alloc_commit_index_the_repository(void); - /* pkt-line.c */ void packet_trace_identity(const char *prog); diff --git a/commit.c b/commit.c index a9a43e79bae3ce..5eb4d2f08f8d09 100644 --- a/commit.c +++ b/commit.c @@ -6,6 +6,7 @@ #include "diff.h" #include "revision.h" #include "notes.h" +#include "alloc.h" #include "gpg-interface.h" #include "mergesort.h" #include "commit-slab.h" @@ -296,6 +297,17 @@ void free_commit_buffer(struct commit *commit) } } +void release_commit_memory(struct commit *c) +{ + c->tree = NULL; + c->index = 0; + free_commit_buffer(c); + free_commit_list(c->parents); + /* TODO: what about commit->util? */ + + c->object.parsed = 0; +} + const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep) { struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit); diff --git a/commit.h b/commit.h index 0fb8271665c6c9..2d764ab7d8e635 100644 --- a/commit.h +++ b/commit.h @@ -99,6 +99,12 @@ void unuse_commit_buffer(const struct commit *, const void *buffer); */ void free_commit_buffer(struct commit *); +/* + * Release memory related to a commit, including the parent list and + * any cached object buffer. + */ +void release_commit_memory(struct commit *c); + /* * Disassociate any cached object buffer from the commit, but do not free it. * The buffer (or NULL, if none) is returned. diff --git a/merge-recursive.c b/merge-recursive.c index 6dac8908648827..cbded673c282fd 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -15,6 +15,7 @@ #include "diff.h" #include "diffcore.h" #include "tag.h" +#include "alloc.h" #include "unpack-trees.h" #include "string-list.h" #include "xdiff-interface.h" diff --git a/object.c b/object.c index 49b952e92997e3..8e29f63bf23253 100644 --- a/object.c +++ b/object.c @@ -5,6 +5,7 @@ #include "tree.h" #include "commit.h" #include "tag.h" +#include "alloc.h" #include "object-store.h" #include "packfile.h" @@ -455,6 +456,13 @@ struct parsed_object_pool *parsed_object_pool_new(void) { struct parsed_object_pool *o = xmalloc(sizeof(*o)); memset(o, 0, sizeof(*o)); + + o->blob_state = allocate_alloc_state(); + o->tree_state = allocate_alloc_state(); + o->commit_state = allocate_alloc_state(); + o->tag_state = allocate_alloc_state(); + o->object_state = allocate_alloc_state(); + return o; } @@ -501,9 +509,39 @@ void raw_object_store_clear(struct raw_object_store *o) void parsed_object_pool_clear(struct parsed_object_pool *o) { /* - * TOOD free objects in o->obj_hash. - * * As objects are allocated in slabs (see alloc.c), we do * not need to free each object, but each slab instead. + * + * Before doing so, we need to free any additional memory + * the objects may hold. */ + unsigned i; + + for (i = 0; i < o->obj_hash_size; i++) { + struct object *obj = o->obj_hash[i]; + + if (!obj) + continue; + + if (obj->type == OBJ_TREE) + free_tree_buffer((struct tree*)obj); + else if (obj->type == OBJ_COMMIT) + release_commit_memory((struct commit*)obj); + else if (obj->type == OBJ_TAG) + release_tag_memory((struct tag*)obj); + } + + FREE_AND_NULL(o->obj_hash); + o->obj_hash_size = 0; + + clear_alloc_state(o->blob_state); + clear_alloc_state(o->tree_state); + clear_alloc_state(o->commit_state); + clear_alloc_state(o->tag_state); + clear_alloc_state(o->object_state); + FREE_AND_NULL(o->blob_state); + FREE_AND_NULL(o->tree_state); + FREE_AND_NULL(o->commit_state); + FREE_AND_NULL(o->tag_state); + FREE_AND_NULL(o->object_state); } diff --git a/object.h b/object.h index b41d7a3accbab8..7916edb4edf015 100644 --- a/object.h +++ b/object.h @@ -4,6 +4,14 @@ struct parsed_object_pool { struct object **obj_hash; int nr_objs, obj_hash_size; + + /* TODO: migrate alloc_states to mem-pool? */ + struct alloc_state *blob_state; + struct alloc_state *tree_state; + struct alloc_state *commit_state; + struct alloc_state *tag_state; + struct alloc_state *object_state; + unsigned commit_count; }; struct parsed_object_pool *parsed_object_pool_new(void); diff --git a/tag.c b/tag.c index 02ef4eaafc0d38..7c12426b4eaba5 100644 --- a/tag.c +++ b/tag.c @@ -3,6 +3,7 @@ #include "commit.h" #include "tree.h" #include "blob.h" +#include "alloc.h" #include "gpg-interface.h" const char *tag_type = "tag"; @@ -115,6 +116,14 @@ static timestamp_t parse_tag_date(const char *buf, const char *tail) return parse_timestamp(dateptr, NULL, 10); } +void release_tag_memory(struct tag *t) +{ + free(t->tag); + t->tagged = NULL; + t->object.parsed = 0; + t->date = 0; +} + int parse_tag_buffer(struct tag *item, const void *data, unsigned long size) { struct object_id oid; diff --git a/tag.h b/tag.h index d469534e82a87b..9057d76a50639d 100644 --- a/tag.h +++ b/tag.h @@ -15,6 +15,7 @@ struct tag { extern struct tag *lookup_tag(const struct object_id *oid); extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long size); extern int parse_tag(struct tag *item); +extern void release_tag_memory(struct tag *t); extern struct object *deref_tag(struct object *, const char *, int); extern struct object *deref_tag_noverify(struct object *); extern int gpg_verify_tag(const struct object_id *oid, diff --git a/tree.c b/tree.c index 58cf19b4fa8e77..8f8ef3189af9f0 100644 --- a/tree.c +++ b/tree.c @@ -5,6 +5,7 @@ #include "blob.h" #include "commit.h" #include "tag.h" +#include "alloc.h" #include "tree-walk.h" const char *tree_type = "tree"; From cbd53a2193d11e83b5bad2c3514bd1603074bc36 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 15 May 2018 16:42:15 -0700 Subject: [PATCH 019/711] object-store: move object access functions to object-store.h This should make these functions easier to find and cache.h less overwhelming to read. In particular, this moves: - read_object_file - oid_object_info - write_object_file As a result, most of the codebase needs to #include object-store.h. In this patch the #include is only added to files that would fail to compile otherwise. It would be better to #include wherever identifiers from the header are used. That can happen later when we have better tooling for it. Signed-off-by: Stefan Beller Signed-off-by: Junio C Hamano --- apply.c | 1 + archive-tar.c | 1 + archive-zip.c | 1 + archive.c | 1 + blame.c | 1 + builtin/blame.c | 1 + builtin/cat-file.c | 1 + builtin/checkout.c | 1 + builtin/clone.c | 1 + builtin/commit-tree.c | 1 + builtin/describe.c | 1 + builtin/difftool.c | 1 + builtin/fast-export.c | 1 + builtin/fetch.c | 1 + builtin/fmt-merge-msg.c | 1 + builtin/hash-object.c | 1 + builtin/log.c | 1 + builtin/ls-tree.c | 1 + builtin/merge-tree.c | 1 + builtin/mktag.c | 1 + builtin/mktree.c | 1 + builtin/notes.c | 1 + builtin/prune.c | 1 + builtin/receive-pack.c | 1 + builtin/reflog.c | 1 + builtin/remote.c | 1 + builtin/rev-list.c | 1 + builtin/show-ref.c | 1 + builtin/tag.c | 1 + builtin/unpack-file.c | 1 + builtin/unpack-objects.c | 1 + builtin/verify-commit.c | 1 + bulk-checkin.c | 1 + bundle.c | 1 + cache-tree.c | 1 + cache.h | 117 --------------------------------------- combine-diff.c | 1 + commit.c | 1 + config.c | 1 + convert.c | 1 + diff.c | 1 + diffcore-rename.c | 1 + dir.c | 1 + entry.c | 1 + fetch-pack.c | 1 + fsck.c | 1 + grep.c | 1 + list-objects-filter.c | 1 + list-objects.c | 1 + log-tree.c | 1 + mailmap.c | 1 + match-trees.c | 1 + merge-blobs.c | 1 + merge-recursive.c | 1 + notes-cache.c | 1 + notes-merge.c | 1 + notes.c | 1 + object-store.h | 117 +++++++++++++++++++++++++++++++++++++++ object.c | 1 + pack-bitmap-write.c | 1 + packfile.h | 5 ++ read-cache.c | 1 + ref-filter.c | 1 + refs.c | 1 + remote-testsvn.c | 1 + remote.c | 1 + rerere.c | 1 + revision.c | 1 + send-pack.c | 1 + sequencer.c | 1 + shallow.c | 1 + submodule-config.c | 1 + tag.c | 1 + tree-walk.c | 1 + tree.c | 1 + unpack-trees.c | 1 + upload-pack.c | 1 + walker.c | 1 + xdiff-interface.c | 1 + 79 files changed, 198 insertions(+), 117 deletions(-) diff --git a/apply.c b/apply.c index 7e5792c996f430..cbc45fa1b0ebf0 100644 --- a/apply.c +++ b/apply.c @@ -9,6 +9,7 @@ #include "cache.h" #include "config.h" +#include "object-store.h" #include "blob.h" #include "delta.h" #include "diff.h" diff --git a/archive-tar.c b/archive-tar.c index f93409324f9d4f..e38435eb4ef93b 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -5,6 +5,7 @@ #include "config.h" #include "tar.h" #include "archive.h" +#include "object-store.h" #include "streaming.h" #include "run-command.h" diff --git a/archive-zip.c b/archive-zip.c index 74f3fe91034205..abc556e5a7506c 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -6,6 +6,7 @@ #include "archive.h" #include "streaming.h" #include "utf8.h" +#include "object-store.h" #include "userdiff.h" #include "xdiff-interface.h" diff --git a/archive.c b/archive.c index 93ab175b0b4055..9da1e3664a6165 100644 --- a/archive.c +++ b/archive.c @@ -1,6 +1,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "tree-walk.h" #include "attr.h" diff --git a/blame.c b/blame.c index 3a11f1ce52baeb..f689bde31cd56a 100644 --- a/blame.c +++ b/blame.c @@ -1,5 +1,6 @@ #include "cache.h" #include "refs.h" +#include "object-store.h" #include "cache-tree.h" #include "mergesort.h" #include "diff.h" diff --git a/builtin/blame.c b/builtin/blame.c index bfdf7cc1325826..0ffd1d443eaf16 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -22,6 +22,7 @@ #include "line-log.h" #include "dir.h" #include "progress.h" +#include "object-store.h" #include "blame.h" static char blame_usage[] = N_("git blame [] [] [] [--] "); diff --git a/builtin/cat-file.c b/builtin/cat-file.c index b8ecbea98e966f..91e7764243e5bf 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -13,6 +13,7 @@ #include "tree-walk.h" #include "sha1-array.h" #include "packfile.h" +#include "object-store.h" struct batch_options { int enabled; diff --git a/builtin/checkout.c b/builtin/checkout.c index b49b5820718335..105e07981ff458 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -4,6 +4,7 @@ #include "lockfile.h" #include "parse-options.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "tree.h" #include "tree-walk.h" diff --git a/builtin/clone.c b/builtin/clone.c index 7df5932b855e87..29998c02ecefd6 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -14,6 +14,7 @@ #include "parse-options.h" #include "fetch-pack.h" #include "refs.h" +#include "object-store.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h" diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index ecf42191da10cd..9fbd3529fb17bf 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -5,6 +5,7 @@ */ #include "cache.h" #include "config.h" +#include "object-store.h" #include "commit.h" #include "tree.h" #include "builtin.h" diff --git a/builtin/describe.c b/builtin/describe.c index 66c497f7896b59..65b0edc473ce81 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -13,6 +13,7 @@ #include "hashmap.h" #include "argv-array.h" #include "run-command.h" +#include "object-store.h" #include "revision.h" #include "list-objects.h" diff --git a/builtin/difftool.c b/builtin/difftool.c index ee8dce019e1ca0..df7e75f797bdc7 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -20,6 +20,7 @@ #include "argv-array.h" #include "strbuf.h" #include "lockfile.h" +#include "object-store.h" #include "dir.h" static char *diff_gui_tool; diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 373c794873efd8..f593e57b9d4cdd 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -7,6 +7,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "object.h" #include "tag.h" diff --git a/builtin/fetch.c b/builtin/fetch.c index 73be393b2eaa37..c1f2df979652a3 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -5,6 +5,7 @@ #include "config.h" #include "repository.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "builtin.h" #include "string-list.h" diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index bd680be6874da2..1b526adb3a95bb 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -2,6 +2,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "diff.h" #include "revision.h" diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 526da5c1856ed1..d5c018eabd5054 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -6,6 +6,7 @@ */ #include "builtin.h" #include "config.h" +#include "object-store.h" #include "blob.h" #include "quote.h" #include "parse-options.h" diff --git a/builtin/log.c b/builtin/log.c index 71f68a3e4f59d9..9656578f58ea53 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -7,6 +7,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "color.h" #include "commit.h" #include "diff.h" diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 409da4e8351f6d..fe3b952cb3007d 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -5,6 +5,7 @@ */ #include "cache.h" #include "config.h" +#include "object-store.h" #include "blob.h" #include "tree.h" #include "commit.h" diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 32736e0b1011f5..1b702d44c9fd01 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "tree-walk.h" #include "xdiff-interface.h" +#include "object-store.h" #include "blob.h" #include "exec_cmd.h" #include "merge-blobs.h" diff --git a/builtin/mktag.c b/builtin/mktag.c index 82a6e860775f87..6fb7dc8578d685 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "tag.h" #include "replace-object.h" +#include "object-store.h" /* * A signature file has a very simple fixed format: four lines diff --git a/builtin/mktree.c b/builtin/mktree.c index bb76b469fd1f57..2dc4ad6ba8f227 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -7,6 +7,7 @@ #include "quote.h" #include "tree.h" #include "parse-options.h" +#include "object-store.h" static struct treeent { unsigned mode; diff --git a/builtin/notes.c b/builtin/notes.c index 921e08d5bf545a..73b680ee13ada3 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -11,6 +11,7 @@ #include "config.h" #include "builtin.h" #include "notes.h" +#include "object-store.h" #include "blob.h" #include "pretty.h" #include "refs.h" diff --git a/builtin/prune.c b/builtin/prune.c index 518ffbea1397fa..8cc8659612fe5f 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -6,6 +6,7 @@ #include "reachable.h" #include "parse-options.h" #include "progress.h" +#include "object-store.h" static const char * const prune_usage[] = { N_("git prune [-n] [-v] [--progress] [--expire