summaryrefslogtreecommitdiff
path: root/builtin/fetch-pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/fetch-pack.c')
-rw-r--r--builtin/fetch-pack.c360
1 files changed, 195 insertions, 165 deletions
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index c6bc8eb0aa..e6443986b8 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -10,6 +10,7 @@
#include "remote.h"
#include "run-command.h"
#include "transport.h"
+#include "version.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@@ -18,12 +19,15 @@ static int prefer_ofs_delta = 1;
static int no_done;
static int fetch_fsck_objects = -1;
static int transfer_fsck_objects = -1;
+static int agent_supported;
static struct fetch_pack_args args = {
/* .uploadpack = */ "git-upload-pack",
};
static const char fetch_pack_usage[] =
-"git fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
+"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
+"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
+"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
@@ -58,9 +62,9 @@ static void rev_list_push(struct commit *commit, int mark)
}
}
-static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- struct object *o = deref_tag(parse_object(sha1), path, 0);
+ struct object *o = deref_tag(parse_object(sha1), refname, 0);
if (o && o->type == OBJ_COMMIT)
rev_list_push((struct commit *)o, SEEN);
@@ -68,9 +72,9 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int
return 0;
}
-static int clear_marks(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- struct object *o = deref_tag(parse_object(sha1), path, 0);
+ struct object *o = deref_tag(parse_object(sha1), refname, 0);
if (o && o->type == OBJ_COMMIT)
clear_commit_marks((struct commit *)o,
@@ -256,11 +260,6 @@ static void insert_one_alternate_ref(const struct ref *ref, void *unused)
rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
}
-static void insert_alternate_refs(void)
-{
- for_each_alternate_ref(insert_one_alternate_ref, NULL);
-}
-
#define INITIAL_FLUSH 16
#define PIPESAFE_FLUSH 32
#define LARGE_FLUSH 1024
@@ -295,7 +294,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
marked = 1;
for_each_ref(rev_list_insert_ref, NULL);
- insert_alternate_refs();
+ for_each_alternate_ref(insert_one_alternate_ref, NULL);
fetching = 0;
for ( ; refs ; refs = refs->next) {
@@ -330,6 +329,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
if (args.no_progress) strbuf_addstr(&c, " no-progress");
if (args.include_tag) strbuf_addstr(&c, " include-tag");
if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta");
+ if (agent_supported) strbuf_addf(&c, " agent=%s",
+ git_user_agent_sanitized());
packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
strbuf_release(&c);
} else
@@ -493,7 +494,7 @@ done:
static struct commit_list *complete;
-static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
struct object *o = parse_object(sha1);
@@ -524,64 +525,68 @@ static void mark_recent_complete_commits(unsigned long cutoff)
}
}
-static void filter_refs(struct ref **refs, int nr_match, char **match)
+static int non_matching_ref(struct string_list_item *item, void *unused)
+{
+ if (item->util) {
+ item->util = NULL;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+static void filter_refs(struct ref **refs, struct string_list *sought)
{
- struct ref **return_refs;
struct ref *newlist = NULL;
struct ref **newtail = &newlist;
struct ref *ref, *next;
- struct ref *fastarray[32];
-
- if (nr_match && !args.fetch_all) {
- if (ARRAY_SIZE(fastarray) < nr_match)
- return_refs = xcalloc(nr_match, sizeof(struct ref *));
- else {
- return_refs = fastarray;
- memset(return_refs, 0, sizeof(struct ref *) * nr_match);
- }
- }
- else
- return_refs = NULL;
+ int sought_pos;
+ sought_pos = 0;
for (ref = *refs; ref; ref = next) {
+ int keep = 0;
next = ref->next;
if (!memcmp(ref->name, "refs/", 5) &&
check_refname_format(ref->name + 5, 0))
; /* trash */
- else if (args.fetch_all &&
- (!args.depth || prefixcmp(ref->name, "refs/tags/") )) {
- *newtail = ref;
- ref->next = NULL;
- newtail = &ref->next;
- continue;
- }
else {
- int order = path_match(ref->name, nr_match, match);
- if (order) {
- return_refs[order-1] = ref;
- continue; /* we will link it later */
+ while (sought_pos < sought->nr) {
+ int cmp = strcmp(ref->name, sought->items[sought_pos].string);
+ if (cmp < 0)
+ break; /* definitely do not have it */
+ else if (cmp == 0) {
+ keep = 1; /* definitely have it */
+ sought->items[sought_pos++].util = "matched";
+ break;
+ }
+ else
+ sought_pos++; /* might have it; keep looking */
}
}
- free(ref);
- }
- if (!args.fetch_all) {
- int i;
- for (i = 0; i < nr_match; i++) {
- ref = return_refs[i];
- if (ref) {
- *newtail = ref;
- ref->next = NULL;
- newtail = &ref->next;
- }
+ if (! keep && args.fetch_all &&
+ (!args.depth || prefixcmp(ref->name, "refs/tags/")))
+ keep = 1;
+
+ if (keep) {
+ *newtail = ref;
+ ref->next = NULL;
+ newtail = &ref->next;
+ } else {
+ free(ref);
}
- if (return_refs != fastarray)
- free(return_refs);
}
+
+ filter_string_list(sought, 0, non_matching_ref, NULL);
*refs = newlist;
}
-static int everything_local(struct ref **refs, int nr_match, char **match)
+static void mark_alternate_complete(const struct ref *ref, void *unused)
+{
+ mark_complete(NULL, ref->old_sha1, 0, NULL);
+}
+
+static int everything_local(struct ref **refs, struct string_list *sought)
{
struct ref *ref;
int retval;
@@ -609,6 +614,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
if (!args.depth) {
for_each_ref(mark_complete, NULL);
+ for_each_alternate_ref(mark_alternate_complete, NULL);
if (cutoff)
mark_recent_complete_commits(cutoff);
}
@@ -631,7 +637,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
}
}
- filter_refs(refs, nr_match, match);
+ filter_refs(refs, sought);
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
const unsigned char *remote = ref->old_sha1;
@@ -731,7 +737,7 @@ static int get_pack(int xd[2], char **pack_lockfile)
}
else {
*av++ = "unpack-objects";
- if (args.quiet)
+ if (args.quiet || args.no_progress)
*av++ = "-q";
}
if (*hdr_arg)
@@ -762,12 +768,15 @@ static int get_pack(int xd[2], char **pack_lockfile)
static struct ref *do_fetch_pack(int fd[2],
const struct ref *orig_ref,
- int nr_match,
- char **match,
+ struct string_list *sought,
char **pack_lockfile)
{
struct ref *ref = copy_ref_list(orig_ref);
unsigned char sha1[20];
+ const char *agent_feature;
+ int agent_len;
+
+ sort_ref_list(&ref, ref_compare_name);
if (is_repository_shallow() && !server_supports("shallow"))
die("Server does not support shallow clients");
@@ -797,12 +806,26 @@ static struct ref *do_fetch_pack(int fd[2],
fprintf(stderr, "Server supports side-band\n");
use_sideband = 1;
}
+ if (!server_supports("thin-pack"))
+ args.use_thin_pack = 0;
+ if (!server_supports("no-progress"))
+ args.no_progress = 0;
+ if (!server_supports("include-tag"))
+ args.include_tag = 0;
if (server_supports("ofs-delta")) {
if (args.verbose)
fprintf(stderr, "Server supports ofs-delta\n");
} else
prefer_ofs_delta = 0;
- if (everything_local(&ref, nr_match, match)) {
+
+ if ((agent_feature = server_feature_value("agent", &agent_len))) {
+ agent_supported = 1;
+ if (args.verbose && agent_len)
+ fprintf(stderr, "Server version is %.*s\n",
+ agent_len, agent_feature);
+ }
+
+ if (everything_local(&ref, sought)) {
packet_flush(fd[1]);
goto all_done;
}
@@ -822,28 +845,6 @@ static struct ref *do_fetch_pack(int fd[2],
return ref;
}
-static int remove_duplicates(int nr_heads, char **heads)
-{
- int src, dst;
-
- for (src = dst = 0; src < nr_heads; src++) {
- /* If heads[src] is different from any of
- * heads[0..dst], push it in.
- */
- int i;
- for (i = 0; i < dst; i++) {
- if (!strcmp(heads[i], heads[src]))
- break;
- }
- if (i < dst)
- continue;
- if (src != dst)
- heads[dst] = heads[src];
- dst++;
- }
- return dst;
-}
-
static int fetch_pack_config(const char *var, const char *value, void *cb)
{
if (strcmp(var, "fetch.unpacklimit") == 0) {
@@ -891,9 +892,10 @@ static void fetch_pack_setup(void)
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
{
- int i, ret, nr_heads;
+ int i, ret;
struct ref *ref = NULL;
- char *dest = NULL, **heads;
+ const char *dest = NULL;
+ struct string_list sought = STRING_LIST_INIT_DUP;
int fd[2];
char *pack_lockfile = NULL;
char **pack_lockfile_ptr = NULL;
@@ -901,85 +903,114 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
packet_trace_identity("fetch-pack");
- nr_heads = 0;
- heads = NULL;
- for (i = 1; i < argc; i++) {
+ for (i = 1; i < argc && *argv[i] == '-'; i++) {
const char *arg = argv[i];
- if (*arg == '-') {
- if (!prefixcmp(arg, "--upload-pack=")) {
- args.uploadpack = arg + 14;
- continue;
- }
- if (!prefixcmp(arg, "--exec=")) {
- args.uploadpack = arg + 7;
- continue;
- }
- if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
- args.quiet = 1;
- continue;
- }
- if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
- args.lock_pack = args.keep_pack;
- args.keep_pack = 1;
- continue;
- }
- if (!strcmp("--thin", arg)) {
- args.use_thin_pack = 1;
- continue;
- }
- if (!strcmp("--include-tag", arg)) {
- args.include_tag = 1;
- continue;
- }
- if (!strcmp("--all", arg)) {
- args.fetch_all = 1;
- continue;
- }
- if (!strcmp("-v", arg)) {
- args.verbose = 1;
- continue;
- }
- if (!prefixcmp(arg, "--depth=")) {
- args.depth = strtol(arg + 8, NULL, 0);
- continue;
- }
- if (!strcmp("--no-progress", arg)) {
- args.no_progress = 1;
- continue;
- }
- if (!strcmp("--stateless-rpc", arg)) {
- args.stateless_rpc = 1;
- continue;
- }
- if (!strcmp("--lock-pack", arg)) {
- args.lock_pack = 1;
- pack_lockfile_ptr = &pack_lockfile;
- continue;
- }
- usage(fetch_pack_usage);
+ if (!prefixcmp(arg, "--upload-pack=")) {
+ args.uploadpack = arg + 14;
+ continue;
+ }
+ if (!prefixcmp(arg, "--exec=")) {
+ args.uploadpack = arg + 7;
+ continue;
+ }
+ if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
+ args.quiet = 1;
+ continue;
+ }
+ if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
+ args.lock_pack = args.keep_pack;
+ args.keep_pack = 1;
+ continue;
+ }
+ if (!strcmp("--thin", arg)) {
+ args.use_thin_pack = 1;
+ continue;
+ }
+ if (!strcmp("--include-tag", arg)) {
+ args.include_tag = 1;
+ continue;
+ }
+ if (!strcmp("--all", arg)) {
+ args.fetch_all = 1;
+ continue;
+ }
+ if (!strcmp("--stdin", arg)) {
+ args.stdin_refs = 1;
+ continue;
+ }
+ if (!strcmp("-v", arg)) {
+ args.verbose = 1;
+ continue;
+ }
+ if (!prefixcmp(arg, "--depth=")) {
+ args.depth = strtol(arg + 8, NULL, 0);
+ continue;
}
- dest = (char *)arg;
- heads = (char **)(argv + i + 1);
- nr_heads = argc - i - 1;
- break;
+ if (!strcmp("--no-progress", arg)) {
+ args.no_progress = 1;
+ continue;
+ }
+ if (!strcmp("--stateless-rpc", arg)) {
+ args.stateless_rpc = 1;
+ continue;
+ }
+ if (!strcmp("--lock-pack", arg)) {
+ args.lock_pack = 1;
+ pack_lockfile_ptr = &pack_lockfile;
+ continue;
+ }
+ usage(fetch_pack_usage);
}
- if (!dest)
+
+ if (i < argc)
+ dest = argv[i++];
+ else
usage(fetch_pack_usage);
+ /*
+ * Copy refs from cmdline to growable list, then append any
+ * refs from the standard input:
+ */
+ for (; i < argc; i++)
+ string_list_append(&sought, xstrdup(argv[i]));
+ if (args.stdin_refs) {
+ if (args.stateless_rpc) {
+ /* in stateless RPC mode we use pkt-line to read
+ * from stdin, until we get a flush packet
+ */
+ static char line[1000];
+ for (;;) {
+ int n = packet_read_line(0, line, sizeof(line));
+ if (!n)
+ break;
+ if (line[n-1] == '\n')
+ n--;
+ string_list_append(&sought, xmemdupz(line, n));
+ }
+ }
+ else {
+ /* read from stdin one ref per line, until EOF */
+ struct strbuf line = STRBUF_INIT;
+ while (strbuf_getline(&line, stdin, '\n') != EOF)
+ string_list_append(&sought, strbuf_detach(&line, NULL));
+ strbuf_release(&line);
+ }
+ }
+
if (args.stateless_rpc) {
conn = NULL;
fd[0] = 0;
fd[1] = 1;
} else {
- conn = git_connect(fd, (char *)dest, args.uploadpack,
+ conn = git_connect(fd, dest, args.uploadpack,
args.verbose ? CONNECT_VERBOSE : 0);
}
- get_remote_heads(fd[0], &ref, 0, NULL, 0, NULL);
+ get_remote_heads(fd[0], &ref, 0, NULL);
ref = fetch_pack(&args, fd, conn, ref, dest,
- nr_heads, heads, pack_lockfile_ptr);
+ &sought, pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
fflush(stdout);
@@ -987,21 +1018,18 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
close(fd[0]);
close(fd[1]);
if (finish_connect(conn))
- ref = NULL;
- ret = !ref;
-
- if (!ret && nr_heads) {
- /* If the heads to pull were given, we should have
- * consumed all of them by matching the remote.
- * Otherwise, 'git fetch remote no-such-ref' would
- * silently succeed without issuing an error.
- */
- for (i = 0; i < nr_heads; i++)
- if (heads[i] && heads[i][0]) {
- error("no such remote ref %s", heads[i]);
- ret = 1;
- }
- }
+ return 1;
+
+ ret = !ref || sought.nr;
+
+ /*
+ * If the heads to pull were given, we should have consumed
+ * all of them by matching the remote. Otherwise, 'git fetch
+ * remote no-such-ref' would silently succeed without issuing
+ * an error.
+ */
+ for (i = 0; i < sought.nr; i++)
+ error("no such remote ref %s", sought.items[i].string);
while (ref) {
printf("%s %s\n",
sha1_to_hex(ref->old_sha1), ref->name);
@@ -1014,10 +1042,9 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
struct ref *fetch_pack(struct fetch_pack_args *my_args,
int fd[], struct child_process *conn,
const struct ref *ref,
- const char *dest,
- int nr_heads,
- char **heads,
- char **pack_lockfile)
+ const char *dest,
+ struct string_list *sought,
+ char **pack_lockfile)
{
struct stat st;
struct ref *ref_cpy;
@@ -1030,13 +1057,16 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
st.st_mtime = 0;
}
- if (heads && nr_heads)
- nr_heads = remove_duplicates(nr_heads, heads);
+ if (sought->nr) {
+ sort_string_list(sought);
+ string_list_remove_duplicates(sought, 0);
+ }
+
if (!ref) {
packet_flush(fd[1]);
die("no matching remote head");
}
- ref_cpy = do_fetch_pack(fd, ref, nr_heads, heads, pack_lockfile);
+ ref_cpy = do_fetch_pack(fd, ref, sought, pack_lockfile);
if (args.depth > 0) {
struct cache_time mtime;