Merge branch 'jc/alternate-push'

* jc/alternate-push:
  push: receiver end advertises refs from alternate repositories
  push: prepare sender to receive extended ref information from the receiver
  receive-pack: make it a builtin
  is_directory(): a generic helper function
This commit is contained in:
Shawn O. Pearce 2008-09-25 09:39:24 -07:00
Родитель 6ef1daf772 d79796bcf0
Коммит 1ad6d46235
14 изменённых файлов: 114 добавлений и 34 удалений

Просмотреть файл

@ -294,7 +294,6 @@ PROGRAMS += git-mktag$X
PROGRAMS += git-mktree$X
PROGRAMS += git-pack-redundant$X
PROGRAMS += git-patch-id$X
PROGRAMS += git-receive-pack$X
PROGRAMS += git-send-pack$X
PROGRAMS += git-shell$X
PROGRAMS += git-show-index$X
@ -546,6 +545,7 @@ BUILTIN_OBJS += builtin-prune-packed.o
BUILTIN_OBJS += builtin-prune.o
BUILTIN_OBJS += builtin-push.o
BUILTIN_OBJS += builtin-read-tree.o
BUILTIN_OBJS += builtin-receive-pack.o
BUILTIN_OBJS += builtin-reflog.o
BUILTIN_OBJS += builtin-remote.o
BUILTIN_OBJS += builtin-rerere.o

Просмотреть файл

@ -1,5 +1,16 @@
#include "cache.h"
/*
* Do not use this for inspecting *tracked* content. When path is a
* symlink to a directory, we do not want to say it is a directory when
* dealing with tracked content in the working tree.
*/
int is_directory(const char *path)
{
struct stat st;
return (!stat(path, &st) && S_ISDIR(st.st_mode));
}
/* We allow "recursive" symbolic links. Only within reason, though. */
#define MAXDEPTH 5
@ -17,7 +28,7 @@ const char *make_absolute_path(const char *path)
die ("Too long path: %.*s", 60, path);
while (depth--) {
if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
if (!is_directory(buf)) {
char *last_slash = strrchr(buf, '/');
if (last_slash) {
*last_slash = '\0';

Просмотреть файл

@ -77,7 +77,7 @@ static char *get_repo_path(const char *repo, int *is_bundle)
for (i = 0; i < ARRAY_SIZE(suffix); i++) {
const char *path;
path = mkpath("%s%s", repo, suffix[i]);
if (!stat(path, &st) && S_ISDIR(st.st_mode)) {
if (is_directory(path)) {
*is_bundle = 0;
return xstrdup(make_nonrelative_path(path));
}
@ -140,13 +140,6 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
return xstrndup(start, end - start);
}
static int is_directory(const char *path)
{
struct stat buf;
return !stat(path, &buf) && S_ISDIR(buf.st_mode);
}
static void strip_trailing_slashes(char *dir)
{
char *end = dir + strlen(dir);

Просмотреть файл

@ -735,7 +735,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
conn = git_connect(fd, (char *)dest, args.uploadpack,
args.verbose ? CONNECT_VERBOSE : 0);
if (conn) {
get_remote_heads(fd[0], &ref, 0, NULL, 0);
get_remote_heads(fd[0], &ref, 0, NULL, 0, NULL);
ref = fetch_pack(&args, fd, conn, ref, dest, nr_heads, heads, NULL);
close(fd[0]);

Просмотреть файл

@ -6,6 +6,8 @@
#include "exec_cmd.h"
#include "commit.h"
#include "object.h"
#include "remote.h"
#include "transport.h"
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
@ -462,14 +464,48 @@ static int delete_only(struct command *cmd)
return 1;
}
int main(int argc, char **argv)
static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
{
char *other = xstrdup(make_absolute_path(e->base));
size_t len = strlen(other);
struct remote *remote;
struct transport *transport;
const struct ref *extra;
while (other[len-1] == '/')
other[--len] = '\0';
if (len < 8 || memcmp(other + len - 8, "/objects", 8))
return 0;
/* Is this a git repository with refs? */
memcpy(other + len - 8, "/refs", 6);
if (!is_directory(other))
return 0;
other[len - 8] = '\0';
remote = remote_get(other);
transport = transport_get(remote, other);
for (extra = transport_get_remote_refs(transport);
extra;
extra = extra->next) {
add_extra_ref(".have", extra->old_sha1, 0);
}
transport_disconnect(transport);
free(other);
return 0;
}
static void add_alternate_refs(void)
{
foreach_alt_odb(add_refs_from_alternate, NULL);
}
int cmd_receive_pack(int argc, const char **argv, const char *prefix)
{
int i;
char *dir = NULL;
argv++;
for (i = 1; i < argc; i++) {
char *arg = *argv++;
const char *arg = *argv++;
if (*arg == '-') {
/* Do flag handling here */
@ -477,7 +513,7 @@ int main(int argc, char **argv)
}
if (dir)
usage(receive_pack_usage);
dir = arg;
dir = xstrdup(arg);
}
if (!dir)
usage(receive_pack_usage);
@ -497,7 +533,9 @@ int main(int argc, char **argv)
else if (0 <= receive_unpack_limit)
unpack_limit = receive_unpack_limit;
add_alternate_refs();
write_head_info();
clear_extra_refs();
/* EOF */
packet_flush(1);

Просмотреть файл

@ -18,7 +18,7 @@ static struct send_pack_args args = {
/*
* Make a pack stream and spit it out into file descriptor fd
*/
static int pack_objects(int fd, struct ref *refs)
static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra)
{
/*
* The child becomes pack-objects --revs; we feed
@ -34,6 +34,8 @@ static int pack_objects(int fd, struct ref *refs)
NULL,
};
struct child_process po;
int i;
char buf[42];
if (args.use_thin_pack)
argv[4] = "--thin";
@ -49,9 +51,15 @@ static int pack_objects(int fd, struct ref *refs)
* We feed the pack-objects we just spawned with revision
* parameters by writing to the pipe.
*/
while (refs) {
char buf[42];
for (i = 0; i < extra->nr; i++) {
memcpy(buf + 1, sha1_to_hex(&extra->array[i][0]), 40);
buf[0] = '^';
buf[41] = '\n';
if (!write_or_whine(po.in, buf, 42, "send-pack: send refs"))
break;
}
while (refs) {
if (!is_null_sha1(refs->old_sha1) &&
has_sha1_file(refs->old_sha1)) {
memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
@ -381,14 +389,17 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
int expect_status_report = 0;
int flags = MATCH_REFS_NONE;
int ret;
struct extra_have_objects extra_have;
memset(&extra_have, 0, sizeof(extra_have));
if (args.send_all)
flags |= MATCH_REFS_ALL;
if (args.send_mirror)
flags |= MATCH_REFS_MIRROR;
/* No funny business with the matcher */
remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);
remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
&extra_have);
get_local_heads();
/* Does the other end support the reporting? */
@ -496,7 +507,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
packet_flush(out);
if (new_refs && !args.dry_run) {
if (pack_objects(out, remote_refs) < 0)
if (pack_objects(out, remote_refs, &extra_have) < 0)
return -1;
}
else

Просмотреть файл

@ -79,6 +79,7 @@ extern int cmd_prune(int argc, const char **argv, const char *prefix);
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
extern int cmd_push(int argc, const char **argv, const char *prefix);
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);
extern int cmd_reflog(int argc, const char **argv, const char *prefix);
extern int cmd_remote(int argc, const char **argv, const char *prefix);
extern int cmd_config(int argc, const char **argv, const char *prefix);

Просмотреть файл

@ -533,6 +533,7 @@ static inline int is_absolute_path(const char *path)
{
return path[0] == '/' || has_dos_drive_prefix(path);
}
int is_directory(const char *);
const char *make_absolute_path(const char *path);
const char *make_nonrelative_path(const char *path);
const char *make_relative_path(const char *abs, const char *base);
@ -640,6 +641,8 @@ extern struct alternate_object_database {
} *alt_odb_list;
extern void prepare_alt_odb(void);
extern void add_to_alternates_file(const char *reference);
typedef int alt_odb_fn(struct alternate_object_database *, void *);
extern void foreach_alt_odb(alt_odb_fn, void*);
struct pack_window {
struct pack_window *next;
@ -708,7 +711,11 @@ extern struct child_process *git_connect(int fd[2], const char *url, const char
extern int finish_connect(struct child_process *conn);
extern int path_match(const char *path, int nr, char **match);
extern int get_ack(int fd, unsigned char *result_sha1);
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
struct extra_have_objects {
int nr, alloc;
unsigned char (*array)[20];
};
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
extern int server_supports(const char *feature);
extern struct packed_git *parse_pack_index(unsigned char *sha1);

Просмотреть файл

@ -41,12 +41,20 @@ int check_ref_type(const struct ref *ref, int flags)
return check_ref(ref->name, strlen(ref->name), flags);
}
static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1)
{
ALLOC_GROW(extra->array, extra->nr + 1, extra->alloc);
hashcpy(&(extra->array[extra->nr][0]), sha1);
extra->nr++;
}
/*
* Read all the refs from the other end
*/
struct ref **get_remote_heads(int in, struct ref **list,
int nr_match, char **match,
unsigned int flags)
unsigned int flags,
struct extra_have_objects *extra_have)
{
*list = NULL;
for (;;) {
@ -72,6 +80,12 @@ struct ref **get_remote_heads(int in, struct ref **list,
server_capabilities = xstrdup(name + name_len + 1);
}
if (extra_have &&
name_len == 5 && !memcmp(".have", name, 5)) {
add_extra_have(extra_have, old_sha1);
continue;
}
if (!check_ref(name, name_len, flags))
continue;
if (nr_match && !path_match(name, nr_match, match))

Просмотреть файл

@ -1116,13 +1116,9 @@ int main(int argc, char **argv)
if (strict_paths && (!ok_paths || !*ok_paths))
die("option --strict-paths requires a whitelist");
if (base_path) {
struct stat st;
if (stat(base_path, &st) || !S_ISDIR(st.st_mode))
die("base-path '%s' does not exist or "
"is not a directory", base_path);
}
if (base_path && !is_directory(base_path))
die("base-path '%s' does not exist or is not a directory",
base_path);
if (inetd_mode) {
struct sockaddr_storage ss;

1
git.c
Просмотреть файл

@ -330,6 +330,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
{ "push", cmd_push, RUN_SETUP },
{ "read-tree", cmd_read_tree, RUN_SETUP },
{ "receive-pack", cmd_receive_pack },
{ "reflog", cmd_reflog, RUN_SETUP },
{ "remote", cmd_remote, RUN_SETUP },
{ "repo-config", cmd_config },

Просмотреть файл

@ -319,7 +319,6 @@ static int git_rerere_config(const char *var, const char *value, void *cb)
static int is_rerere_enabled(void)
{
struct stat st;
const char *rr_cache;
int rr_cache_exists;
@ -327,7 +326,7 @@ static int is_rerere_enabled(void)
return 0;
rr_cache = git_path("rr-cache");
rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);
rr_cache_exists = is_directory(rr_cache);
if (rerere_enabled < 0)
return rr_cache_exists;

Просмотреть файл

@ -254,7 +254,6 @@ static void read_info_alternates(const char * alternates, int depth);
*/
static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
{
struct stat st;
const char *objdir = get_object_directory();
struct alternate_object_database *ent;
struct alternate_object_database *alt;
@ -285,7 +284,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative
ent->base[pfxlen] = ent->base[entlen-1] = 0;
/* Detect cases where alternate disappeared */
if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
if (!is_directory(ent->base)) {
error("object directory %s does not exist; "
"check .git/objects/info/alternates.",
ent->base);
@ -398,6 +397,16 @@ void add_to_alternates_file(const char *reference)
link_alt_odb_entries(alt, alt + strlen(alt), '\n', NULL, 0);
}
void foreach_alt_odb(alt_odb_fn fn, void *cb)
{
struct alternate_object_database *ent;
prepare_alt_odb();
for (ent = alt_odb_list; ent; ent = ent->next)
if (fn(ent, cb))
return;
}
void prepare_alt_odb(void)
{
const char *alt;

Просмотреть файл

@ -619,7 +619,7 @@ static struct ref *get_refs_via_connect(struct transport *transport)
struct ref *refs;
connect_setup(transport);
get_remote_heads(data->fd[0], &refs, 0, NULL, 0);
get_remote_heads(data->fd[0], &refs, 0, NULL, 0, NULL);
return refs;
}
@ -652,7 +652,7 @@ static int fetch_refs_via_pack(struct transport *transport,
if (!data->conn) {
connect_setup(transport);
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0);
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
}
refs = fetch_pack(&args, data->fd, data->conn,