#include "fetch-pack.h"
#include "remote.h"
#include "run-command.h"
+#include "connect.h"
#include "transport.h"
#include "version.h"
#include "prio-queue.h"
+#include "sha1-array.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
static struct lock_file shallow_lock;
static const char *alternate_shallow_file;
+/* Remember to update object flag allocation in object.h */
#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
#define COMMON_REF (1U << 2)
if (!(commit->object.flags & mark)) {
commit->object.flags |= mark;
- if (!(commit->object.parsed))
- if (parse_commit(commit))
- return;
+ if (parse_commit(commit))
+ return;
prio_queue_put(&rev_list, commit);
return NULL;
commit = prio_queue_get(&rev_list);
- if (!commit->object.parsed)
- parse_commit(commit);
+ parse_commit(commit);
parents = commit->parents;
commit->object.flags |= POPPED;
*/
char *line;
while ((line = packet_read_line(fd, NULL))) {
- if (!prefixcmp(line, "shallow "))
+ if (starts_with(line, "shallow "))
continue;
- if (!prefixcmp(line, "unshallow "))
+ if (starts_with(line, "unshallow "))
continue;
die("git fetch-pack: expected shallow list");
}
die("git fetch-pack: expected ACK/NAK, got EOF");
if (!strcmp(line, "NAK"))
return NAK;
- if (!prefixcmp(line, "ACK ")) {
+ if (starts_with(line, "ACK ")) {
if (!get_sha1_hex(line+4, result_sha1)) {
if (len < 45)
return ACK;
}
if (is_repository_shallow())
- write_shallow_commits(&req_buf, 1);
+ write_shallow_commits(&req_buf, 1, NULL);
if (args->depth > 0)
packet_buf_write(&req_buf, "deepen %d", args->depth);
packet_buf_flush(&req_buf);
send_request(args, fd[1], &req_buf);
while ((line = packet_read_line(fd[0], NULL))) {
- if (!prefixcmp(line, "shallow ")) {
+ if (starts_with(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
register_shallow(sha1);
continue;
}
- if (!prefixcmp(line, "unshallow ")) {
+ if (starts_with(line, "unshallow ")) {
if (get_sha1_hex(line + 10, sha1))
die("invalid unshallow line: %s", line);
if (!lookup_object(sha1))
}
strbuf_release(&req_buf);
- consume_shallow_list(args, fd[0]);
+ if (!got_ready || !no_done)
+ consume_shallow_list(args, fd[0]);
while (flushes || multi_ack) {
int ack = get_ack(fd[0], result_sha1);
if (ack) {
}
if (!keep && args->fetch_all &&
- (!args->depth || prefixcmp(ref->name, "refs/tags/")))
+ (!args->depth || !starts_with(ref->name, "refs/tags/")))
keep = 1;
if (keep) {
const char *argv[22];
char keep_arg[256];
char hdr_arg[256];
- const char **av;
+ const char **av, *cmd_name;
int do_keep = args->keep_pack;
struct child_process cmd;
int ret;
if (do_keep) {
if (pack_lockfile)
cmd.out = -1;
- *av++ = "index-pack";
+ *av++ = cmd_name = "index-pack";
*av++ = "--stdin";
if (!args->quiet && !args->no_progress)
*av++ = "-v";
*av++ = "--check-self-contained-and-connected";
}
else {
- *av++ = "unpack-objects";
+ *av++ = cmd_name = "unpack-objects";
if (args->quiet || args->no_progress)
*av++ = "-q";
args->check_self_contained_and_connected = 0;
cmd.in = demux.out;
cmd.git_cmd = 1;
if (start_command(&cmd))
- die("fetch-pack: unable to fork off %s", argv[0]);
+ die("fetch-pack: unable to fork off %s", cmd_name);
if (do_keep && pack_lockfile) {
*pack_lockfile = index_pack_lockfile(cmd.out);
close(cmd.out);
}
+ if (!use_sideband)
+ /* Closed by start_command() */
+ xd[0] = -1;
+
ret = finish_command(&cmd);
if (!ret || (args->check_self_contained_and_connected && ret == 1))
args->self_contained_and_connected =
args->check_self_contained_and_connected &&
ret == 0;
else
- die("%s failed", argv[0]);
+ die("%s failed", cmd_name);
if (use_sideband && finish_async(&demux))
die("error in sideband demultiplexer");
return 0;
int fd[2],
const struct ref *orig_ref,
struct ref **sought, int nr_sought,
+ struct shallow_info *si,
char **pack_lockfile)
{
struct ref *ref = copy_ref_list(orig_ref);
if (args->stateless_rpc)
packet_flush(fd[1]);
if (args->depth > 0)
- setup_alternate_shallow(&shallow_lock, &alternate_shallow_file);
+ setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
+ NULL);
+ else if (si->nr_ours || si->nr_theirs)
+ alternate_shallow_file = setup_temporary_shallow(si->shallow);
else
alternate_shallow_file = NULL;
if (get_pack(args, fd, pack_lockfile))
return dst;
}
+static void update_shallow(struct fetch_pack_args *args,
+ struct ref **sought, int nr_sought,
+ struct shallow_info *si)
+{
+ struct sha1_array ref = SHA1_ARRAY_INIT;
+ int *status;
+ int i;
+
+ if (args->depth > 0 && alternate_shallow_file) {
+ if (*alternate_shallow_file == '\0') { /* --unshallow */
+ unlink_or_warn(git_path("shallow"));
+ rollback_lock_file(&shallow_lock);
+ } else
+ commit_lock_file(&shallow_lock);
+ return;
+ }
+
+ if (!si->shallow || !si->shallow->nr)
+ return;
+
+ if (args->cloning) {
+ /*
+ * remote is shallow, but this is a clone, there are
+ * no objects in repo to worry about. Accept any
+ * shallow points that exist in the pack (iow in repo
+ * after get_pack() and reprepare_packed_git())
+ */
+ struct sha1_array extra = SHA1_ARRAY_INIT;
+ unsigned char (*sha1)[20] = si->shallow->sha1;
+ for (i = 0; i < si->shallow->nr; i++)
+ if (has_sha1_file(sha1[i]))
+ sha1_array_append(&extra, sha1[i]);
+ if (extra.nr) {
+ setup_alternate_shallow(&shallow_lock,
+ &alternate_shallow_file,
+ &extra);
+ commit_lock_file(&shallow_lock);
+ }
+ sha1_array_clear(&extra);
+ return;
+ }
+
+ if (!si->nr_ours && !si->nr_theirs)
+ return;
+
+ remove_nonexistent_theirs_shallow(si);
+ if (!si->nr_ours && !si->nr_theirs)
+ return;
+ for (i = 0; i < nr_sought; i++)
+ sha1_array_append(&ref, sought[i]->old_sha1);
+ si->ref = &ref;
+
+ if (args->update_shallow) {
+ /*
+ * remote is also shallow, .git/shallow may be updated
+ * so all refs can be accepted. Make sure we only add
+ * shallow roots that are actually reachable from new
+ * refs.
+ */
+ struct sha1_array extra = SHA1_ARRAY_INIT;
+ unsigned char (*sha1)[20] = si->shallow->sha1;
+ assign_shallow_commits_to_refs(si, NULL, NULL);
+ if (!si->nr_ours && !si->nr_theirs) {
+ sha1_array_clear(&ref);
+ return;
+ }
+ for (i = 0; i < si->nr_ours; i++)
+ sha1_array_append(&extra, sha1[si->ours[i]]);
+ for (i = 0; i < si->nr_theirs; i++)
+ sha1_array_append(&extra, sha1[si->theirs[i]]);
+ setup_alternate_shallow(&shallow_lock,
+ &alternate_shallow_file,
+ &extra);
+ commit_lock_file(&shallow_lock);
+ sha1_array_clear(&extra);
+ sha1_array_clear(&ref);
+ return;
+ }
+
+ /*
+ * remote is also shallow, check what ref is safe to update
+ * without updating .git/shallow
+ */
+ status = xcalloc(nr_sought, sizeof(*status));
+ assign_shallow_commits_to_refs(si, NULL, status);
+ if (si->nr_ours || si->nr_theirs) {
+ for (i = 0; i < nr_sought; i++)
+ if (status[i])
+ sought[i]->status = REF_STATUS_REJECT_SHALLOW;
+ }
+ free(status);
+ sha1_array_clear(&ref);
+}
+
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
const char *dest,
struct ref **sought, int nr_sought,
+ struct sha1_array *shallow,
char **pack_lockfile)
{
struct ref *ref_cpy;
+ struct shallow_info si;
fetch_pack_setup();
if (nr_sought)
packet_flush(fd[1]);
die("no matching remote head");
}
- ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile);
-
- if (args->depth > 0 && alternate_shallow_file) {
- if (*alternate_shallow_file == '\0') { /* --unshallow */
- unlink_or_warn(git_path("shallow"));
- rollback_lock_file(&shallow_lock);
- } else
- commit_lock_file(&shallow_lock);
- }
-
+ prepare_shallow_info(&si, shallow);
+ ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
+ &si, pack_lockfile);
reprepare_packed_git();
+ update_shallow(args, sought, nr_sought, &si);
+ clear_shallow_info(&si);
return ref_cpy;
}