static void send_unshallow(const struct object_array *shallows) { int i; for (i = 0; i < shallows->nr; i++) { struct object *object = shallows->objects[i].item; if (object->flags & NOT_SHALLOW) { struct commit_list *parents; packet_write_fmt(1, "unshallow %s", oid_to_hex(&object->oid)); object->flags &= ~CLIENT_SHALLOW; /* * We want to _register_ "object" as shallow, but we * also need to traverse object's parents to deepen a * shallow clone. Unregister it for now so we can * parse and add the parents to the want list, then * re-register it. */ unregister_shallow(&object->oid); object->parsed = 0; parse_commit_or_die((struct commit *)object); parents = ((struct commit *)object)->parents; while (parents) { add_object_array(&parents->item->object, NULL, &want_obj); parents = parents->next; } add_object_array(object, NULL, &extra_edge_obj); } /* make sure commit traversal conforms to client */ register_shallow(the_repository, &object->oid); } }
static int find_first_merges(struct object_array *result, const char *path, struct commit *a, struct commit *b) { int i, j; struct object_array merges; struct commit *commit; int contains_another; char merged_revision[42]; const char *rev_args[] = { "rev-list", "--merges", "--ancestry-path", "--all", merged_revision, NULL }; struct rev_info revs; struct setup_revision_opt rev_opts; memset(&merges, 0, sizeof(merges)); memset(result, 0, sizeof(struct object_array)); memset(&rev_opts, 0, sizeof(rev_opts)); /* get all revisions that merge commit a */ snprintf(merged_revision, sizeof(merged_revision), "^%s", sha1_to_hex(a->object.sha1)); init_revisions(&revs, NULL); rev_opts.submodule = path; setup_revisions(sizeof(rev_args)/sizeof(char *)-1, rev_args, &revs, &rev_opts); /* save all revisions from the above list that contain b */ if (prepare_revision_walk(&revs)) die("revision walk setup failed"); while ((commit = get_revision(&revs)) != NULL) { struct object *o = &(commit->object); if (in_merge_bases(b, commit)) add_object_array(o, NULL, &merges); } reset_revision_walk(); /* Now we've got all merges that contain a and b. Prune all * merges that contain another found merge and save them in * result. */ for (i = 0; i < merges.nr; i++) { struct commit *m1 = (struct commit *) merges.objects[i].item; contains_another = 0; for (j = 0; j < merges.nr; j++) { struct commit *m2 = (struct commit *) merges.objects[j].item; if (i != j && in_merge_bases(m2, m1)) { contains_another = 1; break; } } if (!contains_another) add_object_array(merges.objects[i].item, merges.objects[i].name, result); } free(merges.objects); return result->nr; }
static int parse_want(const char *line) { const char *arg; if (skip_prefix(line, "want ", &arg)) { struct object_id oid; struct object *o; if (get_oid_hex(arg, &oid)) die("git upload-pack: protocol error, " "expected to get oid, not '%s'", line); o = parse_object(&oid); if (!o) { packet_write_fmt(1, "ERR upload-pack: not our ref %s", oid_to_hex(&oid)); die("git upload-pack: not our ref %s", oid_to_hex(&oid)); } if (!(o->flags & WANTED)) { o->flags |= WANTED; add_object_array(o, NULL, &want_obj); } return 1; } return 0; }
struct commit_list *get_shallow_commits(struct object_array *heads, int depth, int shallow_flag, int not_shallow_flag) { int i = 0, cur_depth = 0; struct commit_list *result = NULL; struct object_array stack = OBJECT_ARRAY_INIT; struct commit *commit = NULL; while (commit || i < heads->nr || stack.nr) { struct commit_list *p; if (!commit) { if (i < heads->nr) { commit = (struct commit *) deref_tag(heads->objects[i++].item, NULL, 0); if (!commit || commit->object.type != OBJ_COMMIT) { commit = NULL; continue; } if (!commit->util) commit->util = xmalloc(sizeof(int)); *(int *)commit->util = 0; cur_depth = 0; } else { commit = (struct commit *) stack.objects[--stack.nr].item; cur_depth = *(int *)commit->util; } } parse_commit_or_die(commit); cur_depth++; if (cur_depth >= depth) { commit_list_insert(commit, &result); commit->object.flags |= shallow_flag; commit = NULL; continue; } commit->object.flags |= not_shallow_flag; for (p = commit->parents, commit = NULL; p; p = p->next) { if (!p->item->util) { int *pointer = xmalloc(sizeof(int)); p->item->util = pointer; *pointer = cur_depth; } else { int *pointer = p->item->util; if (cur_depth >= *pointer) continue; *pointer = cur_depth; } if (p->next) add_object_array(&p->item->object, NULL, &stack); else { commit = p->item; cur_depth = *(int *)commit->util; } } } return result; }
void add_object(struct object *obj, struct object_array *p, struct name_path *path, const char *name) { add_object_array(obj, path_name(path, name), p); }
static int got_sha1(char *hex, unsigned char *sha1) { struct object *o; int we_knew_they_have = 0; if (get_sha1_hex(hex, sha1)) die("git upload-pack: expected SHA1 object, got '%s'", hex); if (!has_sha1_file(sha1)) return -1; o = parse_object(sha1); if (!o) die("oops (%s)", sha1_to_hex(sha1)); if (o->type == OBJ_COMMIT) { struct commit_list *parents; struct commit *commit = (struct commit *)o; if (o->flags & THEY_HAVE) we_knew_they_have = 1; else o->flags |= THEY_HAVE; if (!oldest_have || (commit->date < oldest_have)) oldest_have = commit->date; for (parents = commit->parents; parents; parents = parents->next) parents->item->object.flags |= THEY_HAVE; } if (!we_knew_they_have) { add_object_array(o, NULL, &have_obj); return 1; } return 0; }
static int check_ancestors(const char *prefix) { struct rev_info revs; struct object_array pending_copy; int i, res; bisect_rev_setup(&revs, prefix, "^%s", "%s", 0); /* Save pending objects, so they can be cleaned up later. */ memset(&pending_copy, 0, sizeof(pending_copy)); for (i = 0; i < revs.pending.nr; i++) add_object_array(revs.pending.objects[i].item, revs.pending.objects[i].name, &pending_copy); bisect_common(&revs); res = (revs.commits != NULL); /* Clean up objects used, as they will be reused. */ for (i = 0; i < pending_copy.nr; i++) { struct object *o = pending_copy.objects[i].item; clear_commit_marks((struct commit *)o, ALL_REV_FLAGS); } return res; }
static void handle_tail(struct object_array *commits, struct rev_info *revs, struct string_list *paths_of_changed_objects) { struct commit *commit; while (commits->nr) { commit = (struct commit *)object_array_pop(commits); if (has_unshown_parent(commit)) { /* Queue again, to be handled later */ add_object_array(&commit->object, NULL, commits); return; } handle_commit(commit, revs, paths_of_changed_objects); } }
static int mark_object(struct object *obj, int type, void *data, struct fsck_options *options) { struct object *parent = data; /* * The only case data is NULL or type is OBJ_ANY is when * mark_object_reachable() calls us. All the callers of * that function has non-NULL obj hence ... */ if (!obj) { /* ... these references to parent->fld are safe here */ printf("broken link from %7s %s\n", printable_type(parent), describe_object(parent)); printf("broken link from %7s %s\n", (type == OBJ_ANY ? "unknown" : type_name(type)), "unknown"); errors_found |= ERROR_REACHABLE; return 1; } if (type != OBJ_ANY && obj->type != type) /* ... and the reference to parent is safe here */ objerror(parent, "wrong object type in link"); if (obj->flags & REACHABLE) return 0; obj->flags |= REACHABLE; if (is_promisor_object(&obj->oid)) /* * Further recursion does not need to be performed on this * object since it is a promisor object (so it does not need to * be added to "pending"). */ return 0; if (!(obj->flags & HAS_OBJ)) { if (parent && !has_object_file(&obj->oid)) { printf("broken link from %7s %s\n", printable_type(parent), describe_object(parent)); printf(" to %7s %s\n", printable_type(obj), describe_object(obj)); errors_found |= ERROR_REACHABLE; } return 1; } add_object_array(obj, NULL, &pending); return 0; }
void traverse_commit_list(struct rev_info *revs, void (*show_commit)(struct commit *), void (*show_object)(struct object_array_entry *)) { int i; struct commit *commit; struct object_array objects = { 0, 0, NULL }; while ((commit = get_revision(revs)) != NULL) { process_tree(revs, commit->tree, &objects, NULL, ""); show_commit(commit); } 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; if (obj->flags & (UNINTERESTING | SEEN)) continue; if (obj->type == OBJ_TAG) { obj->flags |= SEEN; add_object_array(obj, name, &objects); continue; } if (obj->type == OBJ_TREE) { process_tree(revs, (struct tree *)obj, &objects, NULL, name); continue; } if (obj->type == OBJ_BLOB) { process_blob(revs, (struct blob *)obj, &objects, NULL, name); continue; } die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name); } for (i = 0; i < objects.nr; i++) show_object(&objects.objects[i]); free(objects.objects); if (revs->pending.nr) { free(revs->pending.objects); revs->pending.nr = 0; revs->pending.alloc = 0; revs->pending.objects = NULL; } }
static int get_reachable_list(struct object_array *src, struct object_array *reachable) { struct child_process cmd = CHILD_PROCESS_INIT; int i; struct object *o; char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */ const unsigned hexsz = the_hash_algo->hexsz; if (do_reachable_revlist(&cmd, src, reachable) < 0) return -1; while ((i = read_in_full(cmd.out, namebuf, hexsz + 1)) == hexsz + 1) { struct object_id sha1; const char *p; if (parse_oid_hex(namebuf, &sha1, &p) || *p != '\n') break; o = lookup_object(sha1.hash); if (o && o->type == OBJ_COMMIT) { o->flags &= ~TMP_MARK; } } for (i = get_max_object_index(); 0 < i; i--) { o = get_indexed_object(i - 1); if (o && o->type == OBJ_COMMIT && (o->flags & TMP_MARK)) { add_object_array(o, NULL, reachable); o->flags &= ~TMP_MARK; } } close(cmd.out); if (finish_command(&cmd)) return -1; return 0; }
static int process_shallow(const char *line, struct object_array *shallows) { const char *arg; 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) return 1; 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); } return 1; } return 0; }
static int process_haves(struct oid_array *haves, struct oid_array *common) { int i; /* Process haves */ for (i = 0; i < haves->nr; i++) { const struct object_id *oid = &haves->oid[i]; struct object *o; int we_knew_they_have = 0; if (!has_object_file(oid)) continue; oid_array_append(common, oid); o = parse_object(oid); if (!o) die("oops (%s)", oid_to_hex(oid)); if (o->type == OBJ_COMMIT) { struct commit_list *parents; struct commit *commit = (struct commit *)o; if (o->flags & THEY_HAVE) we_knew_they_have = 1; else o->flags |= THEY_HAVE; if (!oldest_have || (commit->date < oldest_have)) oldest_have = commit->date; for (parents = commit->parents; parents; parents = parents->next) parents->item->object.flags |= THEY_HAVE; } if (!we_knew_they_have) add_object_array(o, NULL, &have_obj); } return 0; }
static int get_reachable_list(struct object_array *src, struct object_array *reachable) { struct child_process cmd = CHILD_PROCESS_INIT; int i; struct object *o; char namebuf[42]; /* ^ + SHA-1 + LF */ if (do_reachable_revlist(&cmd, src, reachable) < 0) return -1; while ((i = read_in_full(cmd.out, namebuf, 41)) == 41) { struct object_id sha1; if (namebuf[40] != '\n' || get_oid_hex(namebuf, &sha1)) break; o = lookup_object(sha1.hash); if (o && o->type == OBJ_COMMIT) { o->flags &= ~TMP_MARK; } } for (i = get_max_object_index(); 0 < i; i--) { o = get_indexed_object(i - 1); if (o && o->type == OBJ_COMMIT && (o->flags & TMP_MARK)) { add_object_array(o, NULL, reachable); o->flags &= ~TMP_MARK; } } close(cmd.out); if (finish_command(&cmd)) return -1; return 0; }
int cmd_diff(int argc, const char **argv, const char *prefix) { int i; struct rev_info rev; struct object_array ent = OBJECT_ARRAY_INIT; int blobs = 0, paths = 0; const char *path = NULL; struct blobinfo blob[2]; int nongit; int result = 0; /* * We could get N tree-ish in the rev.pending_objects list. * Also there could be M blobs there, and P pathspecs. * * N=0, M=0: * cache vs files (diff-files) * N=0, M=2: * compare two random blobs. P must be zero. * N=0, M=1, P=1: * compare a blob with a working tree file. * * N=1, M=0: * tree vs cache (diff-index --cached) * * N=2, M=0: * tree vs tree (diff-tree) * * N=0, M=0, P=2: * compare two filesystem entities (aka --no-index). * * Other cases are errors. */ prefix = setup_git_directory_gently(&nongit); gitmodules_config(); git_config(git_diff_ui_config, NULL); init_revisions(&rev, prefix); /* If this is a no-index diff, just run it and exit there. */ diff_no_index(&rev, argc, argv, nongit, prefix); /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; /* Scale to real terminal size and respect statGraphWidth config */ rev.diffopt.stat_width = -1; rev.diffopt.stat_graph_width = -1; /* Default to let external and textconv be used */ DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV); if (nongit) die(_("Not a git repository")); argc = setup_revisions(argc, argv, &rev, NULL); if (!rev.diffopt.output_format) { rev.diffopt.output_format = DIFF_FORMAT_PATCH; diff_setup_done(&rev.diffopt); } DIFF_OPT_SET(&rev.diffopt, RECURSIVE); setup_diff_pager(&rev.diffopt); /* * Do we have --cached and not have a pending object, then * default to HEAD by hand. Eek. */ if (!rev.pending.nr) { int i; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--")) break; else if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged")) { add_head_to_pending(&rev); if (!rev.pending.nr) { struct tree *tree; tree = lookup_tree(EMPTY_TREE_SHA1_BIN); add_pending_object(&rev, &tree->object, "HEAD"); } break; } } } for (i = 0; i < rev.pending.nr; i++) { struct object_array_entry *entry = &rev.pending.objects[i]; struct object *obj = entry->item; const char *name = entry->name; int flags = (obj->flags & UNINTERESTING); if (!obj->parsed) obj = parse_object(obj->sha1); obj = deref_tag(obj, NULL, 0); if (!obj) die(_("invalid object '%s' given."), name); if (obj->type == OBJ_COMMIT) obj = &((struct commit *)obj)->tree->object; if (obj->type == OBJ_TREE) { obj->flags |= flags; add_object_array(obj, name, &ent); } else if (obj->type == OBJ_BLOB) { if (2 <= blobs) die(_("more than two blobs given: '%s'"), name); hashcpy(blob[blobs].sha1, obj->sha1); blob[blobs].name = name; blob[blobs].mode = entry->mode; blobs++; } else { die(_("unhandled object '%s' given."), name); } } if (rev.prune_data.nr) { if (!path) path = rev.prune_data.items[0].match; paths += rev.prune_data.nr; } /* * Now, do the arguments look reasonable? */ if (!ent.nr) { switch (blobs) { case 0: result = builtin_diff_files(&rev, argc, argv); break; case 1: if (paths != 1) usage(builtin_diff_usage); result = builtin_diff_b_f(&rev, argc, argv, blob, path); break; case 2: if (paths) usage(builtin_diff_usage); result = builtin_diff_blobs(&rev, argc, argv, blob); break; default: usage(builtin_diff_usage); } } else if (blobs) usage(builtin_diff_usage); else if (ent.nr == 1) result = builtin_diff_index(&rev, argc, argv); else if (ent.nr == 2) result = builtin_diff_tree(&rev, argc, argv, &ent.objects[0], &ent.objects[1]); else if (ent.objects[0].item->flags & UNINTERESTING) { /* * diff A...B where there is at least one merge base * between A and B. We have ent.objects[0] == * merge-base, ent.objects[ents-2] == A, and * ent.objects[ents-1] == B. Show diff between the * base and B. Note that we pick one merge base at * random if there are more than one. */ result = builtin_diff_tree(&rev, argc, argv, &ent.objects[0], &ent.objects[ent.nr-1]); } else result = builtin_diff_combined(&rev, argc, argv, ent.objects, ent.nr); result = diff_result_code(&rev.diffopt, result); if (1 < rev.diffopt.skip_stat_unmatch) refresh_index_quietly(); return result; }
int cmd_name_rev(int argc, const char **argv, const char *prefix) { struct object_array revs = OBJECT_ARRAY_INIT; int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0; struct name_ref_data data = { 0, 0, NULL }; struct option opts[] = { OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")), OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")), OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"), N_("only use refs matching <pattern>")), OPT_GROUP(""), OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")), OPT_BOOL(0, "stdin", &transform_stdin, N_("read from stdin")), OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")), OPT_BOOL(0, "always", &always, N_("show abbreviated commit object as fallback")), { /* A Hidden OPT_BOOL */ OPTION_SET_INT, 0, "peel-tag", &peel_tag, NULL, N_("dereference tags in the input (internal use)"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1, }, OPT_END(), }; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0); if (all + transform_stdin + !!argc > 1) { error("Specify either a list, or --all, not both!"); usage_with_options(name_rev_usage, opts); } if (all || transform_stdin) cutoff = 0; for (; argc; argc--, argv++) { unsigned char sha1[20]; struct object *object; struct commit *commit; if (get_sha1(*argv, sha1)) { fprintf(stderr, "Could not get sha1 for %s. Skipping.\n", *argv); continue; } commit = NULL; object = parse_object(sha1); if (object) { struct object *peeled = deref_tag(object, *argv, 0); if (peeled && peeled->type == OBJ_COMMIT) commit = (struct commit *)peeled; } if (!object) { fprintf(stderr, "Could not get object for %s. Skipping.\n", *argv); continue; } if (commit) { if (cutoff > commit->date) cutoff = commit->date; } if (peel_tag) { if (!commit) { fprintf(stderr, "Could not get commit for %s. Skipping.\n", *argv); continue; } object = (struct object *)commit; } add_object_array(object, *argv, &revs); } if (cutoff) cutoff = cutoff - CUTOFF_DATE_SLOP; for_each_ref(name_ref, &data); if (transform_stdin) { char buffer[2048]; while (!feof(stdin)) { char *p = fgets(buffer, sizeof(buffer), stdin); if (!p) break; name_rev_line(p, &data); } } else if (all) { int i, max; max = get_max_object_index(); for (i = 0; i < max; i++) { struct object *obj = get_indexed_object(i); if (!obj || obj->type != OBJ_COMMIT) continue; show_name(obj, NULL, always, allow_undefined, data.name_only); } } else { int i; for (i = 0; i < revs.nr; i++) show_name(revs.objects[i].item, revs.objects[i].name, always, allow_undefined, data.name_only); } return 0; }
int cmd_diff(int argc, const char **argv, const char *prefix) { int i; struct rev_info rev; struct object_array ent = OBJECT_ARRAY_INIT; int blobs = 0, paths = 0; struct blobinfo blob[2]; int nongit = 0, no_index = 0; int result = 0; /* * We could get N tree-ish in the rev.pending_objects list. * Also there could be M blobs there, and P pathspecs. * * N=0, M=0: * cache vs files (diff-files) * N=0, M=2: * compare two random blobs. P must be zero. * N=0, M=1, P=1: * compare a blob with a working tree file. * * N=1, M=0: * tree vs cache (diff-index --cached) * * N=2, M=0: * tree vs tree (diff-tree) * * N=0, M=0, P=2: * compare two filesystem entities (aka --no-index). * * Other cases are errors. */ /* Were we asked to do --no-index explicitly? */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--")) { i++; break; } if (!strcmp(argv[i], "--no-index")) no_index = DIFF_NO_INDEX_EXPLICIT; if (argv[i][0] != '-') break; } if (!no_index) prefix = setup_git_directory_gently(&nongit); /* * Treat git diff with at least one path outside of the * repo the same as if the command would have been executed * outside of a git repository. In this case it behaves * the same way as "git diff --no-index <a> <b>", which acts * as a colourful "diff" replacement. */ if (nongit || ((argc == i + 2) && (!path_inside_repo(prefix, argv[i]) || !path_inside_repo(prefix, argv[i + 1])))) no_index = DIFF_NO_INDEX_IMPLICIT; if (!no_index) gitmodules_config(); init_diff_ui_defaults(); git_config(git_diff_ui_config, NULL); precompose_argv(argc, argv); init_revisions(&rev, prefix); if (no_index && argc != i + 2) { if (no_index == DIFF_NO_INDEX_IMPLICIT) { /* * There was no --no-index and there were not two * paths. It is possible that the user intended * to do an inside-repository operation. */ fprintf(stderr, "Not a git repository\n"); fprintf(stderr, "To compare two paths outside a working tree:\n"); } /* Give the usage message for non-repository usage and exit. */ usagef("git diff %s <path> <path>", no_index == DIFF_NO_INDEX_EXPLICIT ? "--no-index" : "[--no-index]"); } if (no_index) /* If this is a no-index diff, just run it and exit there. */ diff_no_index(&rev, argc, argv); /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; /* Scale to real terminal size and respect statGraphWidth config */ rev.diffopt.stat_width = -1; rev.diffopt.stat_graph_width = -1; /* Default to let external and textconv be used */ DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV); if (nongit) die(_("Not a git repository")); argc = setup_revisions(argc, argv, &rev, NULL); if (!rev.diffopt.output_format) { rev.diffopt.output_format = DIFF_FORMAT_PATCH; diff_setup_done(&rev.diffopt); } DIFF_OPT_SET(&rev.diffopt, RECURSIVE); setup_diff_pager(&rev.diffopt); /* * Do we have --cached and not have a pending object, then * default to HEAD by hand. Eek. */ if (!rev.pending.nr) { int i; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--")) break; else if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged")) { add_head_to_pending(&rev); if (!rev.pending.nr) { struct tree *tree; tree = lookup_tree(EMPTY_TREE_SHA1_BIN); add_pending_object(&rev, &tree->object, "HEAD"); } break; } } } for (i = 0; i < rev.pending.nr; i++) { struct object_array_entry *entry = &rev.pending.objects[i]; struct object *obj = entry->item; const char *name = entry->name; int flags = (obj->flags & UNINTERESTING); if (!obj->parsed) obj = parse_object(obj->oid.hash); obj = deref_tag(obj, NULL, 0); if (!obj) die(_("invalid object '%s' given."), name); if (obj->type == OBJ_COMMIT) obj = &((struct commit *)obj)->tree->object; if (obj->type == OBJ_TREE) { obj->flags |= flags; add_object_array(obj, name, &ent); } else if (obj->type == OBJ_BLOB) { if (2 <= blobs) die(_("more than two blobs given: '%s'"), name); hashcpy(blob[blobs].sha1, obj->oid.hash); blob[blobs].name = name; blob[blobs].mode = entry->mode; blobs++; } else { die(_("unhandled object '%s' given."), name); } } if (rev.prune_data.nr) paths += rev.prune_data.nr; /* * Now, do the arguments look reasonable? */ if (!ent.nr) { switch (blobs) { case 0: result = builtin_diff_files(&rev, argc, argv); break; case 1: if (paths != 1) usage(builtin_diff_usage); result = builtin_diff_b_f(&rev, argc, argv, blob); break; case 2: if (paths) usage(builtin_diff_usage); result = builtin_diff_blobs(&rev, argc, argv, blob); break; default: usage(builtin_diff_usage); } } else if (blobs) usage(builtin_diff_usage); else if (ent.nr == 1) result = builtin_diff_index(&rev, argc, argv); else if (ent.nr == 2) result = builtin_diff_tree(&rev, argc, argv, &ent.objects[0], &ent.objects[1]); else if (ent.objects[0].item->flags & UNINTERESTING) { /* * diff A...B where there is at least one merge base * between A and B. We have ent.objects[0] == * merge-base, ent.objects[ents-2] == A, and * ent.objects[ents-1] == B. Show diff between the * base and B. Note that we pick one merge base at * random if there are more than one. */ result = builtin_diff_tree(&rev, argc, argv, &ent.objects[0], &ent.objects[ent.nr-1]); } else result = builtin_diff_combined(&rev, argc, argv, ent.objects, ent.nr); result = diff_result_code(&rev.diffopt, result); if (1 < rev.diffopt.skip_stat_unmatch) refresh_index_quietly(); return result; }
int verify_bundle(struct bundle_header *header, int verbose) { /* * Do fast check, then if any prereqs are missing then go line by line * to be verbose about the errors */ struct ref_list *p = &header->prerequisites; struct rev_info revs; const char *argv[] = {NULL, "--all", NULL}; struct object_array refs; struct commit *commit; int i, ret = 0, req_nr; const char *message = "Repository lacks these prerequisite commits:"; init_revisions(&revs, NULL); for (i = 0; i < p->nr; i++) { struct ref_list_entry *e = p->list + i; struct object *o = parse_object(e->sha1); if (o) { o->flags |= PREREQ_MARK; add_pending_object(&revs, o, e->name); continue; } if (++ret == 1) error("%s", message); error("%s %s", sha1_to_hex(e->sha1), e->name); } if (revs.pending.nr != p->nr) return ret; req_nr = revs.pending.nr; setup_revisions(2, argv, &revs, NULL); memset(&refs, 0, sizeof(struct object_array)); for (i = 0; i < revs.pending.nr; i++) { struct object_array_entry *e = revs.pending.objects + i; add_object_array(e->item, e->name, &refs); } if (prepare_revision_walk(&revs)) die("revision walk setup failed"); i = req_nr; while (i && (commit = get_revision(&revs))) if (commit->object.flags & PREREQ_MARK) i--; for (i = 0; i < req_nr; i++) if (!(refs.objects[i].item->flags & SHOWN)) { if (++ret == 1) error("%s", message); error("%s %s", sha1_to_hex(refs.objects[i].item->sha1), refs.objects[i].name); } for (i = 0; i < refs.nr; i++) clear_commit_marks((struct commit *)refs.objects[i].item, -1); if (verbose) { struct ref_list *r; r = &header->references; printf("The bundle contains %d ref%s\n", r->nr, (1 < r->nr) ? "s" : ""); list_refs(r, 0, NULL); r = &header->prerequisites; printf("The bundle requires these %d ref%s\n", r->nr, (1 < r->nr) ? "s" : ""); list_refs(r, 0, NULL); } return ret; }
int cmd_show(int argc, const char **argv, const char *prefix) { struct rev_info rev; struct object_array_entry *objects; int i, count, ret = 0; git_config(git_log_config, NULL); if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; init_revisions(&rev, prefix); rev.diff = 1; rev.combine_merges = 1; rev.dense_combined_merges = 1; rev.always_show_header = 1; rev.ignore_merges = 0; rev.no_walk = 1; cmd_log_init(argc, argv, prefix, &rev); count = rev.pending.nr; objects = rev.pending.objects; for (i = 0; i < count && !ret; i++) { struct object *o = objects[i].item; const char *name = objects[i].name; switch (o->type) { case OBJ_BLOB: ret = show_object(o->sha1, 0, NULL); break; case OBJ_TAG: { struct tag *t = (struct tag *)o; if (rev.shown_one) putchar('\n'); printf("%stag %s%s\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), t->tag, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); ret = show_object(o->sha1, 1, &rev); rev.shown_one = 1; if (ret) break; o = parse_object(t->tagged->sha1); if (!o) ret = error("Could not read object %s", sha1_to_hex(t->tagged->sha1)); objects[i].item = o; i--; break; } case OBJ_TREE: if (rev.shown_one) putchar('\n'); printf("%stree %s%s\n\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), name, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); read_tree_recursive((struct tree *)o, "", 0, 0, NULL, show_tree_object, NULL); rev.shown_one = 1; break; case OBJ_COMMIT: rev.pending.nr = rev.pending.alloc = 0; rev.pending.objects = NULL; add_object_array(o, name, &rev.pending); ret = cmd_log_walk(&rev); break; default: ret = error("Unknown type: %d", o->type); } } free(objects); return ret; }
int cmd_show(int argc, const char **argv, const char *prefix) { struct rev_info rev; struct object_array_entry *objects; struct setup_revision_opt opt; struct pathspec match_all; int i, count, ret = 0; git_config(git_log_config, NULL); init_pathspec(&match_all, NULL); init_revisions(&rev, prefix); rev.diff = 1; rev.always_show_header = 1; rev.no_walk = 1; rev.diffopt.stat_width = -1; /* Scale to real terminal size */ memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; opt.tweak = show_rev_tweak_rev; cmd_log_init(argc, argv, prefix, &rev, &opt); if (!rev.no_walk) return cmd_log_walk(&rev); count = rev.pending.nr; objects = rev.pending.objects; for (i = 0; i < count && !ret; i++) { struct object *o = objects[i].item; const char *name = objects[i].name; switch (o->type) { case OBJ_BLOB: ret = show_blob_object(o->sha1, NULL); break; case OBJ_TAG: { struct tag *t = (struct tag *)o; if (rev.shown_one) putchar('\n'); printf("%stag %s%s\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), t->tag, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); ret = show_tag_object(o->sha1, &rev); rev.shown_one = 1; if (ret) break; o = parse_object(t->tagged->sha1); if (!o) ret = error(_("Could not read object %s"), sha1_to_hex(t->tagged->sha1)); objects[i].item = o; i--; break; } case OBJ_TREE: if (rev.shown_one) putchar('\n'); printf("%stree %s%s\n\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), name, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); read_tree_recursive((struct tree *)o, "", 0, 0, &match_all, show_tree_object, NULL); rev.shown_one = 1; break; case OBJ_COMMIT: rev.pending.nr = rev.pending.alloc = 0; rev.pending.objects = NULL; add_object_array(o, name, &rev.pending); ret = cmd_log_walk(&rev); break; default: ret = error(_("Unknown type: %d"), o->type); } } free(objects); return ret; }
int cmd_name_rev(int argc, const char **argv, const char *prefix) { struct object_array revs = { 0, 0, NULL }; int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0; struct name_ref_data data = { 0, 0, NULL }; struct option opts[] = { OPT_BOOLEAN(0, "name-only", &data.name_only, "print only names (no SHA-1)"), OPT_BOOLEAN(0, "tags", &data.tags_only, "only use tags to name the commits"), OPT_STRING(0, "refs", &data.ref_filter, "pattern", "only use refs matching <pattern>"), OPT_GROUP(""), OPT_BOOLEAN(0, "all", &all, "list all commits reachable from all refs"), OPT_BOOLEAN(0, "stdin", &transform_stdin, "read from stdin"), OPT_BOOLEAN(0, "undefined", &allow_undefined, "allow to print `undefined` names"), OPT_BOOLEAN(0, "always", &always, "show abbreviated commit object as fallback"), OPT_END(), }; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0); if (!!all + !!transform_stdin + !!argc > 1) { error("Specify either a list, or --all, not both!"); usage_with_options(name_rev_usage, opts); } if (all || transform_stdin) cutoff = 0; for (; argc; argc--, argv++) { unsigned char sha1[20]; struct object *o; struct commit *commit; if (get_sha1(*argv, sha1)) { fprintf(stderr, "Could not get sha1 for %s. Skipping.\n", *argv); continue; } o = deref_tag(parse_object(sha1), *argv, 0); if (!o || o->type != OBJ_COMMIT) { fprintf(stderr, "Could not get commit for %s. Skipping.\n", *argv); continue; } commit = (struct commit *)o; if (cutoff > commit->date) cutoff = commit->date; add_object_array((struct object *)commit, *argv, &revs); } if (cutoff) cutoff = cutoff - CUTOFF_DATE_SLOP; for_each_ref(name_ref, &data); if (transform_stdin) { char buffer[2048]; while (!feof(stdin)) { char *p = fgets(buffer, sizeof(buffer), stdin); if (!p) break; name_rev_line(p, &data); } } else if (all) { int i, max; max = get_max_object_index(); for (i = 0; i < max; i++) { struct object *obj = get_indexed_object(i); if (!obj) continue; show_name(obj, NULL, always, allow_undefined, data.name_only); } } else { int i; for (i = 0; i < revs.nr; i++) show_name(revs.objects[i].item, revs.objects[i].name, always, allow_undefined, data.name_only); } return 0; }
int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; int cached = 0; int seen_dashdash = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; int i; memset(&opt, 0, sizeof(opt)); opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; opt.relative = 1; opt.pathname = 1; opt.pattern_tail = &opt.pattern_list; opt.regflags = REG_NEWLINE; /* * If there is no -- then the paths must exist in the working * tree. If there is no explicit pattern specified with -e or * -f, we take the first unrecognized non option to be the * pattern, but then what follows it must be zero or more * valid refs up to the -- (if exists), and then existing * paths. If there is an explicit pattern, then the first * unrecognized non option is the beginning of the refs list * that continues up to the -- (if exists), and then paths. */ while (1 < argc) { const char *arg = argv[1]; argc--; argv++; if (!strcmp("--cached", arg)) { cached = 1; continue; } if (!strcmp("--no-ext-grep", arg)) { builtin_grep = 1; continue; } if (!strcmp("-a", arg) || !strcmp("--text", arg)) { opt.binary = GREP_BINARY_TEXT; continue; } if (!strcmp("-i", arg) || !strcmp("--ignore-case", arg)) { opt.regflags |= REG_ICASE; continue; } if (!strcmp("-I", arg)) { opt.binary = GREP_BINARY_NOMATCH; continue; } if (!strcmp("-v", arg) || !strcmp("--invert-match", arg)) { opt.invert = 1; continue; } if (!strcmp("-E", arg) || !strcmp("--extended-regexp", arg)) { opt.regflags |= REG_EXTENDED; continue; } if (!strcmp("-F", arg) || !strcmp("--fixed-strings", arg)) { opt.fixed = 1; continue; } if (!strcmp("-G", arg) || !strcmp("--basic-regexp", arg)) { opt.regflags &= ~REG_EXTENDED; continue; } if (!strcmp("-n", arg)) { opt.linenum = 1; continue; } if (!strcmp("-h", arg)) { opt.pathname = 0; continue; } if (!strcmp("-H", arg)) { opt.pathname = 1; continue; } if (!strcmp("-l", arg) || !strcmp("--name-only", arg) || !strcmp("--files-with-matches", arg)) { opt.name_only = 1; continue; } if (!strcmp("-L", arg) || !strcmp("--files-without-match", arg)) { opt.unmatch_name_only = 1; continue; } if (!strcmp("-z", arg) || !strcmp("--null", arg)) { opt.null_following_name = 1; continue; } if (!strcmp("-c", arg) || !strcmp("--count", arg)) { opt.count = 1; continue; } if (!strcmp("-w", arg) || !strcmp("--word-regexp", arg)) { opt.word_regexp = 1; continue; } if (!prefixcmp(arg, "-A") || !prefixcmp(arg, "-B") || !prefixcmp(arg, "-C") || (arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) { unsigned num; const char *scan; switch (arg[1]) { case 'A': case 'B': case 'C': if (!arg[2]) { if (argc <= 1) die(emsg_missing_context_len); scan = *++argv; argc--; } else scan = arg + 2; break; default: scan = arg + 1; break; } if (strtoul_ui(scan, 10, &num)) die(emsg_invalid_context_len, scan); switch (arg[1]) { case 'A': opt.post_context = num; break; default: case 'C': opt.post_context = num; case 'B': opt.pre_context = num; break; } continue; } if (!strcmp("-f", arg)) { FILE *patterns; int lno = 0; char buf[1024]; if (argc <= 1) die(emsg_missing_argument, arg); patterns = fopen(argv[1], "r"); if (!patterns) die("'%s': %s", argv[1], strerror(errno)); while (fgets(buf, sizeof(buf), patterns)) { int len = strlen(buf); if (len && buf[len-1] == '\n') buf[len-1] = 0; /* ignore empty line like grep does */ if (!buf[0]) continue; append_grep_pattern(&opt, xstrdup(buf), argv[1], ++lno, GREP_PATTERN); } fclose(patterns); argv++; argc--; continue; } if (!strcmp("--not", arg)) { append_grep_pattern(&opt, arg, "command line", 0, GREP_NOT); continue; } if (!strcmp("--and", arg)) { append_grep_pattern(&opt, arg, "command line", 0, GREP_AND); continue; } if (!strcmp("--or", arg)) continue; /* no-op */ if (!strcmp("(", arg)) { append_grep_pattern(&opt, arg, "command line", 0, GREP_OPEN_PAREN); continue; } if (!strcmp(")", arg)) { append_grep_pattern(&opt, arg, "command line", 0, GREP_CLOSE_PAREN); continue; } if (!strcmp("--all-match", arg)) { opt.all_match = 1; continue; } if (!strcmp("-e", arg)) { if (1 < argc) { append_grep_pattern(&opt, argv[1], "-e option", 0, GREP_PATTERN); argv++; argc--; continue; } die(emsg_missing_argument, arg); } if (!strcmp("--full-name", arg)) { opt.relative = 0; continue; } if (!strcmp("--", arg)) { /* later processing wants to have this at argv[1] */ argv--; argc++; break; } if (*arg == '-') usage(builtin_grep_usage); /* First unrecognized non-option token */ if (!opt.pattern_list) { append_grep_pattern(&opt, arg, "command line", 0, GREP_PATTERN); break; } else { /* We are looking at the first path or rev; * it is found at argv[1] after leaving the * loop. */ argc++; argv--; break; } } if (!opt.pattern_list) die("no pattern given."); if ((opt.regflags != REG_NEWLINE) && opt.fixed) die("cannot mix --fixed-strings and regexp"); compile_grep_patterns(&opt); /* Check revs and then paths */ for (i = 1; i < argc; i++) { const char *arg = argv[i]; unsigned char sha1[20]; /* Is it a rev? */ if (!get_sha1(arg, sha1)) { struct object *object = parse_object(sha1); if (!object) die("bad object %s", arg); add_object_array(object, arg, &list); continue; } if (!strcmp(arg, "--")) { i++; seen_dashdash = 1; } break; } /* The rest are paths */ if (!seen_dashdash) { int j; for (j = i; j < argc; j++) verify_filename(prefix, argv[j]); } if (i < argc) { paths = get_pathspec(prefix, argv + i); if (opt.prefix_length && opt.relative) { /* Make sure we do not get outside of paths */ for (i = 0; paths[i]; i++) if (strncmp(prefix, paths[i], opt.prefix_length)) die("git grep: cannot generate relative filenames containing '..'"); } } else if (prefix) { paths = xcalloc(2, sizeof(const char *)); paths[0] = prefix; paths[1] = NULL; } if (!list.nr) { if (!cached) setup_work_tree(); return !grep_cache(&opt, paths, cached); } if (cached) die("both --cached and trees are given."); for (i = 0; i < list.nr; i++) { struct object *real_obj; real_obj = deref_tag(list.objects[i].item, NULL, 0); if (grep_object(&opt, paths, real_obj, list.objects[i].name)) hit = 1; } free_grep_patterns(&opt); return !hit; }
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 struct commit *get_revision_internal(struct rev_info *revs) { struct commit *c = NULL; struct commit_list *l; if (revs->boundary == 2) { /* * All of the normal commits have already been returned, * and we are now returning boundary commits. * create_boundary_commit_list() has populated * revs->commits with the remaining commits to return. */ c = pop_commit(&revs->commits); if (c) c->object.flags |= SHOWN; return c; } /* * Now pick up what they want to give us */ c = get_revision_1(revs); if (c) { while (0 < revs->skip_count) { revs->skip_count--; c = get_revision_1(revs); if (!c) break; } } /* * Check the max_count. */ switch (revs->max_count) { case -1: break; case 0: c = NULL; break; default: revs->max_count--; } if (c) c->object.flags |= SHOWN; if (!revs->boundary) { return c; } if (!c) { /* * get_revision_1() runs out the commits, and * we are done computing the boundaries. * switch to boundary commits output mode. */ revs->boundary = 2; /* * Update revs->commits to contain the list of * boundary commits. */ create_boundary_commit_list(revs); return get_revision_internal(revs); } /* * boundary commits are the commits that are parents of the * ones we got from get_revision_1() but they themselves are * not returned from get_revision_1(). Before returning * 'c', we need to mark its parents that they could be boundaries. */ for (l = c->parents; l; l = l->next) { struct object *p; p = &(l->item->object); if (p->flags & (CHILD_SHOWN | SHOWN)) continue; p->flags |= CHILD_SHOWN; gc_boundary(&revs->boundary_commits); add_object_array(p, NULL, &revs->boundary_commits); } return c; }
static void receive_needs(void) { struct object_array shallows = OBJECT_ARRAY_INIT; int depth = 0; int has_non_tip = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; unsigned char sha1_buf[20]; char *line = packet_read_line(0, NULL); reset_timeout(); if (!line) break; if (starts_with(line, "shallow ")) { unsigned char sha1[20]; struct object *object; if (get_sha1_hex(line + 8, sha1)) die("invalid shallow line: %s", line); object = parse_object(sha1); if (!object) continue; if (object->type != OBJ_COMMIT) die("invalid shallow object %s", sha1_to_hex(sha1)); if (!(object->flags & CLIENT_SHALLOW)) { object->flags |= CLIENT_SHALLOW; add_object_array(object, NULL, &shallows); } continue; } if (starts_with(line, "deepen ")) { char *end; depth = strtol(line + 7, &end, 0); if (end == line + 7 || depth <= 0) die("Invalid deepen: %s", line); continue; } if (!starts_with(line, "want ") || get_sha1_hex(line+5, sha1_buf)) die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); features = line + 45; 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; o = parse_object(sha1_buf); if (!o) die("git upload-pack: not our ref %s", sha1_to_hex(sha1_buf)); if (!(o->flags & WANTED)) { o->flags |= WANTED; if (!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 && shallows.nr == 0) return; if (depth > 0) { struct commit_list *result = NULL, *backup = NULL; int i; if (depth == INFINITE_DEPTH && !is_repository_shallow()) for (i = 0; i < shallows.nr; i++) { struct object *object = shallows.objects[i].item; object->flags |= NOT_SHALLOW; } else backup = result = get_shallow_commits(&want_obj, depth, SHALLOW, NOT_SHALLOW); while (result) { struct object *object = &result->item->object; if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { packet_write(1, "shallow %s", sha1_to_hex(object->sha1)); register_shallow(object->sha1); shallow_nr++; } result = result->next; } free_commit_list(backup); for (i = 0; i < shallows.nr; i++) { struct object *object = shallows.objects[i].item; if (object->flags & NOT_SHALLOW) { struct commit_list *parents; packet_write(1, "unshallow %s", sha1_to_hex(object->sha1)); object->flags &= ~CLIENT_SHALLOW; /* make sure the real parents are parsed */ unregister_shallow(object->sha1); object->parsed = 0; parse_commit_or_die((struct commit *)object); parents = ((struct commit *)object)->parents; while (parents) { add_object_array(&parents->item->object, NULL, &want_obj); parents = parents->next; } add_object_array(object, NULL, &extra_edge_obj); } /* make sure commit traversal conforms to client */ register_shallow(object->sha1); } packet_flush(1); } else if (shallows.nr > 0) { int i; for (i = 0; i < shallows.nr; i++) register_shallow(shallows.objects[i].item->sha1); } shallow_nr += shallows.nr; free(shallows.objects); }
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); }
int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; int i; int dummy; int nongit = 0, use_index = 1; struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, "search in index instead of in the work tree"), OPT_BOOLEAN(0, "index", &use_index, "--no-index finds in contents not managed by git"), OPT_GROUP(""), OPT_BOOLEAN('v', "invert-match", &opt.invert, "show non-matching lines"), OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case, "case insensitive matching"), OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp, "match patterns only at word boundaries"), OPT_SET_INT('a', "text", &opt.binary, "process binary files as text", GREP_BINARY_TEXT), OPT_SET_INT('I', NULL, &opt.binary, "don't match patterns in binary files", GREP_BINARY_NOMATCH), { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth", "descend at most <depth> levels", PARSE_OPT_NONEG, NULL, 1 }, OPT_GROUP(""), OPT_BIT('E', "extended-regexp", &opt.regflags, "use extended POSIX regular expressions", REG_EXTENDED), OPT_NEGBIT('G', "basic-regexp", &opt.regflags, "use basic POSIX regular expressions (default)", REG_EXTENDED), OPT_BOOLEAN('F', "fixed-strings", &opt.fixed, "interpret patterns as fixed strings"), OPT_GROUP(""), OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"), OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1), OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1), OPT_NEGBIT(0, "full-name", &opt.relative, "show filenames relative to top directory", 1), OPT_BOOLEAN('l', "files-with-matches", &opt.name_only, "show only filenames instead of matching lines"), OPT_BOOLEAN(0, "name-only", &opt.name_only, "synonym for --files-with-matches"), OPT_BOOLEAN('L', "files-without-match", &opt.unmatch_name_only, "show only the names of files without match"), OPT_BOOLEAN('z', "null", &opt.null_following_name, "print NUL after filenames"), OPT_BOOLEAN('c', "count", &opt.count, "show the number of matches instead of matching lines"), OPT_SET_INT(0, "color", &opt.color, "highlight matches", 1), OPT_GROUP(""), OPT_CALLBACK('C', NULL, &opt, "n", "show <n> context lines before and after matches", context_callback), OPT_INTEGER('B', NULL, &opt.pre_context, "show <n> context lines before matches"), OPT_INTEGER('A', NULL, &opt.post_context, "show <n> context lines after matches"), OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM", context_callback), OPT_BOOLEAN('p', "show-function", &opt.funcname, "show a line with the function name before matches"), OPT_GROUP(""), OPT_CALLBACK('f', NULL, &opt, "file", "read patterns from file", file_callback), { OPTION_CALLBACK, 'e', NULL, &opt, "pattern", "match <pattern>", PARSE_OPT_NONEG, pattern_callback }, { OPTION_CALLBACK, 0, "and", &opt, NULL, "combine patterns specified with -e", PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback }, OPT_BOOLEAN(0, "or", &dummy, ""), { OPTION_CALLBACK, 0, "not", &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback }, { OPTION_CALLBACK, '(', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, open_callback }, { OPTION_CALLBACK, ')', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, close_callback }, OPT_BOOLEAN('q', "quiet", &opt.status_only, "indicate hit with exit status without output"), OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback }, OPT_END() }; prefix = setup_git_directory_gently(&nongit); /* * 'git grep -h', unlike 'git grep -h <pattern>', is a request * to show usage information and exit. */ if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(grep_usage, options); memset(&opt, 0, sizeof(opt)); opt.prefix = prefix; opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; opt.relative = 1; opt.pathname = 1; opt.pattern_tail = &opt.pattern_list; opt.regflags = REG_NEWLINE; opt.max_depth = -1; strcpy(opt.color_match, GIT_COLOR_RED GIT_COLOR_BOLD); opt.color = -1; git_config(grep_config, &opt); if (opt.color == -1) opt.color = git_use_color_default; /* * If there is no -- then the paths must exist in the working * tree. If there is no explicit pattern specified with -e or * -f, we take the first unrecognized non option to be the * pattern, but then what follows it must be zero or more * valid refs up to the -- (if exists), and then existing * paths. If there is an explicit pattern, then the first * unrecognized non option is the beginning of the refs list * that continues up to the -- (if exists), and then paths. */ argc = parse_options(argc, argv, prefix, options, grep_usage, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_STOP_AT_NON_OPTION | PARSE_OPT_NO_INTERNAL_HELP); if (use_index && nongit) /* die the same way as if we did it at the beginning */ setup_git_directory(); /* * skip a -- separator; we know it cannot be * separating revisions from pathnames if * we haven't even had any patterns yet */ if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) { argv++; argc--; } /* First unrecognized non-option token */ if (argc > 0 && !opt.pattern_list) { append_grep_pattern(&opt, argv[0], "command line", 0, GREP_PATTERN); argv++; argc--; } if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) opt.regflags |= REG_ICASE; if ((opt.regflags != REG_NEWLINE) && opt.fixed) die("cannot mix --fixed-strings and regexp"); #ifndef NO_PTHREADS if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; if (use_threads) start_threads(&opt); #else use_threads = 0; #endif compile_grep_patterns(&opt); /* Check revs and then paths */ for (i = 0; i < argc; i++) { const char *arg = argv[i]; unsigned char sha1[20]; /* Is it a rev? */ if (!get_sha1(arg, sha1)) { struct object *object = parse_object(sha1); if (!object) die("bad object %s", arg); add_object_array(object, arg, &list); continue; } if (!strcmp(arg, "--")) { i++; seen_dashdash = 1; } break; } /* The rest are paths */ if (!seen_dashdash) { int j; for (j = i; j < argc; j++) verify_filename(prefix, argv[j]); } if (i < argc) paths = get_pathspec(prefix, argv + i); else if (prefix) { paths = xcalloc(2, sizeof(const char *)); paths[0] = prefix; paths[1] = NULL; } if (!use_index) { int hit; if (cached) die("--cached cannot be used with --no-index."); if (list.nr) die("--no-index cannot be used with revs."); hit = grep_directory(&opt, paths); if (use_threads) hit |= wait_all(); return !hit; } if (!list.nr) { int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); if (use_threads) hit |= wait_all(); return !hit; } if (cached) die("both --cached and trees are given."); for (i = 0; i < list.nr; i++) { struct object *real_obj; real_obj = deref_tag(list.objects[i].item, NULL, 0); if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { hit = 1; if (opt.status_only) break; } } if (use_threads) hit |= wait_all(); free_grep_patterns(&opt); return !hit; }
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; }
int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; int cached = 0, untracked = 0, opt_exclude = -1; int seen_dashdash = 0; int external_grep_allowed__ignored; const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = OBJECT_ARRAY_INIT; const char **paths = NULL; struct pathspec pathspec; struct string_list path_list = STRING_LIST_INIT_NODUP; int i; int dummy; int use_index = 1; int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED; struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, N_("search in index instead of in the work tree")), OPT_NEGBIT(0, "no-index", &use_index, N_("find in contents not managed by git"), 1), OPT_BOOLEAN(0, "untracked", &untracked, N_("search in both tracked and untracked files")), OPT_SET_INT(0, "exclude-standard", &opt_exclude, N_("search also in ignored files"), 1), OPT_GROUP(""), OPT_BOOLEAN('v', "invert-match", &opt.invert, N_("show non-matching lines")), OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case, N_("case insensitive matching")), OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp, N_("match patterns only at word boundaries")), OPT_SET_INT('a', "text", &opt.binary, N_("process binary files as text"), GREP_BINARY_TEXT), OPT_SET_INT('I', NULL, &opt.binary, N_("don't match patterns in binary files"), GREP_BINARY_NOMATCH), { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"), N_("descend at most <depth> levels"), PARSE_OPT_NONEG, NULL, 1 }, OPT_GROUP(""), OPT_SET_INT('E', "extended-regexp", &pattern_type_arg, N_("use extended POSIX regular expressions"), GREP_PATTERN_TYPE_ERE), OPT_SET_INT('G', "basic-regexp", &pattern_type_arg, N_("use basic POSIX regular expressions (default)"), GREP_PATTERN_TYPE_BRE), OPT_SET_INT('F', "fixed-strings", &pattern_type_arg, N_("interpret patterns as fixed strings"), GREP_PATTERN_TYPE_FIXED), OPT_SET_INT('P', "perl-regexp", &pattern_type_arg, N_("use Perl-compatible regular expressions"), GREP_PATTERN_TYPE_PCRE), OPT_GROUP(""), OPT_BOOLEAN('n', "line-number", &opt.linenum, N_("show line numbers")), OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1), OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1), OPT_NEGBIT(0, "full-name", &opt.relative, N_("show filenames relative to top directory"), 1), OPT_BOOLEAN('l', "files-with-matches", &opt.name_only, N_("show only filenames instead of matching lines")), OPT_BOOLEAN(0, "name-only", &opt.name_only, N_("synonym for --files-with-matches")), OPT_BOOLEAN('L', "files-without-match", &opt.unmatch_name_only, N_("show only the names of files without match")), OPT_BOOLEAN('z', "null", &opt.null_following_name, N_("print NUL after filenames")), OPT_BOOLEAN('c', "count", &opt.count, N_("show the number of matches instead of matching lines")), OPT__COLOR(&opt.color, N_("highlight matches")), OPT_BOOLEAN(0, "break", &opt.file_break, N_("print empty line between matches from different files")), OPT_BOOLEAN(0, "heading", &opt.heading, N_("show filename only once above matches from same file")), OPT_GROUP(""), OPT_CALLBACK('C', "context", &opt, N_("n"), N_("show <n> context lines before and after matches"), context_callback), OPT_INTEGER('B', "before-context", &opt.pre_context, N_("show <n> context lines before matches")), OPT_INTEGER('A', "after-context", &opt.post_context, N_("show <n> context lines after matches")), OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"), context_callback), OPT_BOOLEAN('p', "show-function", &opt.funcname, N_("show a line with the function name before matches")), OPT_BOOLEAN('W', "function-context", &opt.funcbody, N_("show the surrounding function")), OPT_GROUP(""), OPT_CALLBACK('f', NULL, &opt, N_("file"), N_("read patterns from file"), file_callback), { OPTION_CALLBACK, 'e', NULL, &opt, N_("pattern"), N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback }, { OPTION_CALLBACK, 0, "and", &opt, NULL, N_("combine patterns specified with -e"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback }, OPT_BOOLEAN(0, "or", &dummy, ""), { OPTION_CALLBACK, 0, "not", &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback }, { OPTION_CALLBACK, '(', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, open_callback }, { OPTION_CALLBACK, ')', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, close_callback }, OPT__QUIET(&opt.status_only, N_("indicate hit with exit status without output")), OPT_BOOLEAN(0, "all-match", &opt.all_match, N_("show only matches from files that match all patterns")), { OPTION_SET_INT, 0, "debug", &opt.debug, NULL, N_("show parse tree for grep expression"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 }, OPT_GROUP(""), { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, N_("pager"), N_("show matching files in the pager"), PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, N_("allow calling of grep(1) (ignored by this build)")), { OPTION_CALLBACK, 0, "help-all", &options, NULL, N_("show usage"), PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback }, OPT_END() }; /* * 'git grep -h', unlike 'git grep -h <pattern>', is a request * to show usage information and exit. */ if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(grep_usage, options); init_grep_defaults(); git_config(grep_cmd_config, NULL); grep_init(&opt, prefix); /* * If there is no -- then the paths must exist in the working * tree. If there is no explicit pattern specified with -e or * -f, we take the first unrecognized non option to be the * pattern, but then what follows it must be zero or more * valid refs up to the -- (if exists), and then existing * paths. If there is an explicit pattern, then the first * unrecognized non option is the beginning of the refs list * that continues up to the -- (if exists), and then paths. */ argc = parse_options(argc, argv, prefix, options, grep_usage, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_STOP_AT_NON_OPTION | PARSE_OPT_NO_INTERNAL_HELP); grep_commit_pattern_type(pattern_type_arg, &opt); if (use_index && !startup_info->have_repository) /* die the same way as if we did it at the beginning */ setup_git_directory(); /* * skip a -- separator; we know it cannot be * separating revisions from pathnames if * we haven't even had any patterns yet */ if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) { argv++; argc--; } /* First unrecognized non-option token */ if (argc > 0 && !opt.pattern_list) { append_grep_pattern(&opt, argv[0], "command line", 0, GREP_PATTERN); argv++; argc--; } if (show_in_pager == default_pager) show_in_pager = git_pager(1); if (show_in_pager) { opt.color = 0; opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; string_list_append(&path_list, show_in_pager); use_threads = 0; } if ((opt.binary & GREP_BINARY_NOMATCH)) use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); if (!opt.fixed && opt.ignore_case) opt.regflags |= REG_ICASE; compile_grep_patterns(&opt); /* Check revs and then paths */ for (i = 0; i < argc; i++) { const char *arg = argv[i]; unsigned char sha1[20]; /* Is it a rev? */ if (!get_sha1(arg, sha1)) { struct object *object = parse_object(sha1); if (!object) die(_("bad object %s"), arg); add_object_array(object, arg, &list); continue; } if (!strcmp(arg, "--")) { i++; seen_dashdash = 1; } break; } #ifndef NO_PTHREADS if (list.nr || cached || online_cpus() == 1) use_threads = 0; #else use_threads = 0; #endif #ifndef NO_PTHREADS if (use_threads) { if (!(opt.name_only || opt.unmatch_name_only || opt.count) && (opt.pre_context || opt.post_context || opt.file_break || opt.funcbody)) skip_first_line = 1; start_threads(&opt); } #endif /* The rest are paths */ if (!seen_dashdash) { int j; for (j = i; j < argc; j++) verify_filename(prefix, argv[j], j == i); } paths = get_pathspec(prefix, argv + i); init_pathspec(&pathspec, paths); pathspec.max_depth = opt.max_depth; pathspec.recursive = 1; if (show_in_pager && (cached || list.nr)) die(_("--open-files-in-pager only works on the worktree")); if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { const char *pager = path_list.items[0].string; int len = strlen(pager); if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", strcmp("less", pager) ? "" : "*", opt.pattern_list->pattern); string_list_append(&path_list, buf.buf); strbuf_detach(&buf, NULL); } } if (!show_in_pager) setup_pager(); if (!use_index && (untracked || cached)) die(_("--cached or --untracked cannot be used with --no-index.")); if (!use_index || untracked) { int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude; if (list.nr) die(_("--no-index or --untracked cannot be used with revs.")); hit = grep_directory(&opt, &pathspec, use_exclude); } else if (0 <= opt_exclude) { die(_("--[no-]exclude-standard cannot be used for tracked contents.")); } else if (!list.nr) { if (!cached) setup_work_tree(); hit = grep_cache(&opt, &pathspec, cached); } else { if (cached) die(_("both --cached and trees are given.")); hit = grep_objects(&opt, &pathspec, &list); } if (use_threads) hit |= wait_all(); if (hit && show_in_pager) run_pager(&opt, prefix); free_grep_patterns(&opt); return !hit; }
/* * on successful case, it's up to the caller to close cmd->out */ static int do_reachable_revlist(struct child_process *cmd, struct object_array *src, struct object_array *reachable) { static const char *argv[] = { "rev-list", "--stdin", NULL, }; struct object *o; char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */ int i; cmd->argv = argv; cmd->git_cmd = 1; cmd->no_stderr = 1; cmd->in = -1; cmd->out = -1; /* * If the next rev-list --stdin encounters an unknown commit, * it terminates, which will cause SIGPIPE in the write loop * below. */ sigchain_push(SIGPIPE, SIG_IGN); if (start_command(cmd)) goto error; namebuf[0] = '^'; namebuf[GIT_SHA1_HEXSZ + 1] = '\n'; for (i = get_max_object_index(); 0 < i; ) { o = get_indexed_object(--i); if (!o) continue; if (reachable && o->type == OBJ_COMMIT) o->flags &= ~TMP_MARK; if (!is_our_ref(o)) continue; memcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ); if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 2) < 0) goto error; } namebuf[GIT_SHA1_HEXSZ] = '\n'; for (i = 0; i < src->nr; i++) { o = src->objects[i].item; if (is_our_ref(o)) { if (reachable) add_object_array(o, NULL, reachable); continue; } if (reachable && o->type == OBJ_COMMIT) o->flags |= TMP_MARK; memcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ); if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 1) < 0) goto error; } close(cmd->in); cmd->in = -1; sigchain_pop(SIGPIPE); return 0; error: sigchain_pop(SIGPIPE); if (cmd->in >= 0) close(cmd->in); if (cmd->out >= 0) close(cmd->out); return -1; }