#include "commit.h"
#include "tag.h"
#include "pkt-line.h"
+#include "remote.h"
+#include "refs.h"
+#include "sha1-array.h"
+#include "diff.h"
+#include "revision.h"
+#include "commit-slab.h"
static int is_shallow = -1;
static struct stat shallow_stat;
return 0;
}
-int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
+int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
+ const struct sha1_array *extra)
{
struct write_shallow_data data;
+ int i;
data.out = out;
data.use_pack_protocol = use_pack_protocol;
data.count = 0;
for_each_commit_graft(write_one_shallow, &data);
+ if (!extra)
+ return data.count;
+ for (i = 0; i < extra->nr; i++) {
+ strbuf_addstr(out, sha1_to_hex(extra->sha1[i]));
+ strbuf_addch(out, '\n');
+ data.count++;
+ }
return data.count;
}
-char *setup_temporary_shallow(void)
+char *setup_temporary_shallow(const struct sha1_array *extra)
{
struct strbuf sb = STRBUF_INIT;
int fd;
- if (write_shallow_commits(&sb, 0)) {
+ if (write_shallow_commits(&sb, 0, extra)) {
struct strbuf path = STRBUF_INIT;
strbuf_addstr(&path, git_path("shallow_XXXXXX"));
fd = xmkstemp(path.buf);
}
void setup_alternate_shallow(struct lock_file *shallow_lock,
- const char **alternate_shallow_file)
+ const char **alternate_shallow_file,
+ const struct sha1_array *extra)
{
struct strbuf sb = STRBUF_INIT;
int fd;
check_shallow_file_for_update();
fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
LOCK_DIE_ON_ERROR);
- if (write_shallow_commits(&sb, 0)) {
+ if (write_shallow_commits(&sb, 0, extra)) {
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
die_errno("failed to write to %s",
shallow_lock->filename);
*alternate_shallow_file = "";
strbuf_release(&sb);
}
+
+static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *cb)
+{
+ int fd = *(int *)cb;
+ if (graft->nr_parent == -1)
+ packet_write(fd, "shallow %s\n", sha1_to_hex(graft->sha1));
+ return 0;
+}
+
+void advertise_shallow_grafts(int fd)
+{
+ if (!is_repository_shallow())
+ return;
+ for_each_commit_graft(advertise_shallow_grafts_cb, &fd);
+}
+
+#define TRACE_KEY "GIT_TRACE_SHALLOW"
+
+/*
+ * Step 1, split sender shallow commits into "ours" and "theirs"
+ * Step 2, clean "ours" based on .git/shallow
+ */
+void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa)
+{
+ int i;
+ trace_printf_key(TRACE_KEY, "shallow: prepare_shallow_info\n");
+ memset(info, 0, sizeof(*info));
+ info->shallow = sa;
+ if (!sa)
+ return;
+ info->ours = xmalloc(sizeof(*info->ours) * sa->nr);
+ info->theirs = xmalloc(sizeof(*info->theirs) * sa->nr);
+ for (i = 0; i < sa->nr; i++) {
+ if (has_sha1_file(sa->sha1[i])) {
+ struct commit_graft *graft;
+ graft = lookup_commit_graft(sa->sha1[i]);
+ if (graft && graft->nr_parent < 0)
+ continue;
+ info->ours[info->nr_ours++] = i;
+ } else
+ info->theirs[info->nr_theirs++] = i;
+ }
+}
+
+void clear_shallow_info(struct shallow_info *info)
+{
+ free(info->ours);
+ free(info->theirs);
+}
+
+/* Step 4, remove non-existent ones in "theirs" after getting the pack */
+
+void remove_nonexistent_theirs_shallow(struct shallow_info *info)
+{
+ unsigned char (*sha1)[20] = info->shallow->sha1;
+ int i, dst;
+ trace_printf_key(TRACE_KEY, "shallow: remove_nonexistent_theirs_shallow\n");
+ for (i = dst = 0; i < info->nr_theirs; i++) {
+ if (i != dst)
+ info->theirs[dst] = info->theirs[i];
+ if (has_sha1_file(sha1[info->theirs[i]]))
+ dst++;
+ }
+ info->nr_theirs = dst;
+}
+
+/* Step 5, remove non-existent ones in "ours" in the pack */
+void remove_nonexistent_ours_in_pack(struct shallow_info *info,
+ struct packed_git *p)
+{
+ unsigned char (*sha1)[20] = info->shallow->sha1;
+ int i, dst;
+ trace_printf_key(TRACE_KEY, "shallow: remove_nonexistent_ours_in_pack\n");
+ for (i = dst = 0; i < info->nr_ours; i++) {
+ if (i != dst)
+ info->ours[dst] = info->ours[i];
+ if (find_pack_entry_one(sha1[info->ours[i]], p))
+ dst++;
+ }
+ info->nr_ours = dst;
+}