@@ -1155,6 +1155,8 @@ struct repository_format {
int hash_algo;
int sparse_index;
char *work_tree;
+ int ref_format_count;
+ enum ref_format_flags ref_format;
struct string_list unknown_extensions;
struct string_list v1_only_extensions;
};
@@ -1982,6 +1982,15 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map,
return entry ? entry->refs : NULL;
}
+static int add_ref_format_flags(enum ref_format_flags flags, int caps) {
+ if (flags & REF_FORMAT_FILES)
+ caps |= REF_STORE_FORMAT_FILES;
+ if (flags & REF_FORMAT_PACKED)
+ caps |= REF_STORE_FORMAT_PACKED;
+
+ return caps;
+}
+
/*
* Create, record, and return a ref_store instance for the specified
* gitdir.
@@ -1991,9 +2000,17 @@ static struct ref_store *ref_store_init(struct repository *repo,
unsigned int flags)
{
const char *be_name = "files";
- struct ref_storage_be *be = find_ref_storage_backend(be_name);
+ struct ref_storage_be *be;
struct ref_store *refs;
+ flags = add_ref_format_flags(repo->ref_format, flags);
+
+ if (!(flags & REF_STORE_FORMAT_FILES) &&
+ (flags & REF_STORE_FORMAT_PACKED))
+ be_name = "packed";
+
+ be = find_ref_storage_backend(be_name);
+
if (!be)
BUG("reference backend %s is unknown", be_name);
@@ -2009,7 +2026,8 @@ struct ref_store *get_main_ref_store(struct repository *r)
if (!r->gitdir)
BUG("attempting to get main_ref_store outside of repository");
- r->refs_private = ref_store_init(r, r->gitdir, REF_STORE_ALL_CAPS);
+ r->refs_private = ref_store_init(r, r->gitdir,
+ REF_STORE_ALL_CAPS);
r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private);
return r->refs_private;
}
@@ -3274,7 +3274,7 @@ static int files_init_db(struct ref_store *ref_store, struct strbuf *err UNUSED)
}
struct ref_storage_be refs_be_files = {
- .next = NULL,
+ .next = &refs_be_packed,
.name = "files",
.init = files_ref_store_create,
.init_db = files_init_db,
@@ -521,6 +521,9 @@ struct ref_store;
REF_STORE_ODB | \
REF_STORE_MAIN)
+#define REF_STORE_FORMAT_FILES (1 << 8) /* can use loose ref files */
+#define REF_STORE_FORMAT_PACKED (1 << 9) /* can use packed-refs file */
+
/*
* Initialize the ref_store for the specified gitdir. These functions
* should call base_ref_store_init() to initialize the shared part of
@@ -182,6 +182,8 @@ int repo_init(struct repository *repo,
repo->repository_format_partial_clone = format.partial_clone;
format.partial_clone = NULL;
+ repo->ref_format = format.ref_format;
+
if (worktree)
repo_set_worktree(repo, worktree);
@@ -61,6 +61,11 @@ struct repo_path_cache {
char *shallow;
};
+enum ref_format_flags {
+ REF_FORMAT_FILES = (1 << 0),
+ REF_FORMAT_PACKED = (1 << 1),
+};
+
struct repository {
/* Environment */
/*
@@ -95,6 +100,7 @@ struct repository {
* the ref object.
*/
struct ref_store *refs_private;
+ enum ref_format_flags ref_format;
/*
* Contains path to often used file names.
@@ -578,9 +578,14 @@ static enum extension_result handle_extension(const char *var,
data->hash_algo = format;
return EXTENSION_OK;
} else if (!strcmp(ext, "refformat")) {
- if (strcmp(value, "files") && strcmp(value, "packed"))
+ if (!strcmp(value, "files"))
+ data->ref_format |= REF_FORMAT_FILES;
+ else if (!strcmp(value, "packed"))
+ data->ref_format |= REF_FORMAT_PACKED;
+ else
return error(_("invalid value for '%s': '%s'"),
"extensions.refFormat", value);
+ data->ref_format_count++;
return EXTENSION_OK;
}
return EXTENSION_UNKNOWN;
@@ -723,6 +728,11 @@ int read_repository_format(struct repository_format *format, const char *path)
git_config_from_file(check_repo_format, path, format);
if (format->version == -1)
clear_repository_format(format);
+
+ /* Set default ref_format if no extensions.refFormat exists. */
+ if (!format->ref_format_count)
+ format->ref_format = REF_FORMAT_FILES | REF_FORMAT_PACKED;
+
return format->version;
}
@@ -1425,6 +1435,9 @@ int discover_git_directory(struct strbuf *commondir,
candidate.partial_clone;
candidate.partial_clone = NULL;
+ /* take ownership of candidate.ref_format */
+ the_repository->ref_format = candidate.ref_format;
+
clear_repository_format(&candidate);
return 0;
}
@@ -1561,6 +1574,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
the_repository->repository_format_partial_clone =
repo_fmt.partial_clone;
repo_fmt.partial_clone = NULL;
+
+ the_repository->ref_format = repo_fmt.ref_format;
}
}
/*
@@ -1650,6 +1665,7 @@ void check_repository_format(struct repository_format *fmt)
repo_set_hash_algo(the_repository, fmt->hash_algo);
the_repository->repository_format_partial_clone =
xstrdup_or_null(fmt->partial_clone);
+ the_repository->ref_format = fmt->ref_format;
clear_repository_format(&repo_fmt);
}
@@ -24,4 +24,16 @@ test_expect_success 'invalid extensions.refFormat' '
grep "invalid value for '\''extensions.refFormat'\'': '\''bogus'\''" err
'
+test_expect_success 'extensions.refFormat=packed only' '
+ git init only-packed &&
+ (
+ cd only-packed &&
+ git config core.repositoryFormatVersion 1 &&
+ git config extensions.refFormat packed &&
+ test_commit A &&
+ test_path_exists .git/packed-refs &&
+ test_path_is_missing .git/refs/tags/A
+ )
+'
+
test_done