Browse Source

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
maint
Junio C Hamano 6 years ago
parent
commit
68e65ded5b
  1. 8
      Documentation/rev-list-options.txt
  2. 1
      builtin/receive-pack.c
  3. 1
      connected.c
  4. 2
      object-store.h
  5. 29
      revision.c
  6. 97
      sha1-file.c
  7. 27
      t/perf/p5600-clone-reference.sh
  8. 60
      t/t5618-alternate-refs.sh
  9. 97
      transport.c
  10. 2
      transport.h

8
Documentation/rev-list-options.txt

@ -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

1
builtin/receive-pack.c

@ -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"

1
connected.c

@ -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"));

2
object-store.h

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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);
}

2
transport.h

@ -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

Loading…
Cancel
Save