Merge branch 'ps/odb-alternates-at-creation' into jch
The setup of alternates has been deferred to object database
creation time during clone, which drops the unused ad-hoc alternate
writing API, simplifying the object database backend interface.
* ps/odb-alternates-at-creation:
odb/source: remove the ability to write alternates
builtin/clone: write alternates via `odb_create_on_disk()`
odb/source: support writing alternates when creating the database
builtin/clone: move setup of alternates for non-shared local clones
builtin/clone: move setup of alternates for shared local clones
builtin/clone: refactor handling of "--reference{,-if-able}"
builtin/clone: move around `setup_reference()`
builtin/clone: defer setup of the object database
jch
commit
7dfd47023a
108
builtin/clone.c
108
builtin/clone.c
|
|
@ -154,24 +154,26 @@ static char *get_repo_path(const char *repo, int *is_bundle)
|
|||
return canon;
|
||||
}
|
||||
|
||||
static int add_one_reference(struct string_list_item *item, void *cb_data)
|
||||
struct add_one_alternate_data {
|
||||
struct strvec *alternates;
|
||||
int required;
|
||||
};
|
||||
|
||||
static int add_one_alternate(struct string_list_item *item, void *cb_data)
|
||||
{
|
||||
struct add_one_alternate_data *data = cb_data;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
int *required = cb_data;
|
||||
char *ref_git = compute_alternate_path(item->string, &err);
|
||||
|
||||
if (!ref_git) {
|
||||
if (*required)
|
||||
if (data->required)
|
||||
die("%s", err.buf);
|
||||
else
|
||||
fprintf(stderr,
|
||||
_("info: Could not add alternate for '%s': %s\n"),
|
||||
item->string, err.buf);
|
||||
} else {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
strbuf_addf(&sb, "%s/objects", ref_git);
|
||||
odb_add_to_alternates_file(the_repository->objects, sb.buf);
|
||||
strbuf_release(&sb);
|
||||
strvec_pushf(data->alternates, "%s/objects", ref_git);
|
||||
}
|
||||
|
||||
strbuf_release(&err);
|
||||
|
|
@ -179,17 +181,7 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void setup_reference(void)
|
||||
{
|
||||
int required = 1;
|
||||
for_each_string_list(&option_required_reference,
|
||||
add_one_reference, &required);
|
||||
required = 0;
|
||||
for_each_string_list(&option_optional_reference,
|
||||
add_one_reference, &required);
|
||||
}
|
||||
|
||||
static void copy_alternates(struct strbuf *src, const char *src_repo)
|
||||
static void read_alternates(struct strvec *alternates, const char *src_repo)
|
||||
{
|
||||
/*
|
||||
* Read from the source objects/info/alternates file
|
||||
|
|
@ -203,29 +195,70 @@ static void copy_alternates(struct strbuf *src, const char *src_repo)
|
|||
* to turn entries with paths relative to the original
|
||||
* absolute, so that they can be used in the new repository.
|
||||
*/
|
||||
FILE *in = xfopen(src->buf, "r");
|
||||
FILE *in;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
|
||||
strbuf_addf(&path, "%s/objects/info/alternates", src_repo);
|
||||
|
||||
in = fopen(path.buf, "r");
|
||||
if (!in) {
|
||||
if (errno == ENOENT)
|
||||
goto out;
|
||||
die_errno("could not read alternates file '%s'", path.buf);
|
||||
}
|
||||
|
||||
while (strbuf_getline(&line, in) != EOF) {
|
||||
char *abs_path;
|
||||
if (!line.len || line.buf[0] == '#')
|
||||
continue;
|
||||
if (is_absolute_path(line.buf)) {
|
||||
odb_add_to_alternates_file(the_repository->objects,
|
||||
line.buf);
|
||||
strvec_push(alternates, line.buf);
|
||||
continue;
|
||||
}
|
||||
abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
|
||||
if (!normalize_path_copy(abs_path, abs_path))
|
||||
odb_add_to_alternates_file(the_repository->objects,
|
||||
abs_path);
|
||||
strvec_push(alternates, abs_path);
|
||||
else
|
||||
warning("skipping invalid relative alternate: %s/%s",
|
||||
src_repo, line.buf);
|
||||
free(abs_path);
|
||||
}
|
||||
|
||||
out:
|
||||
strbuf_release(&path);
|
||||
strbuf_release(&line);
|
||||
fclose(in);
|
||||
if (in)
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
static void collect_alternates(struct strvec *alternates,
|
||||
const char *src_repo, bool is_local)
|
||||
{
|
||||
if (option_required_reference.nr || option_optional_reference.nr) {
|
||||
struct add_one_alternate_data data = {
|
||||
.alternates = alternates,
|
||||
.required = 1,
|
||||
};
|
||||
|
||||
for_each_string_list(&option_required_reference,
|
||||
add_one_alternate, &data);
|
||||
data.required = 0;
|
||||
for_each_string_list(&option_optional_reference,
|
||||
add_one_alternate, &data);
|
||||
}
|
||||
|
||||
if (is_local) {
|
||||
struct strbuf commondir = STRBUF_INIT;
|
||||
|
||||
get_common_dir(&commondir, src_repo);
|
||||
if (option_shared)
|
||||
strvec_pushf(alternates, "%s/objects", commondir.buf);
|
||||
else
|
||||
read_alternates(alternates, commondir.buf);
|
||||
|
||||
strbuf_release(&commondir);
|
||||
}
|
||||
}
|
||||
|
||||
static void mkdir_if_missing(const char *pathname, mode_t mode)
|
||||
|
|
@ -301,11 +334,9 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Files that cannot be copied bit-for-bit... */
|
||||
if (!fspathcmp(iter->relative_path, "info/alternates")) {
|
||||
copy_alternates(src, src_repo);
|
||||
/* Alternates were already handled earlier. */
|
||||
if (!fspathcmp(iter->relative_path, "info/alternates"))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unlink(dest->buf) && errno != ENOENT)
|
||||
die_errno(_("failed to unlink '%s'"), dest->buf);
|
||||
|
|
@ -349,13 +380,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
|
|||
|
||||
static void clone_local(const char *src_repo, const char *dest_repo)
|
||||
{
|
||||
if (option_shared) {
|
||||
struct strbuf alt = STRBUF_INIT;
|
||||
get_common_dir(&alt, src_repo);
|
||||
strbuf_addstr(&alt, "/objects");
|
||||
odb_add_to_alternates_file(the_repository->objects, alt.buf);
|
||||
strbuf_release(&alt);
|
||||
} else {
|
||||
if (!option_shared) {
|
||||
struct strbuf src = STRBUF_INIT;
|
||||
struct strbuf dest = STRBUF_INIT;
|
||||
get_common_dir(&src, src_repo);
|
||||
|
|
@ -999,6 +1024,7 @@ int cmd_clone(int argc,
|
|||
N_("uri"), N_("a URI for downloading bundles before fetching from origin remote")),
|
||||
OPT_END()
|
||||
};
|
||||
struct strvec alternates = STRVEC_INIT;
|
||||
|
||||
const char * const builtin_clone_usage[] = {
|
||||
N_("git clone [<options>] [--] <repo> [<dir>]"),
|
||||
|
|
@ -1184,11 +1210,14 @@ int cmd_clone(int argc,
|
|||
* database. We do not yet know about the object format of the
|
||||
* repository, and reference backends may persist that information into
|
||||
* their on-disk data structures.
|
||||
*
|
||||
* Furthermore, we skip initializing the object database so that we can
|
||||
* first resolve potential alternates before creating it.
|
||||
*/
|
||||
init_db(the_repository, git_dir, real_git_dir, work_tree, option_template,
|
||||
GIT_HASH_UNKNOWN, ref_storage_format, NULL,
|
||||
do_not_override_repo_unix_permissions,
|
||||
INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
|
||||
INIT_DB_QUIET | INIT_DB_SKIP_REFDB | INIT_DB_SKIP_ODB);
|
||||
|
||||
if (real_git_dir) {
|
||||
free((char *)git_dir);
|
||||
|
|
@ -1311,9 +1340,6 @@ int cmd_clone(int argc,
|
|||
strbuf_reset(&key);
|
||||
}
|
||||
|
||||
if (option_required_reference.nr || option_optional_reference.nr)
|
||||
setup_reference();
|
||||
|
||||
remote = remote_get_early(remote_name);
|
||||
|
||||
if (!option_rev)
|
||||
|
|
@ -1342,6 +1368,9 @@ int cmd_clone(int argc,
|
|||
if (option_local > 0 && !is_local)
|
||||
warning(_("--local is ignored"));
|
||||
|
||||
collect_alternates(&alternates, path, is_local);
|
||||
create_object_database(the_repository, &alternates);
|
||||
|
||||
transport = transport_get(remote, path ? path : remote->url.v[0]);
|
||||
transport_set_verbosity(transport, option_verbosity, option_progress);
|
||||
transport->family = family;
|
||||
|
|
@ -1637,6 +1666,7 @@ int cmd_clone(int argc,
|
|||
string_list_clear(&option_not, 0);
|
||||
string_list_clear(&option_config, 0);
|
||||
string_list_clear(&server_options, 0);
|
||||
strvec_clear(&alternates);
|
||||
|
||||
free(remote_name);
|
||||
strbuf_release(&reflog_msg);
|
||||
|
|
|
|||
9
odb.c
9
odb.c
|
|
@ -238,15 +238,6 @@ static struct odb_source *odb_add_alternate_recursively(struct object_database *
|
|||
return alternate;
|
||||
}
|
||||
|
||||
void odb_add_to_alternates_file(struct object_database *odb,
|
||||
const char *dir)
|
||||
{
|
||||
int ret = odb_source_write_alternate(odb->sources, dir);
|
||||
if (ret < 0)
|
||||
die(NULL);
|
||||
odb_add_alternate_recursively(odb, dir, 0);
|
||||
}
|
||||
|
||||
struct odb_source *odb_add_to_alternates_memory(struct object_database *odb,
|
||||
const char *dir)
|
||||
{
|
||||
|
|
|
|||
7
odb.h
7
odb.h
|
|
@ -265,13 +265,6 @@ int odb_mkstemp(struct object_database *odb,
|
|||
*/
|
||||
int odb_has_alternates(struct object_database *odb);
|
||||
|
||||
/*
|
||||
* Add the directory to the on-disk alternates file; the new entry will also
|
||||
* take effect in the current process.
|
||||
*/
|
||||
void odb_add_to_alternates_file(struct object_database *odb,
|
||||
const char *dir);
|
||||
|
||||
/*
|
||||
* Add the directory to the in-memory list of alternate sources (along with any
|
||||
* recursive alternates it points to), but do not modify the on-disk alternates
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "run-command.h"
|
||||
#include "strbuf.h"
|
||||
#include "string-list.h"
|
||||
#include "strmap.h"
|
||||
#include "strvec.h"
|
||||
#include "tree.h"
|
||||
#include "write-or-die.h"
|
||||
|
|
@ -51,9 +52,14 @@ static void odb_source_files_close(struct odb_source *source)
|
|||
odb_source_close(&files->packed->base);
|
||||
}
|
||||
|
||||
static int odb_source_files_create_on_disk(struct odb_source *source)
|
||||
static int odb_source_files_create_on_disk(struct odb_source *source,
|
||||
const struct odb_create_on_disk_options *opts)
|
||||
{
|
||||
struct lock_file alternates_lock = LOCK_INIT;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
struct strset seen = STRSET_INIT;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
int ret;
|
||||
|
||||
safe_create_dir(source->odb->repo, source->path, 1);
|
||||
|
||||
|
|
@ -64,8 +70,74 @@ static int odb_source_files_create_on_disk(struct odb_source *source)
|
|||
strbuf_addf(&path, "%s/info", source->path);
|
||||
safe_create_dir(source->odb->repo, path.buf, 1);
|
||||
|
||||
if (opts->alternates && opts->alternates->nr) {
|
||||
FILE *alternates, *orig;
|
||||
|
||||
strbuf_reset(&path);
|
||||
strbuf_addf(&path, "%s/info/alternates", source->path);
|
||||
|
||||
repo_hold_lock_file_for_update(source->odb->repo, &alternates_lock,
|
||||
path.buf, LOCK_DIE_ON_ERROR);
|
||||
|
||||
alternates = fdopen_lock_file(&alternates_lock, "w");
|
||||
if (!alternates) {
|
||||
ret = error_errno(_("unable to fdopen alternates lockfile"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The alternates file may already exist, e.g. when it has been
|
||||
* seeded from a template directory. Read any preexisting
|
||||
* entries so that we don't end up writing duplicates.
|
||||
*/
|
||||
orig = fopen(path.buf, "r");
|
||||
if (orig) {
|
||||
while (strbuf_getline(&line, orig) != EOF) {
|
||||
strset_add(&seen, line.buf);
|
||||
fprintf(alternates, "%s\n", line.buf);
|
||||
}
|
||||
|
||||
if (ferror(orig)) {
|
||||
ret = error_errno(_("unable to read alternates file"));
|
||||
fclose(orig);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fclose(orig);
|
||||
} else if (errno != ENOENT) {
|
||||
ret = error_errno(_("unable to read alternates file"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < opts->alternates->nr; i++) {
|
||||
const char *alternate = opts->alternates->v[i];
|
||||
if (!strset_add(&seen, alternate))
|
||||
continue;
|
||||
fprintf(alternates, "%s\n", alternate);
|
||||
}
|
||||
|
||||
if (ferror(alternates)) {
|
||||
ret = error_errno(_("unable to write alternates file"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (commit_lock_file(&alternates_lock)) {
|
||||
ret = error_errno(_("unable to commit alternates file"));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reprepare the object database to activate alternates. */
|
||||
odb_reprepare(source->odb);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
rollback_lock_file(&alternates_lock);
|
||||
strbuf_release(&line);
|
||||
strbuf_release(&path);
|
||||
return 0;
|
||||
strset_clear(&seen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void odb_source_files_prepare(struct odb_source *source,
|
||||
|
|
@ -251,59 +323,6 @@ static int odb_source_files_read_alternates(struct odb_source *source,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int odb_source_files_write_alternate(struct odb_source *source,
|
||||
const char *alternate)
|
||||
{
|
||||
struct lock_file lock = LOCK_INIT;
|
||||
char *path = xstrfmt("%s/%s", source->path, "info/alternates");
|
||||
FILE *in, *out;
|
||||
int found = 0;
|
||||
int ret;
|
||||
|
||||
repo_hold_lock_file_for_update(source->odb->repo, &lock, path,
|
||||
LOCK_DIE_ON_ERROR);
|
||||
out = fdopen_lock_file(&lock, "w");
|
||||
if (!out) {
|
||||
ret = error_errno(_("unable to fdopen alternates lockfile"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
in = fopen(path, "r");
|
||||
if (in) {
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
|
||||
while (strbuf_getline(&line, in) != EOF) {
|
||||
if (!strcmp(alternate, line.buf)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
fprintf_or_die(out, "%s\n", line.buf);
|
||||
}
|
||||
|
||||
strbuf_release(&line);
|
||||
fclose(in);
|
||||
} else if (errno != ENOENT) {
|
||||
ret = error_errno(_("unable to read alternates file"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
rollback_lock_file(&lock);
|
||||
} else {
|
||||
fprintf_or_die(out, "%s\n", alternate);
|
||||
if (commit_lock_file(&lock)) {
|
||||
ret = error_errno(_("unable to move new alternates file into place"));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int too_many_loose_objects(struct odb_source_files *files, int limit)
|
||||
{
|
||||
unsigned long loose_count;
|
||||
|
|
@ -934,7 +953,6 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
|
|||
files->base.write_object_stream = odb_source_files_write_object_stream;
|
||||
files->base.begin_transaction = odb_source_files_begin_transaction;
|
||||
files->base.read_alternates = odb_source_files_read_alternates;
|
||||
files->base.write_alternate = odb_source_files_write_alternate;
|
||||
files->base.optimize = odb_source_files_optimize;
|
||||
files->base.optimize_required = odb_source_files_optimize_required;
|
||||
files->base.generate_pack = odb_source_files_generate_pack;
|
||||
|
|
|
|||
|
|
@ -327,12 +327,6 @@ static int odb_source_inmemory_read_alternates(struct odb_source *source UNUSED,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int odb_source_inmemory_write_alternate(struct odb_source *source UNUSED,
|
||||
const char *alternate UNUSED)
|
||||
{
|
||||
return error("in-memory source does not support alternates");
|
||||
}
|
||||
|
||||
static void odb_source_inmemory_close(struct odb_source *source UNUSED)
|
||||
{
|
||||
}
|
||||
|
|
@ -389,7 +383,6 @@ struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)
|
|||
source->base.freshen_object = odb_source_inmemory_freshen_object;
|
||||
source->base.begin_transaction = odb_source_inmemory_begin_transaction;
|
||||
source->base.read_alternates = odb_source_inmemory_read_alternates;
|
||||
source->base.write_alternate = odb_source_inmemory_write_alternate;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -990,12 +990,6 @@ static int odb_source_loose_read_alternates(struct odb_source *source UNUSED,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int odb_source_loose_write_alternate(struct odb_source *source UNUSED,
|
||||
const char *alternate UNUSED)
|
||||
{
|
||||
return error("loose source does not support alternates");
|
||||
}
|
||||
|
||||
static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
|
||||
{
|
||||
oidtree_clear(loose->cache);
|
||||
|
|
@ -1060,7 +1054,6 @@ struct odb_source_loose *odb_source_loose_new(struct object_database *odb,
|
|||
loose->base.write_object_stream = odb_source_loose_write_object_stream;
|
||||
loose->base.begin_transaction = odb_source_loose_begin_transaction;
|
||||
loose->base.read_alternates = odb_source_loose_read_alternates;
|
||||
loose->base.write_alternate = odb_source_loose_write_alternate;
|
||||
|
||||
if (!is_absolute_path(loose->base.path))
|
||||
chdir_notify_register(odb_source_loose_reparent, loose);
|
||||
|
|
|
|||
|
|
@ -658,12 +658,6 @@ static int odb_source_packed_read_alternates(struct odb_source *source UNUSED,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int odb_source_packed_write_alternate(struct odb_source *source UNUSED,
|
||||
const char *alternate UNUSED)
|
||||
{
|
||||
return error("packed backend cannot write alternates");
|
||||
}
|
||||
|
||||
void (*report_garbage)(unsigned seen_bits, const char *path);
|
||||
|
||||
static void report_helper(const struct string_list *list,
|
||||
|
|
@ -878,7 +872,6 @@ struct odb_source_packed *odb_source_packed_new(struct object_database *odb,
|
|||
packed->base.write_object_stream = odb_source_packed_write_object_stream;
|
||||
packed->base.begin_transaction = odb_source_packed_begin_transaction;
|
||||
packed->base.read_alternates = odb_source_packed_read_alternates;
|
||||
packed->base.write_alternate = odb_source_packed_write_alternate;
|
||||
|
||||
if (!is_absolute_path(path))
|
||||
chdir_notify_register(odb_source_packed_reparent, packed);
|
||||
|
|
|
|||
43
odb/source.h
43
odb/source.h
|
|
@ -37,6 +37,15 @@ struct odb_stream;
|
|||
struct strbuf;
|
||||
struct strvec;
|
||||
|
||||
struct odb_create_on_disk_options {
|
||||
/*
|
||||
* Alternates that shall be written into the newly created object
|
||||
* database. Whether or not this option can be handled is specific to
|
||||
* the backend.
|
||||
*/
|
||||
const struct strvec *alternates;
|
||||
};
|
||||
|
||||
/*
|
||||
* The source is the part of the object database that stores the actual
|
||||
* objects. It thus encapsulates the logic to read and write the specific
|
||||
|
|
@ -107,7 +116,8 @@ struct odb_source {
|
|||
* This callback may be NULL in case the source does not need any
|
||||
* on-disk setup.
|
||||
*/
|
||||
int (*create_on_disk)(struct odb_source *source);
|
||||
int (*create_on_disk)(struct odb_source *source,
|
||||
const struct odb_create_on_disk_options *opts);
|
||||
|
||||
/*
|
||||
* This callback is expected to prepare the source so that it becomes
|
||||
|
|
@ -281,19 +291,6 @@ struct odb_source {
|
|||
int (*read_alternates)(struct odb_source *source,
|
||||
struct strvec *out);
|
||||
|
||||
/*
|
||||
* This callback is expected to persist the singular alternate passed
|
||||
* to it into its list of alternates. Any pre-existing alternates are
|
||||
* expected to remain active. Subsequent calls to `read_alternates` are
|
||||
* thus expected to yield the pre-existing list of alternates plus the
|
||||
* newly added alternate appended to its end.
|
||||
*
|
||||
* The callback is expected to return 0 on success, a negative error
|
||||
* code otherwise.
|
||||
*/
|
||||
int (*write_alternate)(struct odb_source *source,
|
||||
const char *alternate);
|
||||
|
||||
/*
|
||||
* This callback is expected to optimize the object database source.
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
|
|
@ -378,11 +375,12 @@ static inline void odb_source_close(struct odb_source *source)
|
|||
* Create on-disk data structures that are required for this source to operate
|
||||
* correctly. Returns 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
static inline int odb_source_create_on_disk(struct odb_source *source)
|
||||
static inline int odb_source_create_on_disk(struct odb_source *source,
|
||||
const struct odb_create_on_disk_options *opts)
|
||||
{
|
||||
if (!source->create_on_disk)
|
||||
return 0;
|
||||
return source->create_on_disk(source);
|
||||
return source->create_on_disk(source, opts);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -534,19 +532,6 @@ static inline int odb_source_read_alternates(struct odb_source *source,
|
|||
return source->read_alternates(source, out);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write and persist a new alternate object database source for the given
|
||||
* source. Any preexisting alternates are expected to stay valid, and the new
|
||||
* alternate shall be appended to the end of the list.
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
static inline int odb_source_write_alternate(struct odb_source *source,
|
||||
const char *alternate)
|
||||
{
|
||||
return source->write_alternate(source, alternate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new transaction that can be used to write objects into a temporary
|
||||
* staging area. The objects will only be persisted when the transaction is
|
||||
|
|
|
|||
15
setup.c
15
setup.c
|
|
@ -2663,8 +2663,13 @@ static int create_default_files(struct repository *repo,
|
|||
return reinit;
|
||||
}
|
||||
|
||||
static void create_object_database(struct repository *repo)
|
||||
void create_object_database(struct repository *repo,
|
||||
const struct strvec *alternates)
|
||||
{
|
||||
struct odb_create_on_disk_options opts = {
|
||||
.alternates = alternates,
|
||||
};
|
||||
|
||||
/*
|
||||
* Create the "objects" directory in the common directory. This is done
|
||||
* so that the repository can be discovered regardless of the backend
|
||||
|
|
@ -2684,7 +2689,7 @@ static void create_object_database(struct repository *repo)
|
|||
|
||||
repo->objects = odb_new(repo, ODB_NEW_HONOR_ENV);
|
||||
|
||||
if (odb_source_create_on_disk(repo->objects->sources) < 0)
|
||||
if (odb_source_create_on_disk(repo->objects->sources, &opts) < 0)
|
||||
die(_("failed creating object database"));
|
||||
}
|
||||
|
||||
|
|
@ -2845,7 +2850,8 @@ int init_db(struct repository *repo,
|
|||
const char *template_dir, int hash,
|
||||
enum ref_storage_format ref_storage_format,
|
||||
const char *initial_branch,
|
||||
int init_shared_repository, unsigned int flags)
|
||||
int init_shared_repository,
|
||||
enum init_db_flags flags)
|
||||
{
|
||||
int reinit;
|
||||
int exist_ok = flags & INIT_DB_EXIST_OK;
|
||||
|
|
@ -2919,7 +2925,8 @@ int init_db(struct repository *repo,
|
|||
|
||||
if (!(flags & INIT_DB_SKIP_REFDB))
|
||||
create_reference_database(repo, initial_branch, flags & INIT_DB_QUIET);
|
||||
create_object_database(repo);
|
||||
if (!(flags & INIT_DB_SKIP_ODB))
|
||||
create_object_database(repo, NULL);
|
||||
|
||||
startup_info->have_repository = 1;
|
||||
|
||||
|
|
|
|||
15
setup.h
15
setup.h
|
|
@ -257,9 +257,12 @@ int apply_repository_format(struct repository *repo,
|
|||
|
||||
const char *get_template_dir(const char *option_template);
|
||||
|
||||
#define INIT_DB_QUIET (1 << 0)
|
||||
#define INIT_DB_EXIST_OK (1 << 1)
|
||||
#define INIT_DB_SKIP_REFDB (1 << 2)
|
||||
enum init_db_flags {
|
||||
INIT_DB_QUIET = (1 << 0),
|
||||
INIT_DB_EXIST_OK = (1 << 1),
|
||||
INIT_DB_SKIP_REFDB = (1 << 2),
|
||||
INIT_DB_SKIP_ODB = (1 << 3),
|
||||
};
|
||||
|
||||
int init_db(struct repository *repo,
|
||||
const char *git_dir,
|
||||
|
|
@ -267,13 +270,15 @@ int init_db(struct repository *repo,
|
|||
const char *worktree,
|
||||
const char *template_dir, int hash_algo,
|
||||
enum ref_storage_format ref_storage_format,
|
||||
const char *initial_branch, int init_shared_repository,
|
||||
unsigned int flags);
|
||||
const char *initial_branch,
|
||||
int init_shared_repository,
|
||||
enum init_db_flags flags);
|
||||
void initialize_repository_version(struct repository *repo,
|
||||
int hash_algo,
|
||||
enum ref_storage_format ref_storage_format,
|
||||
int reinit);
|
||||
void create_reference_database(struct repository *repo, const char *initial_branch, int quiet);
|
||||
void create_object_database(struct repository *repo, const struct strvec *alternates);
|
||||
|
||||
/*
|
||||
* NOTE NOTE NOTE!!
|
||||
|
|
|
|||
|
|
@ -383,4 +383,29 @@ test_expect_success 'dissociate from repo with commit graph' '
|
|||
git clone --no-local --reference graph.git --dissociate orig clone
|
||||
'
|
||||
|
||||
test_expect_success 'local clone from linked worktree carries over alternates' '
|
||||
rm -fr base derived derived-wt dst expect &&
|
||||
git init base &&
|
||||
test_commit -C base one &&
|
||||
git clone --shared base derived &&
|
||||
git -C derived worktree add ../derived-wt &&
|
||||
git clone derived-wt dst &&
|
||||
echo "$(pwd)/base/.git/objects" >expect &&
|
||||
test_cmp expect dst/.git/objects/info/alternates &&
|
||||
git -C dst fsck
|
||||
'
|
||||
|
||||
test_expect_success 'local clone from linked worktree resolves relative alternates' '
|
||||
rm -fr base derived derived-wt dst expect &&
|
||||
git init base &&
|
||||
test_commit -C base one &&
|
||||
git clone --shared base derived &&
|
||||
echo "../../../base/.git/objects" >derived/.git/objects/info/alternates &&
|
||||
git -C derived worktree add ../derived-wt &&
|
||||
git clone derived-wt dst &&
|
||||
echo "$(pwd)/base/.git/objects" >expect &&
|
||||
test_cmp expect dst/.git/objects/info/alternates &&
|
||||
git -C dst fsck
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
|||
Loading…
Reference in New Issue