Merge branch 'jk/check-connected-with-alternates'
The tips of refs from the alternate object store can be used as starting point for reachability computation now. * jk/check-connected-with-alternates: check_everything_connected: assume alternate ref tips are valid object-store.h: move for_each_alternate_ref() from transport.h
This commit is contained in:
@ -182,6 +182,14 @@ explicitly.
|
|||||||
Pretend as if all objects mentioned by reflogs are listed on the
|
Pretend as if all objects mentioned by reflogs are listed on the
|
||||||
command line as `<commit>`.
|
command line as `<commit>`.
|
||||||
|
|
||||||
|
--alternate-refs::
|
||||||
|
Pretend as if all objects mentioned as ref tips of alternate
|
||||||
|
repositories were listed on the command line. An alternate
|
||||||
|
repository is any repository whose object directory is specified
|
||||||
|
in `objects/info/alternates`. The set of included objects may
|
||||||
|
be modified by `core.alternateRefsCommand`, etc. See
|
||||||
|
linkgit:git-config[1].
|
||||||
|
|
||||||
--single-worktree::
|
--single-worktree::
|
||||||
By default, all working trees will be examined by the
|
By default, all working trees will be examined by the
|
||||||
following options when there are more than one (see
|
following options when there are more than one (see
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "connect.h"
|
#include "connect.h"
|
||||||
#include "transport.h"
|
|
||||||
#include "string-list.h"
|
#include "string-list.h"
|
||||||
#include "sha1-array.h"
|
#include "sha1-array.h"
|
||||||
#include "connected.h"
|
#include "connected.h"
|
||||||
|
@ -80,6 +80,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
|
|||||||
argv_array_push(&rev_list.args, "--all");
|
argv_array_push(&rev_list.args, "--all");
|
||||||
}
|
}
|
||||||
argv_array_push(&rev_list.args, "--quiet");
|
argv_array_push(&rev_list.args, "--quiet");
|
||||||
|
argv_array_push(&rev_list.args, "--alternate-refs");
|
||||||
if (opt->progress)
|
if (opt->progress)
|
||||||
argv_array_pushf(&rev_list.args, "--progress=%s",
|
argv_array_pushf(&rev_list.args, "--progress=%s",
|
||||||
_("Checking connectivity"));
|
_("Checking connectivity"));
|
||||||
|
@ -33,6 +33,8 @@ void prepare_alt_odb(struct repository *r);
|
|||||||
char *compute_alternate_path(const char *path, struct strbuf *err);
|
char *compute_alternate_path(const char *path, struct strbuf *err);
|
||||||
typedef int alt_odb_fn(struct object_directory *, void *);
|
typedef int alt_odb_fn(struct object_directory *, void *);
|
||||||
int foreach_alt_odb(alt_odb_fn, void*);
|
int foreach_alt_odb(alt_odb_fn, void*);
|
||||||
|
typedef void alternate_ref_fn(const struct object_id *oid, void *);
|
||||||
|
void for_each_alternate_ref(alternate_ref_fn, void *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the directory to the on-disk alternates file; the new entry will also
|
* Add the directory to the on-disk alternates file; the new entry will also
|
||||||
|
29
revision.c
29
revision.c
@ -1554,6 +1554,32 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
|
|||||||
free_worktrees(worktrees);
|
free_worktrees(worktrees);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct add_alternate_refs_data {
|
||||||
|
struct rev_info *revs;
|
||||||
|
unsigned int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void add_one_alternate_ref(const struct object_id *oid,
|
||||||
|
void *vdata)
|
||||||
|
{
|
||||||
|
const char *name = ".alternate";
|
||||||
|
struct add_alternate_refs_data *data = vdata;
|
||||||
|
struct object *obj;
|
||||||
|
|
||||||
|
obj = get_reference(data->revs, name, oid, data->flags);
|
||||||
|
add_rev_cmdline(data->revs, obj, name, REV_CMD_REV, data->flags);
|
||||||
|
add_pending_object(data->revs, obj, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_alternate_refs_to_pending(struct rev_info *revs,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
struct add_alternate_refs_data data;
|
||||||
|
data.revs = revs;
|
||||||
|
data.flags = flags;
|
||||||
|
for_each_alternate_ref(add_one_alternate_ref, &data);
|
||||||
|
}
|
||||||
|
|
||||||
static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
|
static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
|
||||||
int exclude_parent)
|
int exclude_parent)
|
||||||
{
|
{
|
||||||
@ -1956,6 +1982,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
|||||||
!strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
|
!strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
|
||||||
!strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
|
!strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
|
||||||
!strcmp(arg, "--indexed-objects") ||
|
!strcmp(arg, "--indexed-objects") ||
|
||||||
|
!strcmp(arg, "--alternate-refs") ||
|
||||||
starts_with(arg, "--exclude=") ||
|
starts_with(arg, "--exclude=") ||
|
||||||
starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
|
starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
|
||||||
starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
|
starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
|
||||||
@ -2442,6 +2469,8 @@ static int handle_revision_pseudo_opt(const char *submodule,
|
|||||||
add_reflogs_to_pending(revs, *flags);
|
add_reflogs_to_pending(revs, *flags);
|
||||||
} else if (!strcmp(arg, "--indexed-objects")) {
|
} else if (!strcmp(arg, "--indexed-objects")) {
|
||||||
add_index_objects_to_pending(revs, *flags);
|
add_index_objects_to_pending(revs, *flags);
|
||||||
|
} else if (!strcmp(arg, "--alternate-refs")) {
|
||||||
|
add_alternate_refs_to_pending(revs, *flags);
|
||||||
} else if (!strcmp(arg, "--not")) {
|
} else if (!strcmp(arg, "--not")) {
|
||||||
*flags ^= UNINTERESTING | BOTTOM;
|
*flags ^= UNINTERESTING | BOTTOM;
|
||||||
} else if (!strcmp(arg, "--no-walk")) {
|
} else if (!strcmp(arg, "--no-walk")) {
|
||||||
|
97
sha1-file.c
97
sha1-file.c
@ -743,6 +743,103 @@ out:
|
|||||||
return ref_git;
|
return ref_git;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fill_alternate_refs_command(struct child_process *cmd,
|
||||||
|
const char *repo_path)
|
||||||
|
{
|
||||||
|
const char *value;
|
||||||
|
|
||||||
|
if (!git_config_get_value("core.alternateRefsCommand", &value)) {
|
||||||
|
cmd->use_shell = 1;
|
||||||
|
|
||||||
|
argv_array_push(&cmd->args, value);
|
||||||
|
argv_array_push(&cmd->args, repo_path);
|
||||||
|
} else {
|
||||||
|
cmd->git_cmd = 1;
|
||||||
|
|
||||||
|
argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path);
|
||||||
|
argv_array_push(&cmd->args, "for-each-ref");
|
||||||
|
argv_array_push(&cmd->args, "--format=%(objectname)");
|
||||||
|
|
||||||
|
if (!git_config_get_value("core.alternateRefsPrefixes", &value)) {
|
||||||
|
argv_array_push(&cmd->args, "--");
|
||||||
|
argv_array_split(&cmd->args, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->env = local_repo_env;
|
||||||
|
cmd->out = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_alternate_refs(const char *path,
|
||||||
|
alternate_ref_fn *cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||||
|
struct strbuf line = STRBUF_INIT;
|
||||||
|
FILE *fh;
|
||||||
|
|
||||||
|
fill_alternate_refs_command(&cmd, path);
|
||||||
|
|
||||||
|
if (start_command(&cmd))
|
||||||
|
return;
|
||||||
|
|
||||||
|
fh = xfdopen(cmd.out, "r");
|
||||||
|
while (strbuf_getline_lf(&line, fh) != EOF) {
|
||||||
|
struct object_id oid;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
if (parse_oid_hex(line.buf, &oid, &p) || *p) {
|
||||||
|
warning(_("invalid line while parsing alternate refs: %s"),
|
||||||
|
line.buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(&oid, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fh);
|
||||||
|
finish_command(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct alternate_refs_data {
|
||||||
|
alternate_ref_fn *fn;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int refs_from_alternate_cb(struct object_directory *e,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
size_t base_len;
|
||||||
|
struct alternate_refs_data *cb = data;
|
||||||
|
|
||||||
|
if (!strbuf_realpath(&path, e->path, 0))
|
||||||
|
goto out;
|
||||||
|
if (!strbuf_strip_suffix(&path, "/objects"))
|
||||||
|
goto out;
|
||||||
|
base_len = path.len;
|
||||||
|
|
||||||
|
/* Is this a git repository with refs? */
|
||||||
|
strbuf_addstr(&path, "/refs");
|
||||||
|
if (!is_directory(path.buf))
|
||||||
|
goto out;
|
||||||
|
strbuf_setlen(&path, base_len);
|
||||||
|
|
||||||
|
read_alternate_refs(path.buf, cb->fn, cb->data);
|
||||||
|
|
||||||
|
out:
|
||||||
|
strbuf_release(&path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void for_each_alternate_ref(alternate_ref_fn fn, void *data)
|
||||||
|
{
|
||||||
|
struct alternate_refs_data cb;
|
||||||
|
cb.fn = fn;
|
||||||
|
cb.data = data;
|
||||||
|
foreach_alt_odb(refs_from_alternate_cb, &cb);
|
||||||
|
}
|
||||||
|
|
||||||
int foreach_alt_odb(alt_odb_fn fn, void *cb)
|
int foreach_alt_odb(alt_odb_fn fn, void *cb)
|
||||||
{
|
{
|
||||||
struct object_directory *ent;
|
struct object_directory *ent;
|
||||||
|
27
t/perf/p5600-clone-reference.sh
Executable file
27
t/perf/p5600-clone-reference.sh
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='speed of clone --reference'
|
||||||
|
. ./perf-lib.sh
|
||||||
|
|
||||||
|
test_perf_default_repo
|
||||||
|
|
||||||
|
test_expect_success 'create shareable repository' '
|
||||||
|
git clone --bare . shared.git
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'advance base repository' '
|
||||||
|
# Do not use test_commit here; its test_tick will
|
||||||
|
# use some ancient hard-coded date. The resulting clock
|
||||||
|
# skew will cause pack-objects to traverse in a very
|
||||||
|
# sub-optimal order, skewing the results.
|
||||||
|
echo content >new-file-that-does-not-exist &&
|
||||||
|
git add new-file-that-does-not-exist &&
|
||||||
|
git commit -m "new commit"
|
||||||
|
'
|
||||||
|
|
||||||
|
test_perf 'clone --reference' '
|
||||||
|
rm -rf dst.git &&
|
||||||
|
git clone --no-local --bare --reference shared.git . dst.git
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
60
t/t5618-alternate-refs.sh
Executable file
60
t/t5618-alternate-refs.sh
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='test handling of --alternate-refs traversal'
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
# Avoid test_commit because we want a specific and known set of refs:
|
||||||
|
#
|
||||||
|
# base -- one
|
||||||
|
# \ \
|
||||||
|
# two -- merged
|
||||||
|
#
|
||||||
|
# where "one" and "two" are on separate refs, and "merged" is available only in
|
||||||
|
# the dependent child repository.
|
||||||
|
test_expect_success 'set up local refs' '
|
||||||
|
git checkout -b one &&
|
||||||
|
test_tick &&
|
||||||
|
git commit --allow-empty -m base &&
|
||||||
|
test_tick &&
|
||||||
|
git commit --allow-empty -m one &&
|
||||||
|
git checkout -b two HEAD^ &&
|
||||||
|
test_tick &&
|
||||||
|
git commit --allow-empty -m two
|
||||||
|
'
|
||||||
|
|
||||||
|
# We'll enter the child repository after it's set up since that's where
|
||||||
|
# all of the subsequent tests will want to run (and it's easy to forget a
|
||||||
|
# "-C child" and get nonsense results).
|
||||||
|
test_expect_success 'set up shared clone' '
|
||||||
|
git clone -s . child &&
|
||||||
|
cd child &&
|
||||||
|
git merge origin/one
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rev-list --alternate-refs' '
|
||||||
|
git rev-list --remotes=origin >expect &&
|
||||||
|
git rev-list --alternate-refs >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rev-list --not --alternate-refs' '
|
||||||
|
git rev-parse HEAD >expect &&
|
||||||
|
git rev-list HEAD --not --alternate-refs >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'limiting with alternateRefsPrefixes' '
|
||||||
|
test_config core.alternateRefsPrefixes refs/heads/one &&
|
||||||
|
git rev-list origin/one >expect &&
|
||||||
|
git rev-list --alternate-refs >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'log --source shows .alternate marker' '
|
||||||
|
git log --oneline --source --remotes=origin >expect.orig &&
|
||||||
|
sed "s/origin.* /.alternate /" <expect.orig >expect &&
|
||||||
|
git log --oneline --source --alternate-refs >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
97
transport.c
97
transport.c
@ -1380,100 +1380,3 @@ char *transport_anonymize_url(const char *url)
|
|||||||
literal_copy:
|
literal_copy:
|
||||||
return xstrdup(url);
|
return xstrdup(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_alternate_refs_command(struct child_process *cmd,
|
|
||||||
const char *repo_path)
|
|
||||||
{
|
|
||||||
const char *value;
|
|
||||||
|
|
||||||
if (!git_config_get_value("core.alternateRefsCommand", &value)) {
|
|
||||||
cmd->use_shell = 1;
|
|
||||||
|
|
||||||
argv_array_push(&cmd->args, value);
|
|
||||||
argv_array_push(&cmd->args, repo_path);
|
|
||||||
} else {
|
|
||||||
cmd->git_cmd = 1;
|
|
||||||
|
|
||||||
argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path);
|
|
||||||
argv_array_push(&cmd->args, "for-each-ref");
|
|
||||||
argv_array_push(&cmd->args, "--format=%(objectname)");
|
|
||||||
|
|
||||||
if (!git_config_get_value("core.alternateRefsPrefixes", &value)) {
|
|
||||||
argv_array_push(&cmd->args, "--");
|
|
||||||
argv_array_split(&cmd->args, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->env = local_repo_env;
|
|
||||||
cmd->out = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_alternate_refs(const char *path,
|
|
||||||
alternate_ref_fn *cb,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
|
||||||
struct strbuf line = STRBUF_INIT;
|
|
||||||
FILE *fh;
|
|
||||||
|
|
||||||
fill_alternate_refs_command(&cmd, path);
|
|
||||||
|
|
||||||
if (start_command(&cmd))
|
|
||||||
return;
|
|
||||||
|
|
||||||
fh = xfdopen(cmd.out, "r");
|
|
||||||
while (strbuf_getline_lf(&line, fh) != EOF) {
|
|
||||||
struct object_id oid;
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
if (parse_oid_hex(line.buf, &oid, &p) || *p) {
|
|
||||||
warning(_("invalid line while parsing alternate refs: %s"),
|
|
||||||
line.buf);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(&oid, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fh);
|
|
||||||
finish_command(&cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct alternate_refs_data {
|
|
||||||
alternate_ref_fn *fn;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int refs_from_alternate_cb(struct object_directory *e,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
struct strbuf path = STRBUF_INIT;
|
|
||||||
size_t base_len;
|
|
||||||
struct alternate_refs_data *cb = data;
|
|
||||||
|
|
||||||
if (!strbuf_realpath(&path, e->path, 0))
|
|
||||||
goto out;
|
|
||||||
if (!strbuf_strip_suffix(&path, "/objects"))
|
|
||||||
goto out;
|
|
||||||
base_len = path.len;
|
|
||||||
|
|
||||||
/* Is this a git repository with refs? */
|
|
||||||
strbuf_addstr(&path, "/refs");
|
|
||||||
if (!is_directory(path.buf))
|
|
||||||
goto out;
|
|
||||||
strbuf_setlen(&path, base_len);
|
|
||||||
|
|
||||||
read_alternate_refs(path.buf, cb->fn, cb->data);
|
|
||||||
|
|
||||||
out:
|
|
||||||
strbuf_release(&path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void for_each_alternate_ref(alternate_ref_fn fn, void *data)
|
|
||||||
{
|
|
||||||
struct alternate_refs_data cb;
|
|
||||||
cb.fn = fn;
|
|
||||||
cb.data = data;
|
|
||||||
foreach_alt_odb(refs_from_alternate_cb, &cb);
|
|
||||||
}
|
|
||||||
|
@ -262,6 +262,4 @@ int transport_refs_pushed(struct ref *ref);
|
|||||||
void transport_print_push_status(const char *dest, struct ref *refs,
|
void transport_print_push_status(const char *dest, struct ref *refs,
|
||||||
int verbose, int porcelain, unsigned int *reject_reasons);
|
int verbose, int porcelain, unsigned int *reject_reasons);
|
||||||
|
|
||||||
typedef void alternate_ref_fn(const struct object_id *oid, void *);
|
|
||||||
void for_each_alternate_ref(alternate_ref_fn, void *);
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user