int create_bundle(struct bundle_header *header, const char *path, int argc, const char **argv) { static struct lock_file lock; int bundle_fd = -1; int bundle_to_stdout; const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *)); const char **argv_pack = xmalloc(5 * sizeof(const char *)); int i, ref_count = 0; char buffer[1024]; struct rev_info revs; int read_from_stdin = 0; struct child_process rls; FILE *rls_fout; bundle_to_stdout = !strcmp(path, "-"); if (bundle_to_stdout) bundle_fd = 1; else bundle_fd = hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR); /* write signature */ write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature)); /* init revs to list objects for pack-objects later */ save_commit_buffer = 0; init_revisions(&revs, NULL); /* write prerequisites */ memcpy(argv_boundary + 3, argv + 1, argc * sizeof(const char *)); argv_boundary[0] = "rev-list"; argv_boundary[1] = "--boundary"; argv_boundary[2] = "--pretty=oneline"; argv_boundary[argc + 2] = NULL; memset(&rls, 0, sizeof(rls)); rls.argv = argv_boundary; rls.out = -1; rls.git_cmd = 1; if (start_command(&rls)) return -1; rls_fout = fdopen(rls.out, "r"); while (fgets(buffer, sizeof(buffer), rls_fout)) { unsigned char sha1[20]; if (buffer[0] == '-') { write_or_die(bundle_fd, buffer, strlen(buffer)); if (!get_sha1_hex(buffer + 1, sha1)) { struct object *object = parse_object(sha1); object->flags |= UNINTERESTING; add_pending_object(&revs, object, buffer); } } else if (!get_sha1_hex(buffer, sha1)) { struct object *object = parse_object(sha1); object->flags |= SHOWN; } } fclose(rls_fout); if (finish_command(&rls)) return error("rev-list died"); /* write references */ argc = setup_revisions(argc, argv, &revs, NULL); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--stdin")) { if (read_from_stdin++) die("--stdin given twice?"); read_revisions_from_stdin(&revs); continue; } return error("unrecognized argument: %s'", argv[i]); } for (i = 0; i < revs.pending.nr; i++) { struct object_array_entry *e = revs.pending.objects + i; unsigned char sha1[20]; char *ref; const char *display_ref; int flag; if (e->item->flags & UNINTERESTING) continue; if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1) continue; if (!resolve_ref(e->name, sha1, 1, &flag)) flag = 0; display_ref = (flag & REF_ISSYMREF) ? e->name : ref; /* * Make sure the refs we wrote out is correct; --max-count and * other limiting options could have prevented all the tips * from getting output. * * Non commit objects such as tags and blobs do not have * this issue as they are not affected by those extra * constraints. */ if (!(e->item->flags & SHOWN) && e->item->type == OBJ_COMMIT) { warning("ref '%s' is excluded by the rev-list options", e->name); free(ref); continue; } /* * If you run "git bundle create bndl v1.0..v2.0", the * name of the positive ref is "v2.0" but that is the * commit that is referenced by the tag, and not the tag * itself. */ if (hashcmp(sha1, e->item->sha1)) { /* * Is this the positive end of a range expressed * in terms of a tag (e.g. v2.0 from the range * "v1.0..v2.0")? */ struct commit *one = lookup_commit_reference(sha1); struct object *obj; if (e->item == &(one->object)) { /* * Need to include e->name as an * independent ref to the pack-objects * input, so that the tag is included * in the output; otherwise we would * end up triggering "empty bundle" * error. */ obj = parse_object(sha1); obj->flags |= SHOWN; add_pending_object(&revs, obj, e->name); } free(ref); continue; } ref_count++; write_or_die(bundle_fd, sha1_to_hex(e->item->sha1), 40); write_or_die(bundle_fd, " ", 1); write_or_die(bundle_fd, display_ref, strlen(display_ref)); write_or_die(bundle_fd, "\n", 1); free(ref); } if (!ref_count) die ("Refusing to create empty bundle."); /* end header */ write_or_die(bundle_fd, "\n", 1); /* write pack */ argv_pack[0] = "pack-objects"; argv_pack[1] = "--all-progress"; argv_pack[2] = "--stdout"; argv_pack[3] = "--thin"; argv_pack[4] = NULL; memset(&rls, 0, sizeof(rls)); rls.argv = argv_pack; rls.in = -1; rls.out = bundle_fd; rls.git_cmd = 1; if (start_command(&rls)) return error("Could not spawn pack-objects"); /* * start_command closed bundle_fd if it was > 1 * so set the lock fd to -1 so commit_lock_file() * won't fail trying to close it. */ lock.fd = -1; for (i = 0; i < revs.pending.nr; i++) { struct object *object = revs.pending.objects[i].item; if (object->flags & UNINTERESTING) write_or_die(rls.in, "^", 1); write_or_die(rls.in, sha1_to_hex(object->sha1), 40); write_or_die(rls.in, "\n", 1); } close(rls.in); if (finish_command(&rls)) return error ("pack-objects died"); if (!bundle_to_stdout) commit_lock_file(&lock); return 0; }
int cmd_rev_list(int argc, const char **argv, const char *prefix) { struct commit_list *list; int i; int read_from_stdin = 0; int bisect_show_vars = 0; int bisect_find_all = 0; int quiet = 0; git_config(git_default_config, NULL); init_revisions(&revs, prefix); revs.abbrev = 0; revs.commit_format = CMIT_FMT_UNSPECIFIED; argc = setup_revisions(argc, argv, &revs, NULL); quiet = DIFF_OPT_TST(&revs.diffopt, QUIET); for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--header")) { revs.verbose_header = 1; continue; } if (!strcmp(arg, "--timestamp")) { show_timestamp = 1; continue; } if (!strcmp(arg, "--bisect")) { bisect_list = 1; continue; } if (!strcmp(arg, "--bisect-all")) { bisect_list = 1; bisect_find_all = 1; continue; } if (!strcmp(arg, "--bisect-vars")) { bisect_list = 1; bisect_show_vars = 1; continue; } if (!strcmp(arg, "--stdin")) { if (read_from_stdin++) die("--stdin given twice?"); read_revisions_from_stdin(&revs); continue; } usage(rev_list_usage); } if (revs.commit_format != CMIT_FMT_UNSPECIFIED) { /* The command line has a --pretty */ hdr_termination = '\n'; if (revs.commit_format == CMIT_FMT_ONELINE) header_prefix = ""; else header_prefix = "commit "; } else if (revs.verbose_header) /* Only --header was specified */ revs.commit_format = CMIT_FMT_RAW; list = revs.commits; if ((!list && (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending.nr)) || revs.diff) usage(rev_list_usage); save_commit_buffer = revs.verbose_header || revs.grep_filter; if (bisect_list) revs.limited = 1; if (prepare_revision_walk(&revs)) die("revision walk setup failed"); if (revs.tree_objects) mark_edges_uninteresting(revs.commits, &revs, show_edge); if (bisect_list) { int reaches = reaches, all = all; revs.commits = find_bisection(revs.commits, &reaches, &all, bisect_find_all); if (bisect_show_vars) { int cnt; char hex[41]; if (!revs.commits) return 1; /* * revs.commits can reach "reaches" commits among * "all" commits. If it is good, then there are * (all-reaches) commits left to be bisected. * On the other hand, if it is bad, then the set * to bisect is "reaches". * A bisect set of size N has (N-1) commits further * to test, as we already know one bad one. */ cnt = all - reaches; if (cnt < reaches) cnt = reaches; strcpy(hex, sha1_to_hex(revs.commits->item->object.sha1)); if (bisect_find_all) { traverse_commit_list(&revs, show_commit, show_object); printf("------\n"); } printf("bisect_rev=%s\n" "bisect_nr=%d\n" "bisect_good=%d\n" "bisect_bad=%d\n" "bisect_all=%d\n", hex, cnt - 1, all - reaches - 1, reaches - 1, all); return 0; } } traverse_commit_list(&revs, quiet ? finish_commit : show_commit, quiet ? finish_object : show_object); return 0; }
int cmd_rev_list(int argc, const char **argv, const char *prefix) { struct rev_info revs; struct rev_list_info info; int i; int read_from_stdin = 0; int bisect_list = 0; int bisect_show_vars = 0; int bisect_find_all = 0; int quiet = 0; git_config(git_default_config, NULL); init_revisions(&revs, prefix); revs.abbrev = 0; revs.commit_format = CMIT_FMT_UNSPECIFIED; argc = setup_revisions(argc, argv, &revs, NULL); memset(&info, 0, sizeof(info)); info.revs = &revs; quiet = DIFF_OPT_TST(&revs.diffopt, QUIET); for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--header")) { revs.verbose_header = 1; continue; } if (!strcmp(arg, "--timestamp")) { info.show_timestamp = 1; continue; } if (!strcmp(arg, "--bisect")) { bisect_list = 1; continue; } if (!strcmp(arg, "--bisect-all")) { bisect_list = 1; bisect_find_all = 1; info.bisect_show_flags = BISECT_SHOW_ALL; revs.show_decorations = 1; continue; } if (!strcmp(arg, "--bisect-vars")) { bisect_list = 1; bisect_show_vars = 1; continue; } if (!strcmp(arg, "--stdin")) { if (read_from_stdin++) die("--stdin given twice?"); read_revisions_from_stdin(&revs); continue; } usage(rev_list_usage); } if (revs.commit_format != CMIT_FMT_UNSPECIFIED) { /* The command line has a --pretty */ info.hdr_termination = '\n'; if (revs.commit_format == CMIT_FMT_ONELINE) info.header_prefix = ""; else info.header_prefix = "commit "; } else if (revs.verbose_header) /* Only --header was specified */ revs.commit_format = CMIT_FMT_RAW; if ((!revs.commits && (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending.nr)) || revs.diff) usage(rev_list_usage); save_commit_buffer = revs.verbose_header || revs.grep_filter.pattern_list; if (bisect_list) revs.limited = 1; if (prepare_revision_walk(&revs)) die("revision walk setup failed"); if (revs.tree_objects) mark_edges_uninteresting(revs.commits, &revs, show_edge); if (bisect_list) { int reaches = reaches, all = all; revs.commits = find_bisection(revs.commits, &reaches, &all, bisect_find_all); if (bisect_show_vars) return show_bisect_vars(&info, reaches, all); } traverse_commit_list(&revs, quiet ? finish_commit : show_commit, quiet ? finish_object : show_object, &info); return 0; }