static void upload_pack_data_clear(struct upload_pack_data *data) { object_array_clear(&data->wants); oid_array_clear(&data->haves); object_array_clear(&data->shallows); string_list_clear(&data->deepen_not, 0); }
static int check_changes_tracked_files(struct pathspec ps) { int result; struct rev_info rev; struct object_id dummy; /* No initial commit. */ if (get_oid("HEAD", &dummy)) return -1; if (read_cache() < 0) return -1; init_revisions(&rev, NULL); rev.prune_data = ps; rev.diffopt.flags.quick = 1; rev.diffopt.flags.ignore_submodules = 1; rev.abbrev = 0; add_head_to_pending(&rev); diff_setup_done(&rev.diffopt); result = run_diff_index(&rev, 1); if (diff_result_code(&rev.diffopt, result)) return 1; object_array_clear(&rev.pending); result = run_diff_files(&rev, 0); if (diff_result_code(&rev.diffopt, result)) return 1; return 0; }
static int stash_working_tree(struct stash_info *info, struct pathspec ps) { int ret = 0; struct rev_info rev; struct child_process cp_upd_index = CHILD_PROCESS_INIT; struct strbuf diff_output = STRBUF_INIT; struct index_state istate = { NULL }; init_revisions(&rev, NULL); set_alternate_index_output(stash_index_path.buf); if (reset_tree(&info->i_tree, 0, 0)) { ret = -1; goto done; } set_alternate_index_output(NULL); rev.prune_data = ps; rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = add_diff_to_buf; rev.diffopt.format_callback_data = &diff_output; if (read_cache_preload(&rev.diffopt.pathspec) < 0) { ret = -1; goto done; } add_pending_object(&rev, parse_object(the_repository, &info->b_commit), ""); if (run_diff_index(&rev, 0)) { ret = -1; goto done; } cp_upd_index.git_cmd = 1; argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add", "--remove", "--stdin", NULL); argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s", stash_index_path.buf); if (pipe_command(&cp_upd_index, diff_output.buf, diff_output.len, NULL, 0, NULL, 0)) { ret = -1; goto done; } if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0, NULL)) { ret = -1; goto done; } done: discard_index(&istate); UNLEAK(rev); object_array_clear(&rev.pending); strbuf_release(&diff_output); remove_path(stash_index_path.buf); return ret; }
static void deepen(int depth, int deepen_relative, struct object_array *shallows) { if (depth == INFINITE_DEPTH && !is_repository_shallow(the_repository)) { int i; for (i = 0; i < shallows->nr; i++) { struct object *object = shallows->objects[i].item; object->flags |= NOT_SHALLOW; } } else if (deepen_relative) { struct object_array reachable_shallows = OBJECT_ARRAY_INIT; struct commit_list *result; get_reachable_list(shallows, &reachable_shallows); result = get_shallow_commits(&reachable_shallows, depth + 1, SHALLOW, NOT_SHALLOW); send_shallow(result); free_commit_list(result); object_array_clear(&reachable_shallows); } else { struct commit_list *result; result = get_shallow_commits(&want_obj, depth, SHALLOW, NOT_SHALLOW); send_shallow(result); free_commit_list(result); } send_unshallow(shallows); }
void traverse_commit_list(struct rev_info *revs, show_commit_fn show_commit, show_object_fn show_object, void *data) { int i; struct commit *commit; struct strbuf base; strbuf_init(&base, PATH_MAX); while ((commit = get_revision(revs)) != NULL) { /* * an uninteresting boundary commit may not have its tree * parsed yet, but we are not going to show them anyway */ if (commit->tree) add_pending_tree(revs, commit->tree); show_commit(commit, data); } for (i = 0; i < revs->pending.nr; i++) { struct object_array_entry *pending = revs->pending.objects + i; struct object *obj = pending->item; const char *name = pending->name; const char *path = pending->path; if (obj->flags & (UNINTERESTING | SEEN)) continue; if (obj->type == OBJ_TAG) { obj->flags |= SEEN; show_object(obj, name, data); continue; } if (!path) path = ""; if (obj->type == OBJ_TREE) { process_tree(revs, (struct tree *)obj, show_object, &base, path, data); continue; } if (obj->type == OBJ_BLOB) { process_blob(revs, (struct blob *)obj, show_object, &base, path, data); continue; } die("unknown pending object %s (%s)", oid_to_hex(&obj->oid), name); } object_array_clear(&revs->pending); strbuf_release(&base); }
int index_differs_from(const char *def, const struct diff_flags *flags, int ita_invisible_in_index) { struct rev_info rev; struct setup_revision_opt opt; repo_init_revisions(the_repository, &rev, NULL); memset(&opt, 0, sizeof(opt)); opt.def = def; setup_revisions(0, NULL, &rev, &opt); rev.diffopt.flags.quick = 1; rev.diffopt.flags.exit_with_status = 1; if (flags) diff_flags_or(&rev.diffopt.flags, flags); rev.diffopt.ita_invisible_in_index = ita_invisible_in_index; run_diff_index(&rev, 1); object_array_clear(&rev.pending); return (rev.diffopt.flags.has_changes != 0); }
static void traverse_trees_and_blobs(struct rev_info *revs, struct strbuf *base, show_object_fn show_object, void *show_data, filter_object_fn filter_fn, void *filter_data) { int i; assert(base->len == 0); for (i = 0; i < revs->pending.nr; i++) { struct object_array_entry *pending = revs->pending.objects + i; struct object *obj = pending->item; const char *name = pending->name; const char *path = pending->path; if (obj->flags & (UNINTERESTING | SEEN)) continue; if (obj->type == OBJ_TAG) { obj->flags |= SEEN; show_object(obj, name, show_data); continue; } if (!path) path = ""; if (obj->type == OBJ_TREE) { process_tree(revs, (struct tree *)obj, show_object, base, path, show_data, filter_fn, filter_data); continue; } if (obj->type == OBJ_BLOB) { process_blob(revs, (struct blob *)obj, show_object, base, path, show_data, filter_fn, filter_data); continue; } die("unknown pending object %s (%s)", oid_to_hex(&obj->oid), name); } object_array_clear(&revs->pending); }
static int commit_is_complete(struct commit *commit) { struct object_array study; struct object_array found; int is_incomplete = 0; int i; /* early return */ if (commit->object.flags & SEEN) return 1; if (commit->object.flags & INCOMPLETE) return 0; /* * Find all commits that are reachable and are not marked as * SEEN. Then make sure the trees and blobs contained are * complete. After that, mark these commits also as SEEN. * If some of the objects that are needed to complete this * commit are missing, mark this commit as INCOMPLETE. */ memset(&study, 0, sizeof(study)); memset(&found, 0, sizeof(found)); add_object_array(&commit->object, NULL, &study); add_object_array(&commit->object, NULL, &found); commit->object.flags |= STUDYING; while (study.nr) { struct commit *c; struct commit_list *parent; c = (struct commit *)object_array_pop(&study); if (!c->object.parsed && !parse_object(the_repository, &c->object.oid)) c->object.flags |= INCOMPLETE; if (c->object.flags & INCOMPLETE) { is_incomplete = 1; break; } else if (c->object.flags & SEEN) continue; for (parent = c->parents; parent; parent = parent->next) { struct commit *p = parent->item; if (p->object.flags & STUDYING) continue; p->object.flags |= STUDYING; add_object_array(&p->object, NULL, &study); add_object_array(&p->object, NULL, &found); } } if (!is_incomplete) { /* * make sure all commits in "found" array have all the * necessary objects. */ for (i = 0; i < found.nr; i++) { struct commit *c = (struct commit *)found.objects[i].item; if (!tree_is_complete(get_commit_tree_oid(c))) { is_incomplete = 1; c->object.flags |= INCOMPLETE; } } if (!is_incomplete) { /* mark all found commits as complete, iow SEEN */ for (i = 0; i < found.nr; i++) found.objects[i].item->flags |= SEEN; } } /* clear flags from the objects we traversed */ for (i = 0; i < found.nr; i++) found.objects[i].item->flags &= ~STUDYING; if (is_incomplete) commit->object.flags |= INCOMPLETE; else { /* * If we come here, we have (1) traversed the ancestry chain * from the "commit" until we reach SEEN commits (which are * known to be complete), and (2) made sure that the commits * encountered during the above traversal refer to trees that * are complete. Which means that we know *all* the commits * we have seen during this process are complete. */ for (i = 0; i < found.nr; i++) found.objects[i].item->flags |= SEEN; } /* free object arrays */ object_array_clear(&study); object_array_clear(&found); return !is_incomplete; }
static void receive_needs(void) { struct object_array shallows = OBJECT_ARRAY_INIT; struct string_list deepen_not = STRING_LIST_INIT_DUP; int depth = 0; int has_non_tip = 0; timestamp_t deepen_since = 0; int deepen_rev_list = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; struct object_id oid_buf; char *line = packet_read_line(0, NULL); const char *arg; reset_timeout(); if (!line) break; if (process_shallow(line, &shallows)) continue; if (process_deepen(line, &depth)) continue; if (process_deepen_since(line, &deepen_since, &deepen_rev_list)) continue; if (process_deepen_not(line, &deepen_not, &deepen_rev_list)) continue; if (skip_prefix(line, "filter ", &arg)) { if (!filter_capability_requested) die("git upload-pack: filtering capability not negotiated"); parse_list_objects_filter(&filter_options, arg); continue; } if (!skip_prefix(line, "want ", &arg) || parse_oid_hex(arg, &oid_buf, &features)) die("git upload-pack: protocol error, " "expected to get object ID, not '%s'", line); if (parse_feature_request(features, "deepen-relative")) deepen_relative = 1; if (parse_feature_request(features, "multi_ack_detailed")) multi_ack = 2; else if (parse_feature_request(features, "multi_ack")) multi_ack = 1; if (parse_feature_request(features, "no-done")) no_done = 1; if (parse_feature_request(features, "thin-pack")) use_thin_pack = 1; if (parse_feature_request(features, "ofs-delta")) use_ofs_delta = 1; if (parse_feature_request(features, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (parse_feature_request(features, "side-band")) use_sideband = DEFAULT_PACKET_MAX; if (parse_feature_request(features, "no-progress")) no_progress = 1; if (parse_feature_request(features, "include-tag")) use_include_tag = 1; if (allow_filter && parse_feature_request(features, "filter")) filter_capability_requested = 1; o = parse_object(&oid_buf); if (!o) { packet_write_fmt(1, "ERR upload-pack: not our ref %s", oid_to_hex(&oid_buf)); die("git upload-pack: not our ref %s", oid_to_hex(&oid_buf)); } if (!(o->flags & WANTED)) { o->flags |= WANTED; if (!((allow_unadvertised_object_request & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1 || is_our_ref(o))) has_non_tip = 1; add_object_array(o, NULL, &want_obj); } } /* * We have sent all our refs already, and the other end * should have chosen out of them. When we are operating * in the stateless RPC mode, however, their choice may * have been based on the set of older refs advertised * by another process that handled the initial request. */ if (has_non_tip) check_non_tip(); if (!use_sideband && daemon_mode) no_progress = 1; if (depth == 0 && !deepen_rev_list && shallows.nr == 0) return; if (send_shallow_list(depth, deepen_rev_list, deepen_since, &deepen_not, &shallows)) packet_flush(1); object_array_clear(&shallows); }
static void receive_needs(void) { struct object_array shallows = OBJECT_ARRAY_INIT; struct string_list deepen_not = STRING_LIST_INIT_DUP; int depth = 0; int has_non_tip = 0; timestamp_t deepen_since = 0; int deepen_rev_list = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; struct object_id oid_buf; char *line = packet_read_line(0, NULL); const char *arg; reset_timeout(); if (!line) break; if (skip_prefix(line, "shallow ", &arg)) { struct object_id oid; struct object *object; if (get_oid_hex(arg, &oid)) die("invalid shallow line: %s", line); object = parse_object(&oid); if (!object) continue; if (object->type != OBJ_COMMIT) die("invalid shallow object %s", oid_to_hex(&oid)); if (!(object->flags & CLIENT_SHALLOW)) { object->flags |= CLIENT_SHALLOW; add_object_array(object, NULL, &shallows); } continue; } if (skip_prefix(line, "deepen ", &arg)) { char *end = NULL; depth = strtol(arg, &end, 0); if (!end || *end || depth <= 0) die("Invalid deepen: %s", line); continue; } if (skip_prefix(line, "deepen-since ", &arg)) { char *end = NULL; deepen_since = parse_timestamp(arg, &end, 0); if (!end || *end || !deepen_since || /* revisions.c's max_age -1 is special */ deepen_since == -1) die("Invalid deepen-since: %s", line); deepen_rev_list = 1; continue; } if (skip_prefix(line, "deepen-not ", &arg)) { char *ref = NULL; struct object_id oid; if (expand_ref(arg, strlen(arg), &oid, &ref) != 1) die("git upload-pack: ambiguous deepen-not: %s", line); string_list_append(&deepen_not, ref); free(ref); deepen_rev_list = 1; continue; } if (skip_prefix(line, "filter ", &arg)) { if (!filter_capability_requested) die("git upload-pack: filtering capability not negotiated"); parse_list_objects_filter(&filter_options, arg); continue; } if (!skip_prefix(line, "want ", &arg) || get_oid_hex(arg, &oid_buf)) die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); features = arg + 40; if (parse_feature_request(features, "deepen-relative")) deepen_relative = 1; if (parse_feature_request(features, "multi_ack_detailed")) multi_ack = 2; else if (parse_feature_request(features, "multi_ack")) multi_ack = 1; if (parse_feature_request(features, "no-done")) no_done = 1; if (parse_feature_request(features, "thin-pack")) use_thin_pack = 1; if (parse_feature_request(features, "ofs-delta")) use_ofs_delta = 1; if (parse_feature_request(features, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (parse_feature_request(features, "side-band")) use_sideband = DEFAULT_PACKET_MAX; if (parse_feature_request(features, "no-progress")) no_progress = 1; if (parse_feature_request(features, "include-tag")) use_include_tag = 1; if (allow_filter && parse_feature_request(features, "filter")) filter_capability_requested = 1; o = parse_object(&oid_buf); if (!o) { packet_write_fmt(1, "ERR upload-pack: not our ref %s", oid_to_hex(&oid_buf)); die("git upload-pack: not our ref %s", oid_to_hex(&oid_buf)); } if (!(o->flags & WANTED)) { o->flags |= WANTED; if (!((allow_unadvertised_object_request & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1 || is_our_ref(o))) has_non_tip = 1; add_object_array(o, NULL, &want_obj); } } /* * We have sent all our refs already, and the other end * should have chosen out of them. When we are operating * in the stateless RPC mode, however, their choice may * have been based on the set of older refs advertised * by another process that handled the initial request. */ if (has_non_tip) check_non_tip(); if (!use_sideband && daemon_mode) no_progress = 1; if (depth == 0 && !deepen_rev_list && shallows.nr == 0) return; if (depth > 0 && deepen_rev_list) die("git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together"); if (depth > 0) deepen(depth, deepen_relative, &shallows); else if (deepen_rev_list) { struct argv_array av = ARGV_ARRAY_INIT; int i; argv_array_push(&av, "rev-list"); if (deepen_since) argv_array_pushf(&av, "--max-age=%"PRItime, deepen_since); if (deepen_not.nr) { argv_array_push(&av, "--not"); for (i = 0; i < deepen_not.nr; i++) { struct string_list_item *s = deepen_not.items + i; argv_array_push(&av, s->string); } argv_array_push(&av, "--not"); } for (i = 0; i < want_obj.nr; i++) { struct object *o = want_obj.objects[i].item; argv_array_push(&av, oid_to_hex(&o->oid)); } deepen_by_rev_list(av.argc, av.argv, &shallows); argv_array_clear(&av); } else if (shallows.nr > 0) { int i; for (i = 0; i < shallows.nr; i++) register_shallow(&shallows.objects[i].item->oid); } shallow_nr += shallows.nr; object_array_clear(&shallows); }
void bitmap_writer_build(struct packing_data *to_pack) { static const double REUSE_BITMAP_THRESHOLD = 0.2; int i, reuse_after, need_reset; struct bitmap *base = bitmap_new(); struct rev_info revs; writer.bitmaps = kh_init_sha1(); writer.to_pack = to_pack; if (writer.show_progress) writer.progress = start_progress("Building bitmaps", writer.selected_nr); repo_init_revisions(to_pack->repo, &revs, NULL); revs.tag_objects = 1; revs.tree_objects = 1; revs.blob_objects = 1; revs.no_walk = 0; revs.include_check = should_include; reset_revision_walk(); reuse_after = writer.selected_nr * REUSE_BITMAP_THRESHOLD; need_reset = 0; for (i = writer.selected_nr - 1; i >= 0; --i) { struct bitmapped_commit *stored; struct object *object; khiter_t hash_pos; int hash_ret; stored = &writer.selected[i]; object = (struct object *)stored->commit; if (stored->bitmap == NULL) { if (i < writer.selected_nr - 1 && (need_reset || !in_merge_bases(writer.selected[i + 1].commit, stored->commit))) { bitmap_reset(base); reset_all_seen(); } add_pending_object(&revs, object, ""); revs.include_check_data = base; if (prepare_revision_walk(&revs)) die("revision walk setup failed"); traverse_commit_list(&revs, show_commit, show_object, base); object_array_clear(&revs.pending); stored->bitmap = bitmap_to_ewah(base); need_reset = 0; } else need_reset = 1; if (i >= reuse_after) stored->flags |= BITMAP_FLAG_REUSE; hash_pos = kh_put_sha1(writer.bitmaps, object->oid.hash, &hash_ret); if (hash_ret == 0) die("Duplicate entry when writing index: %s", oid_to_hex(&object->oid)); kh_value(writer.bitmaps, hash_pos) = stored; display_progress(writer.progress, writer.selected_nr - i); } bitmap_free(base); stop_progress(&writer.progress); compute_xor_offsets(); }