Esempio n. 1
0
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]);
    }

    object_array_remove_duplicates(&revs.pending);

    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;

        if (e->item->type == OBJ_TAG &&
                !is_tag_in_date_range(e->item, &revs)) {
            e->item->flags |= UNINTERESTING;
            continue;
        }

        /*
         * 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 rev_info revs;
	struct rev_list_info info;
	int i;
	int bisect_list = 0;
	int bisect_show_vars = 0;
	int bisect_find_all = 0;

	git_config(git_default_config, NULL);
	init_revisions(&revs, prefix);
	revs.abbrev = DEFAULT_ABBREV;
	revs.commit_format = CMIT_FMT_UNSPECIFIED;
	argc = setup_revisions(argc, argv, &revs, NULL);

	memset(&info, 0, sizeof(info));
	info.revs = &revs;
	if (revs.bisect)
		bisect_list = 1;

	if (DIFF_OPT_TST(&revs.diffopt, QUICK))
		info.flags |= REV_LIST_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.flags |= BISECT_SHOW_ALL;
			revs.show_decorations = 1;
			continue;
		}
		if (!strcmp(arg, "--bisect-vars")) {
			bisect_list = 1;
			bisect_show_vars = 1;
			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 ||
			      revs.grep_filter.header_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 = 0, all = 0;

		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, show_commit, show_object, &info);

	if (revs.count) {
		if (revs.left_right && revs.cherry_mark)
			printf("%d\t%d\t%d\n", revs.count_left, revs.count_right, revs.count_same);
		else if (revs.left_right)
			printf("%d\t%d\n", revs.count_left, revs.count_right);
		else if (revs.cherry_mark)
			printf("%d\t%d\n", revs.count_left + revs.count_right, revs.count_same);
		else
			printf("%d\n", revs.count_left + revs.count_right);
	}

	return 0;
}
Esempio n. 3
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 bisect_list = 0;
	int bisect_show_vars = 0;
	int bisect_find_all = 0;
	int use_bitmap_index = 0;
	const char *show_progress = NULL;

	if (argc == 2 && !strcmp(argv[1], "-h"))
		usage(rev_list_usage);

	git_config(git_default_config, NULL);
	init_revisions(&revs, prefix);
	revs.abbrev = DEFAULT_ABBREV;
	revs.commit_format = CMIT_FMT_UNSPECIFIED;
	argc = setup_revisions(argc, argv, &revs, NULL);

	memset(&info, 0, sizeof(info));
	info.revs = &revs;
	if (revs.bisect)
		bisect_list = 1;

	if (DIFF_OPT_TST(&revs.diffopt, QUICK))
		info.flags |= REV_LIST_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.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, "--use-bitmap-index")) {
			use_bitmap_index = 1;
			continue;
		}
		if (!strcmp(arg, "--test-bitmap")) {
			test_bitmap_walk(&revs);
			return 0;
		}
		if (skip_prefix(arg, "--progress=", &arg)) {
			show_progress = arg;
			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);

	if (revs.show_notes)
		die(_("rev-list does not support display of notes"));

	save_commit_buffer = (revs.verbose_header ||
			      revs.grep_filter.pattern_list ||
			      revs.grep_filter.header_list);
	if (bisect_list)
		revs.limited = 1;

	if (show_progress)
		progress = start_progress_delay(show_progress, 0, 0, 2);

	if (use_bitmap_index && !revs.prune) {
		if (revs.count && !revs.left_right && !revs.cherry_mark) {
			uint32_t commit_count;
			int max_count = revs.max_count;
			if (!prepare_bitmap_walk(&revs)) {
				count_bitmap_commit_list(&commit_count, NULL, NULL, NULL);
				if (max_count >= 0 && max_count < commit_count)
					commit_count = max_count;
				printf("%d\n", commit_count);
				return 0;
			}
		} else if (revs.max_count < 0 &&
			   revs.tag_objects && revs.tree_objects && revs.blob_objects) {
			if (!prepare_bitmap_walk(&revs)) {
				traverse_bitmap_commit_list(&show_object_fast);
				return 0;
			}
		}
	}

	if (prepare_revision_walk(&revs))
		die("revision walk setup failed");
	if (revs.tree_objects)
		mark_edges_uninteresting(&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, show_commit, show_object, &info);

	stop_progress(&progress);

	if (revs.count) {
		if (revs.left_right && revs.cherry_mark)
			printf("%d\t%d\t%d\n", revs.count_left, revs.count_right, revs.count_same);
		else if (revs.left_right)
			printf("%d\t%d\n", revs.count_left, revs.count_right);
		else if (revs.cherry_mark)
			printf("%d\t%d\n", revs.count_left + revs.count_right, revs.count_same);
		else
			printf("%d\n", revs.count_left + revs.count_right);
	}

	return 0;
}
Esempio n. 4
0
static void parse_args(int argc, const char **argv, struct replay_opts *opts)
{
	const char * const * usage_str = revert_or_cherry_pick_usage(opts);
	const char *me = action_name(opts);
	int remove_state = 0;
	int contin = 0;
	int rollback = 0;
	struct option options[] = {
		OPT_BOOLEAN(0, "quit", &remove_state, N_("end revert or cherry-pick sequence")),
		OPT_BOOLEAN(0, "continue", &contin, N_("resume revert or cherry-pick sequence")),
		OPT_BOOLEAN(0, "abort", &rollback, N_("cancel revert or cherry-pick sequence")),
		OPT_BOOLEAN('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
		OPT_BOOLEAN('e', "edit", &opts->edit, N_("edit the commit message")),
		OPT_NOOP_NOARG('r', NULL),
		OPT_BOOLEAN('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
		OPT_INTEGER('m', "mainline", &opts->mainline, N_("parent number")),
		OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
		OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
		OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
			N_("option for merge strategy"), option_parse_x),
		OPT_END(),
		OPT_END(),
		OPT_END(),
		OPT_END(),
		OPT_END(),
		OPT_END(),
	};

	if (opts->action == REPLAY_PICK) {
		struct option cp_extra[] = {
			OPT_BOOLEAN('x', NULL, &opts->record_origin, N_("append commit name")),
			OPT_BOOLEAN(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
			OPT_BOOLEAN(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
			OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")),
			OPT_END(),
		};
		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
			die(_("program error"));
	}

	argc = parse_options(argc, argv, NULL, options, usage_str,
			PARSE_OPT_KEEP_ARGV0 |
			PARSE_OPT_KEEP_UNKNOWN);

	/* Check for incompatible subcommands */
	verify_opt_mutually_compatible(me,
				"--quit", remove_state,
				"--continue", contin,
				"--abort", rollback,
				NULL);

	/* implies allow_empty */
	if (opts->keep_redundant_commits)
		opts->allow_empty = 1;

	/* Set the subcommand */
	if (remove_state)
		opts->subcommand = REPLAY_REMOVE_STATE;
	else if (contin)
		opts->subcommand = REPLAY_CONTINUE;
	else if (rollback)
		opts->subcommand = REPLAY_ROLLBACK;
	else
		opts->subcommand = REPLAY_NONE;

	/* Check for incompatible command line arguments */
	if (opts->subcommand != REPLAY_NONE) {
		char *this_operation;
		if (opts->subcommand == REPLAY_REMOVE_STATE)
			this_operation = "--quit";
		else if (opts->subcommand == REPLAY_CONTINUE)
			this_operation = "--continue";
		else {
			assert(opts->subcommand == REPLAY_ROLLBACK);
			this_operation = "--abort";
		}

		verify_opt_compatible(me, this_operation,
				"--no-commit", opts->no_commit,
				"--signoff", opts->signoff,
				"--mainline", opts->mainline,
				"--strategy", opts->strategy ? 1 : 0,
				"--strategy-option", opts->xopts ? 1 : 0,
				"-x", opts->record_origin,
				"--ff", opts->allow_ff,
				NULL);
	}

	if (opts->allow_ff)
		verify_opt_compatible(me, "--ff",
				"--signoff", opts->signoff,
				"--no-commit", opts->no_commit,
				"-x", opts->record_origin,
				"--edit", opts->edit,
				NULL);

	if (opts->subcommand != REPLAY_NONE) {
		opts->revs = NULL;
	} else {
		struct setup_revision_opt s_r_opt;
		opts->revs = xmalloc(sizeof(*opts->revs));
		init_revisions(opts->revs, NULL);
		opts->revs->no_walk = 1;
		if (argc < 2)
			usage_with_options(usage_str, options);
		memset(&s_r_opt, 0, sizeof(s_r_opt));
		s_r_opt.assume_dashdash = 1;
		argc = setup_revisions(argc, argv, opts->revs, &s_r_opt);
	}

	if (argc > 1)
		usage_with_options(usage_str, options);
}
Esempio n. 5
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);
	init_revisions(&revs, prefix);
	revs.abbrev = 0;
	revs.commit_format = CMIT_FMT_UNSPECIFIED;
	argc = setup_revisions(argc, argv, &revs, NULL);

	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;
		}
		if (!strcmp(arg, "--quiet")) {
			quiet = 1;
			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;
}
Esempio n. 6
0
static void print_object(const unsigned char *sha1, const char *path,
			 const char *basename, const char *rev)
{
	enum object_type type;
	char *buf;
	unsigned long size;
	struct argv_array rev_argv = ARGV_ARRAY_INIT;
	struct rev_info revs;
	struct blame_scoreboard sb;
	struct blame_origin *o;
	struct blame_entry *ent = NULL;

	type = sha1_object_info(sha1, &size);
	if (type == OBJ_BAD) {
		cgit_print_error_page(404, "Not found", "Bad object name: %s",
				      sha1_to_hex(sha1));
		return;
	}

	buf = read_sha1_file(sha1, &type, &size);
	if (!buf) {
		cgit_print_error_page(500, "Internal server error",
			"Error reading object %s", sha1_to_hex(sha1));
		return;
	}

	argv_array_push(&rev_argv, "blame");
	argv_array_push(&rev_argv, rev);
	init_revisions(&revs, NULL);
	revs.diffopt.flags.allow_textconv = 1;
	setup_revisions(rev_argv.argc, rev_argv.argv, &revs, NULL);
	init_scoreboard(&sb);
	sb.revs = &revs;
	setup_scoreboard(&sb, path, &o);
	o->suspects = blame_entry_prepend(NULL, 0, sb.num_lines, o);
	prio_queue_put(&sb.commits, o->commit);
	blame_origin_decref(o);
	sb.ent = NULL;
	sb.path = path;
	assign_blame(&sb, 0);
	blame_sort_final(&sb);
	blame_coalesce(&sb);

	cgit_set_title_from_path(path);

	cgit_print_layout_start();
	htmlf("blob: %s (", sha1_to_hex(sha1));
	cgit_plain_link("plain", NULL, NULL, ctx.qry.head, rev, path);
	html(") (");
	cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path);
	html(")\n");

	if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) {
		htmlf("<div class='error'>blob size (%ldKB)"
		      " exceeds display size limit (%dKB).</div>",
		      size / 1024, ctx.cfg.max_blob_size);
		return;
	}

	html("<table class='blame blob'>\n<tr>\n");

	/* Commit hashes */
	html("<td class='hashes'>");
	for (ent = sb.ent; ent; ent = ent->next) {
		html("<div class='alt'><pre>");
		emit_blame_entry_hash(ent);
		html("</pre></div>");
	}
	html("</td>\n");

	/* Line numbers */
	if (ctx.cfg.enable_tree_linenumbers) {
		html("<td class='linenumbers'>");
		for (ent = sb.ent; ent; ent = ent->next) {
			html("<div class='alt'><pre>");
			emit_blame_entry_linenumber(ent);
			html("</pre></div>");
		}
		html("</td>\n");
	}

	html("<td class='lines'><div>");

	/* Colored bars behind lines */
	html("<div>");
	for (ent = sb.ent; ent; ) {
		struct blame_entry *e = ent->next;
		html("<div class='alt'><pre>");
		emit_blame_entry_line_background(&sb, ent);
		html("</pre></div>");
		free(ent);
		ent = e;
	}
	html("</div>");

	free((void *)sb.final_buf);

	/* Lines */
	html("<pre><code>");
	if (ctx.repo->source_filter) {
		char *filter_arg = xstrdup(basename);
		cgit_open_filter(ctx.repo->source_filter, filter_arg);
		html_raw(buf, size);
		cgit_close_filter(ctx.repo->source_filter);
		free(filter_arg);
	} else {
		html_txt(buf);
	}
	html("</code></pre>");

	html("</div></td>\n");

	html("</tr>\n</table>\n");

	cgit_print_layout_end();
}
Esempio n. 7
0
int cmd_format_patch(int argc, const char **argv, const char *prefix)
{
	struct commit *commit;
	struct commit **list = NULL;
	struct rev_info rev;
	int nr = 0, total, i, j;
	int use_stdout = 0;
	int start_number = -1;
	int keep_subject = 0;
	int numbered_files = 0;		/* _just_ numbers */
	int subject_prefix = 0;
	int ignore_if_in_upstream = 0;
	int thread = 0;
	int cover_letter = 0;
	int boundary_count = 0;
	int no_binary_diff = 0;
	struct commit *origin = NULL, *head = NULL;
	const char *in_reply_to = NULL;
	struct patch_ids ids;
	char *add_signoff = NULL;
	struct strbuf buf;

	git_config(git_format_config, NULL);
	init_revisions(&rev, prefix);
	rev.commit_format = CMIT_FMT_EMAIL;
	rev.verbose_header = 1;
	rev.diff = 1;
	rev.combine_merges = 0;
	rev.ignore_merges = 1;
	DIFF_OPT_SET(&rev.diffopt, RECURSIVE);

	rev.subject_prefix = fmt_patch_subject_prefix;

	/*
	 * Parse the arguments before setup_revisions(), or something
	 * like "git format-patch -o a123 HEAD^.." may fail; a123 is
	 * possibly a valid SHA1.
	 */
	for (i = 1, j = 1; i < argc; i++) {
		if (!strcmp(argv[i], "--stdout"))
			use_stdout = 1;
		else if (!strcmp(argv[i], "-n") ||
				!strcmp(argv[i], "--numbered"))
			numbered = 1;
		else if (!strcmp(argv[i], "-N") ||
				!strcmp(argv[i], "--no-numbered")) {
			numbered = 0;
			auto_number = 0;
		}
		else if (!prefixcmp(argv[i], "--start-number="))
			start_number = strtol(argv[i] + 15, NULL, 10);
		else if (!strcmp(argv[i], "--numbered-files"))
			numbered_files = 1;
		else if (!strcmp(argv[i], "--start-number")) {
			i++;
			if (i == argc)
				die("Need a number for --start-number");
			start_number = strtol(argv[i], NULL, 10);
		}
		else if (!prefixcmp(argv[i], "--cc=")) {
			ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc);
			extra_cc[extra_cc_nr++] = xstrdup(argv[i] + 5);
		}
		else if (!strcmp(argv[i], "-k") ||
				!strcmp(argv[i], "--keep-subject")) {
			keep_subject = 1;
			rev.total = -1;
		}
		else if (!strcmp(argv[i], "--output-directory") ||
			 !strcmp(argv[i], "-o")) {
			i++;
			if (argc <= i)
				die("Which directory?");
			if (output_directory)
				die("Two output directories?");
			output_directory = argv[i];
		}
		else if (!strcmp(argv[i], "--signoff") ||
			 !strcmp(argv[i], "-s")) {
			const char *committer;
			const char *endpos;
			committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
			endpos = strchr(committer, '>');
			if (!endpos)
				die("bogos committer info %s\n", committer);
			add_signoff = xmemdupz(committer, endpos - committer + 1);
		}
		else if (!strcmp(argv[i], "--attach")) {
			rev.mime_boundary = git_version_string;
			rev.no_inline = 1;
		}
		else if (!prefixcmp(argv[i], "--attach=")) {
			rev.mime_boundary = argv[i] + 9;
			rev.no_inline = 1;
		}
		else if (!strcmp(argv[i], "--inline")) {
			rev.mime_boundary = git_version_string;
			rev.no_inline = 0;
		}
		else if (!prefixcmp(argv[i], "--inline=")) {
			rev.mime_boundary = argv[i] + 9;
			rev.no_inline = 0;
		}
		else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
			ignore_if_in_upstream = 1;
		else if (!strcmp(argv[i], "--thread"))
			thread = 1;
		else if (!prefixcmp(argv[i], "--in-reply-to="))
			in_reply_to = argv[i] + 14;
		else if (!strcmp(argv[i], "--in-reply-to")) {
			i++;
			if (i == argc)
				die("Need a Message-Id for --in-reply-to");
			in_reply_to = argv[i];
		} else if (!prefixcmp(argv[i], "--subject-prefix=")) {
			subject_prefix = 1;
			rev.subject_prefix = argv[i] + 17;
		} else if (!prefixcmp(argv[i], "--suffix="))
			fmt_patch_suffix = argv[i] + 9;
		else if (!strcmp(argv[i], "--cover-letter"))
			cover_letter = 1;
		else if (!strcmp(argv[i], "--no-binary"))
			no_binary_diff = 1;
		else
			argv[j++] = argv[i];
	}
	argc = j;

	strbuf_init(&buf, 0);

	for (i = 0; i < extra_hdr_nr; i++) {
		strbuf_addstr(&buf, extra_hdr[i]);
		strbuf_addch(&buf, '\n');
	}

	if (extra_to_nr)
		strbuf_addstr(&buf, "To: ");
	for (i = 0; i < extra_to_nr; i++) {
		if (i)
			strbuf_addstr(&buf, "    ");
		strbuf_addstr(&buf, extra_to[i]);
		if (i + 1 < extra_to_nr)
			strbuf_addch(&buf, ',');
		strbuf_addch(&buf, '\n');
	}

	if (extra_cc_nr)
		strbuf_addstr(&buf, "Cc: ");
	for (i = 0; i < extra_cc_nr; i++) {
		if (i)
			strbuf_addstr(&buf, "    ");
		strbuf_addstr(&buf, extra_cc[i]);
		if (i + 1 < extra_cc_nr)
			strbuf_addch(&buf, ',');
		strbuf_addch(&buf, '\n');
	}

	rev.extra_headers = strbuf_detach(&buf, 0);

	if (start_number < 0)
		start_number = 1;
	if (numbered && keep_subject)
		die ("-n and -k are mutually exclusive.");
	if (keep_subject && subject_prefix)
		die ("--subject-prefix and -k are mutually exclusive.");
	if (numbered_files && use_stdout)
		die ("--numbered-files and --stdout are mutually exclusive.");

	argc = setup_revisions(argc, argv, &rev, "HEAD");
	if (argc > 1)
		die ("unrecognized argument: %s", argv[1]);

	if (!rev.diffopt.output_format)
		rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_PATCH;

	if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)
		DIFF_OPT_SET(&rev.diffopt, BINARY);

	if (!output_directory && !use_stdout)
		output_directory = prefix;

	if (output_directory) {
		if (use_stdout)
			die("standard output, or directory, which one?");
		if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
			die("Could not create directory %s",
			    output_directory);
	}

	if (rev.pending.nr == 1) {
		if (rev.max_count < 0 && !rev.show_root_diff) {
			/*
			 * This is traditional behaviour of "git format-patch
			 * origin" that prepares what the origin side still
			 * does not have.
			 */
			rev.pending.objects[0].item->flags |= UNINTERESTING;
			add_head_to_pending(&rev);
		}
		/*
		 * Otherwise, it is "format-patch -22 HEAD", and/or
		 * "format-patch --root HEAD".  The user wants
		 * get_revision() to do the usual traversal.
		 */
	}
	if (cover_letter) {
		/* remember the range */
		int i;
		for (i = 0; i < rev.pending.nr; i++) {
			struct object *o = rev.pending.objects[i].item;
			if (!(o->flags & UNINTERESTING))
				head = (struct commit *)o;
		}
		/* We can't generate a cover letter without any patches */
		if (!head)
			return 0;
	}

	if (ignore_if_in_upstream)
		get_patch_ids(&rev, &ids, prefix);

	if (!use_stdout)
		realstdout = xfdopen(xdup(1), "w");

	if (prepare_revision_walk(&rev))
		die("revision walk setup failed");
	rev.boundary = 1;
	while ((commit = get_revision(&rev)) != NULL) {
		if (commit->object.flags & BOUNDARY) {
			boundary_count++;
			origin = (boundary_count == 1) ? commit : NULL;
			continue;
		}

		/* ignore merges */
		if (commit->parents && commit->parents->next)
			continue;

		if (ignore_if_in_upstream &&
				has_commit_patch_id(commit, &ids))
			continue;

		nr++;
		list = xrealloc(list, nr * sizeof(list[0]));
		list[nr - 1] = commit;
	}
	total = nr;
	if (!keep_subject && auto_number && total > 1)
		numbered = 1;
	if (numbered)
		rev.total = total + start_number - 1;
	if (in_reply_to)
		rev.ref_message_id = clean_message_id(in_reply_to);
	if (cover_letter) {
		if (thread)
			gen_message_id(&rev, "cover");
		make_cover_letter(&rev, use_stdout, numbered, numbered_files,
				  origin, nr, list, head);
		total++;
		start_number--;
	}
	rev.add_signoff = add_signoff;
	while (0 <= --nr) {
		int shown;
		commit = list[nr];
		rev.nr = total - nr + (start_number - 1);
		/* Make the second and subsequent mails replies to the first */
		if (thread) {
			/* Have we already had a message ID? */
			if (rev.message_id) {
				/*
				 * If we've got the ID to be a reply
				 * to, discard the current ID;
				 * otherwise, make everything a reply
				 * to that.
				 */
				if (rev.ref_message_id)
					free(rev.message_id);
				else
					rev.ref_message_id = rev.message_id;
			}
			gen_message_id(&rev, sha1_to_hex(commit->object.sha1));
		}
		if (!use_stdout && reopen_stdout(numbered_files ? NULL :
				get_oneline_for_filename(commit, keep_subject),
				rev.nr, rev.total))
			die("Failed to create output files");
		shown = log_tree_commit(&rev, commit);
		free(commit->buffer);
		commit->buffer = NULL;

		/* We put one extra blank line between formatted
		 * patches and this flag is used by log-tree code
		 * to see if it needs to emit a LF before showing
		 * the log; when using one file per patch, we do
		 * not want the extra blank line.
		 */
		if (!use_stdout)
			rev.shown_one = 0;
		if (shown) {
			if (rev.mime_boundary)
				printf("\n--%s%s--\n\n\n",
				       mime_boundary_leader,
				       rev.mime_boundary);
			else
				printf("-- \n%s\n\n", git_version_string);
		}
		if (!use_stdout)
			fclose(stdout);
	}
	free(list);
	if (ignore_if_in_upstream)
		free_patch_ids(&ids);
	return 0;
}
Esempio n. 8
0
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;

#ifdef USE_CPLUSPLUS_FOR_INIT
#pragma cplusplus on
#endif

	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;

#ifdef USE_CPLUSPLUS_FOR_INIT
#pragma cplusplus reset
#endif

	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, 1))
			add_object_array(o, NULL, &merges);
	}

	/* 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, 1)) {
				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;
}
Esempio n. 9
0
void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern,
		    char *path, int pager, int commit_graph, int commit_sort)
{
	struct rev_info rev;
	struct commit *commit;
	struct vector vec = VECTOR_INIT(char *);
	int i, columns = 3;
	char *arg;

	/* First argv is NULL */
	vector_push(&vec, NULL, 0);

	if (!tip)
		tip = ctx.qry.head;
	tip = disambiguate_ref(tip);
	vector_push(&vec, &tip, 0);

	if (grep && pattern && *pattern) {
		pattern = xstrdup(pattern);
		if (!strcmp(grep, "grep") || !strcmp(grep, "author") ||
		    !strcmp(grep, "committer")) {
			arg = fmt("--%s=%s", grep, pattern);
			vector_push(&vec, &arg, 0);
		}
		if (!strcmp(grep, "range")) {
			/* Split the pattern at whitespace and add each token
			 * as a revision expression. Do not accept other
			 * rev-list options. Also, replace the previously
			 * pushed tip (it's no longer relevant).
			 */
			vec.count--;
			while ((arg = next_token(&pattern))) {
				if (*arg == '-') {
					fprintf(stderr, "Bad range expr: %s\n",
						arg);
					break;
				}
				vector_push(&vec, &arg, 0);
			}
		}
	}
	if (commit_graph) {
		static const char *graph_arg = "--graph";
		static const char *color_arg = "--color";
		vector_push(&vec, &graph_arg, 0);
		vector_push(&vec, &color_arg, 0);
		graph_set_column_colors(column_colors_html,
					COLUMN_COLORS_HTML_MAX);
	}

	if (commit_sort == 1) {
		static const char *date_order_arg = "--date-order";
		vector_push(&vec, &date_order_arg, 0);
	} else if (commit_sort == 2) {
		static const char *topo_order_arg = "--topo-order";
		vector_push(&vec, &topo_order_arg, 0);
	}

	if (path) {
		arg = "--";
		vector_push(&vec, &arg, 0);
		vector_push(&vec, &path, 0);
	}

	/* Make sure the vector is NULL-terminated */
	vector_push(&vec, NULL, 0);
	vec.count--;

	init_revisions(&rev, NULL);
	rev.abbrev = DEFAULT_ABBREV;
	rev.commit_format = CMIT_FMT_DEFAULT;
	rev.verbose_header = 1;
	rev.show_root_diff = 0;
	setup_revisions(vec.count, vec.data, &rev, NULL);
	load_ref_decorations(DECORATE_FULL_REFS);
	rev.show_decorations = 1;
	rev.grep_filter.regflags |= REG_ICASE;
	compile_grep_patterns(&rev.grep_filter);
	prepare_revision_walk(&rev);

	if (pager)
		html("<table class='list nowrap'>");

	html("<tr class='nohover'>");
	if (commit_graph)
		html("<th></th>");
	else
		html("<th class='left'>Age</th>");
	html("<th class='left'>Commit message");
	if (pager) {
		html(" (");
		cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL,
			      NULL, ctx.qry.head, ctx.qry.sha1,
			      ctx.qry.vpath, ctx.qry.ofs, ctx.qry.grep,
			      ctx.qry.search, ctx.qry.showmsg ? 0 : 1);
		html(")");
	}
	html("</th><th class='left'>Author</th>");
	if (commit_graph)
		html("<th class='left'>Age</th>");
	if (ctx.repo->enable_log_filecount) {
		html("<th class='left'>Files</th>");
		columns++;
	}
	if (ctx.repo->enable_log_linecount) {
		html("<th class='left'>Lines</th>");
		columns++;
	}
	html("</tr>\n");

	if (ofs<0)
		ofs = 0;

	for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) {
		free(commit->buffer);
		commit->buffer = NULL;
		free_commit_list(commit->parents);
		commit->parents = NULL;
	}

	for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
		print_commit(commit, &rev);
		free(commit->buffer);
		commit->buffer = NULL;
		free_commit_list(commit->parents);
		commit->parents = NULL;
	}
	if (pager) {
		html("</table><div class='pager'>");
		if (ofs > 0) {
			cgit_log_link("[prev]", NULL, NULL, ctx.qry.head,
				      ctx.qry.sha1, ctx.qry.vpath,
				      ofs - cnt, ctx.qry.grep,
				      ctx.qry.search, ctx.qry.showmsg);
			html("&nbsp;");
		}
		if ((commit = get_revision(&rev)) != NULL) {
			cgit_log_link("[next]", NULL, NULL, ctx.qry.head,
				      ctx.qry.sha1, ctx.qry.vpath,
				      ofs + cnt, ctx.qry.grep,
				      ctx.qry.search, ctx.qry.showmsg);
		}
		html("</div>");
	} else if ((commit = get_revision(&rev)) != NULL) {
		html("<tr class='nohover'><td colspan='3'>");
		cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL,
			      ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg);
		html("</td></tr>\n");
	}
}
Esempio n. 10
0
static void shortlog(const char *name,
		     struct origin_data *origin_data,
		     struct commit *head,
		     struct rev_info *rev, int limit,
		     struct strbuf *out)
{
	int i, count = 0;
	struct commit *commit;
	struct object *branch;
	struct string_list subjects = STRING_LIST_INIT_DUP;
	int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
	struct strbuf sb = STRBUF_INIT;
	const unsigned char *sha1 = origin_data->sha1;

	branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
	if (!branch || branch->type != OBJ_COMMIT)
		return;

	setup_revisions(0, NULL, rev, NULL);
	rev->ignore_merges = 1;
	add_pending_object(rev, branch, name);
	add_pending_object(rev, &head->object, "^HEAD");
	head->object.flags |= UNINTERESTING;
	if (prepare_revision_walk(rev))
		die("revision walk setup failed");
	while ((commit = get_revision(rev)) != NULL) {
		struct pretty_print_context ctx = {0};

		/* ignore merges */
		if (commit->parents && commit->parents->next)
			continue;

		count++;
		if (subjects.nr > limit)
			continue;

		format_commit_message(commit, "%s", &sb, &ctx);
		strbuf_ltrim(&sb);

		if (!sb.len)
			string_list_append(&subjects,
					   sha1_to_hex(commit->object.sha1));
		else
			string_list_append(&subjects, strbuf_detach(&sb, NULL));
	}

	if (count > limit)
		strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
	else
		strbuf_addf(out, "\n* %s:\n", name);

	if (origin_data->is_local_branch && use_branch_desc)
		add_branch_desc(out, name);

	for (i = 0; i < subjects.nr; i++)
		if (i >= limit)
			strbuf_addf(out, "  ...\n");
		else
			strbuf_addf(out, "  %s\n", subjects.items[i].string);

	clear_commit_marks((struct commit *)branch, flags);
	clear_commit_marks(head, flags);
	free_commit_list(rev->commits);
	rev->commits = NULL;
	rev->pending.nr = 0;

	string_list_clear(&subjects, 0);
}
Esempio n. 11
0
int cmd_main(int argc, const char **argv)
{
	struct transfer_request *request;
	struct transfer_request *next_request;
	int nr_refspec = 0;
	const char **refspec = NULL;
	struct remote_lock *ref_lock = NULL;
	struct remote_lock *info_ref_lock = NULL;
	struct rev_info revs;
	int delete_branch = 0;
	int force_delete = 0;
	int objects_to_send;
	int rc = 0;
	int i;
	int new_refs;
	struct ref *ref, *local_refs;

	repo = xcalloc(1, sizeof(*repo));

	argv++;
	for (i = 1; i < argc; i++, argv++) {
		const char *arg = *argv;

		if (*arg == '-') {
			if (!strcmp(arg, "--all")) {
				push_all = MATCH_REFS_ALL;
				continue;
			}
			if (!strcmp(arg, "--force")) {
				force_all = 1;
				continue;
			}
			if (!strcmp(arg, "--dry-run")) {
				dry_run = 1;
				continue;
			}
			if (!strcmp(arg, "--helper-status")) {
				helper_status = 1;
				continue;
			}
			if (!strcmp(arg, "--verbose")) {
				push_verbosely = 1;
				http_is_verbose = 1;
				continue;
			}
			if (!strcmp(arg, "-d")) {
				delete_branch = 1;
				continue;
			}
			if (!strcmp(arg, "-D")) {
				delete_branch = 1;
				force_delete = 1;
				continue;
			}
			if (!strcmp(arg, "-h"))
				usage(http_push_usage);
		}
		if (!repo->url) {
			char *path = strstr(arg, "//");
			str_end_url_with_slash(arg, &repo->url);
			repo->path_len = strlen(repo->url);
			if (path) {
				repo->path = strchr(path+2, '/');
				if (repo->path)
					repo->path_len = strlen(repo->path);
			}
			continue;
		}
		refspec = argv;
		nr_refspec = argc - i;
		break;
	}

#ifndef USE_CURL_MULTI
	die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI");
#endif

	if (!repo->url)
		usage(http_push_usage);

	if (delete_branch && nr_refspec != 1)
		die("You must specify only one branch name when deleting a remote branch");

	setup_git_directory();

	memset(remote_dir_exists, -1, 256);

	http_init(NULL, repo->url, 1);

#ifdef USE_CURL_MULTI
	is_running_queue = 0;
#endif

	/* Verify DAV compliance/lock support */
	if (!locking_available()) {
		rc = 1;
		goto cleanup;
	}

	sigchain_push_common(remove_locks_on_signal);

	/* Check whether the remote has server info files */
	repo->can_update_info_refs = 0;
	repo->has_info_refs = remote_exists("info/refs");
	repo->has_info_packs = remote_exists("objects/info/packs");
	if (repo->has_info_refs) {
		info_ref_lock = lock_remote("info/refs", LOCK_TIME);
		if (info_ref_lock)
			repo->can_update_info_refs = 1;
		else {
			error("cannot lock existing info/refs");
			rc = 1;
			goto cleanup;
		}
	}
	if (repo->has_info_packs)
		fetch_indices();

	/* Get a list of all local and remote heads to validate refspecs */
	local_refs = get_local_heads();
	fprintf(stderr, "Fetching remote heads...\n");
	get_dav_remote_heads();
	run_request_queue();

	/* Remove a remote branch if -d or -D was specified */
	if (delete_branch) {
		if (delete_remote_branch(refspec[0], force_delete) == -1) {
			fprintf(stderr, "Unable to delete remote branch %s\n",
				refspec[0]);
			if (helper_status)
				printf("error %s cannot remove\n", refspec[0]);
		}
		goto cleanup;
	}

	/* match them up */
	if (match_push_refs(local_refs, &remote_refs,
			    nr_refspec, (const char **) refspec, push_all)) {
		rc = -1;
		goto cleanup;
	}
	if (!remote_refs) {
		fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
		if (helper_status)
			printf("error null no match\n");
		rc = 0;
		goto cleanup;
	}

	new_refs = 0;
	for (ref = remote_refs; ref; ref = ref->next) {
		struct argv_array commit_argv = ARGV_ARRAY_INIT;

		if (!ref->peer_ref)
			continue;

		if (is_null_oid(&ref->peer_ref->new_oid)) {
			if (delete_remote_branch(ref->name, 1) == -1) {
				error("Could not remove %s", ref->name);
				if (helper_status)
					printf("error %s cannot remove\n", ref->name);
				rc = -4;
			}
			else if (helper_status)
				printf("ok %s\n", ref->name);
			new_refs++;
			continue;
		}

		if (!oidcmp(&ref->old_oid, &ref->peer_ref->new_oid)) {
			if (push_verbosely)
				fprintf(stderr, "'%s': up-to-date\n", ref->name);
			if (helper_status)
				printf("ok %s up to date\n", ref->name);
			continue;
		}

		if (!force_all &&
		    !is_null_oid(&ref->old_oid) &&
		    !ref->force) {
			if (!has_object_file(&ref->old_oid) ||
			    !ref_newer(&ref->peer_ref->new_oid,
				       &ref->old_oid)) {
				/*
				 * We do not have the remote ref, or
				 * we know that the remote ref is not
				 * an ancestor of what we are trying to
				 * push.  Either way this can be losing
				 * commits at the remote end and likely
				 * we were not up to date to begin with.
				 */
				error("remote '%s' is not an ancestor of\n"
				      "local '%s'.\n"
				      "Maybe you are not up-to-date and "
				      "need to pull first?",
				      ref->name,
				      ref->peer_ref->name);
				if (helper_status)
					printf("error %s non-fast forward\n", ref->name);
				rc = -2;
				continue;
			}
		}
		oidcpy(&ref->new_oid, &ref->peer_ref->new_oid);
		new_refs++;

		fprintf(stderr, "updating '%s'", ref->name);
		if (strcmp(ref->name, ref->peer_ref->name))
			fprintf(stderr, " using '%s'", ref->peer_ref->name);
		fprintf(stderr, "\n  from %s\n  to   %s\n",
			oid_to_hex(&ref->old_oid), oid_to_hex(&ref->new_oid));
		if (dry_run) {
			if (helper_status)
				printf("ok %s\n", ref->name);
			continue;
		}

		/* Lock remote branch ref */
		ref_lock = lock_remote(ref->name, LOCK_TIME);
		if (ref_lock == NULL) {
			fprintf(stderr, "Unable to lock remote branch %s\n",
				ref->name);
			if (helper_status)
				printf("error %s lock error\n", ref->name);
			rc = 1;
			continue;
		}

		/* Set up revision info for this refspec */
		argv_array_push(&commit_argv, ""); /* ignored */
		argv_array_push(&commit_argv, "--objects");
		argv_array_push(&commit_argv, oid_to_hex(&ref->new_oid));
		if (!push_all && !is_null_oid(&ref->old_oid))
			argv_array_pushf(&commit_argv, "^%s",
					 oid_to_hex(&ref->old_oid));
		init_revisions(&revs, setup_git_directory());
		setup_revisions(commit_argv.argc, commit_argv.argv, &revs, NULL);
		revs.edge_hint = 0; /* just in case */

		/* Generate a list of objects that need to be pushed */
		pushing = 0;
		if (prepare_revision_walk(&revs))
			die("revision walk setup failed");
		mark_edges_uninteresting(&revs, NULL);
		objects_to_send = get_delta(&revs, ref_lock);
		finish_all_active_slots();

		/* Push missing objects to remote, this would be a
		   convenient time to pack them first if appropriate. */
		pushing = 1;
		if (objects_to_send)
			fprintf(stderr, "    sending %d objects\n",
				objects_to_send);

		run_request_queue();

		/* Update the remote branch if all went well */
		if (aborted || !update_remote(ref->new_oid.hash, ref_lock))
			rc = 1;

		if (!rc)
			fprintf(stderr, "    done\n");
		if (helper_status)
			printf("%s %s\n", !rc ? "ok" : "error", ref->name);
		unlock_remote(ref_lock);
		check_locks();
		argv_array_clear(&commit_argv);
	}

	/* Update remote server info if appropriate */
	if (repo->has_info_refs && new_refs) {
		if (info_ref_lock && repo->can_update_info_refs) {
			fprintf(stderr, "Updating remote server info\n");
			if (!dry_run)
				update_remote_info_refs(info_ref_lock);
		} else {
			fprintf(stderr, "Unable to update server info\n");
		}
	}

 cleanup:
	if (info_ref_lock)
		unlock_remote(info_ref_lock);
	free(repo);

	http_cleanup();

	request = request_queue_head;
	while (request != NULL) {
		next_request = request->next;
		release_request(request);
		request = next_request;
	}

	return rc;
}
Esempio n. 12
0
File: bundle.c Progetto: 2572/git
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;
	int ref_count = 0;
	struct rev_info revs;

	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_pack_data() will close the fd passed to it,
		 * but commit_lock_file() will also try to close the
		 * lockfile's fd. So make a copy of the file
		 * descriptor to avoid trying to close it twice.
		 */
		bundle_fd = dup(bundle_fd);
		if (bundle_fd < 0)
			die_errno("unable to dup file descriptor");
	}

	/* 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 */
	if (compute_and_write_prerequisites(bundle_fd, &revs, argc, argv))
		return -1;

	argc = setup_revisions(argc, argv, &revs, NULL);

	if (argc > 1)
		return error(_("unrecognized argument: %s"), argv[1]);

	object_array_remove_duplicates(&revs.pending);

	ref_count = write_bundle_refs(bundle_fd, &revs);
	if (!ref_count)
		die(_("Refusing to create empty bundle."));
	else if (ref_count < 0)
		return -1;

	/* write pack */
	if (write_pack_data(bundle_fd, &revs))
		return -1;

	if (!bundle_to_stdout) {
		if (commit_lock_file(&lock))
			die_errno(_("cannot create '%s'"), path);
	}
	return 0;
}
Esempio n. 13
0
void show_submodule_summary(FILE *f, const char *path,
		unsigned char one[20], unsigned char two[20],
		unsigned dirty_submodule,
		const char *del, const char *add, const char *reset)
{
	struct rev_info rev;
	struct commit *commit, *left = left, *right = right;
	struct commit_list *merge_bases, *list;
	const char *message = NULL;
	struct strbuf sb = STRBUF_INIT;
	static const char *format = "  %m %s";
	int fast_forward = 0, fast_backward = 0;

	if (is_null_sha1(two))
		message = "(submodule deleted)";
	else if (add_submodule_odb(path))
		message = "(not checked out)";
	else if (is_null_sha1(one))
		message = "(new submodule)";
	else if (!(left = lookup_commit_reference(one)) ||
		 !(right = lookup_commit_reference(two)))
		message = "(commits not present)";

	if (!message) {
		init_revisions(&rev, NULL);
		setup_revisions(0, NULL, &rev, NULL);
		rev.left_right = 1;
		rev.first_parent_only = 1;
		left->object.flags |= SYMMETRIC_LEFT;
		add_pending_object(&rev, &left->object, path);
		add_pending_object(&rev, &right->object, path);
		merge_bases = get_merge_bases(left, right, 1);
		if (merge_bases) {
			if (merge_bases->item == left)
				fast_forward = 1;
			else if (merge_bases->item == right)
				fast_backward = 1;
		}
		for (list = merge_bases; list; list = list->next) {
			list->item->object.flags |= UNINTERESTING;
			add_pending_object(&rev, &list->item->object,
				sha1_to_hex(list->item->object.sha1));
		}
		if (prepare_revision_walk(&rev))
			message = "(revision walker failed)";
	}

	strbuf_addf(&sb, "Submodule %s %s..", path,
			find_unique_abbrev(one, DEFAULT_ABBREV));
	if (!fast_backward && !fast_forward)
		strbuf_addch(&sb, '.');
	strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
	if (dirty_submodule)
		strbuf_add(&sb, "-dirty", 6);
	if (message)
		strbuf_addf(&sb, " %s\n", message);
	else
		strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
	fwrite(sb.buf, sb.len, 1, f);

	if (!message) {
		while ((commit = get_revision(&rev))) {
			struct pretty_print_context ctx = {0};
			ctx.date_mode = rev.date_mode;
			strbuf_setlen(&sb, 0);
			if (commit->object.flags & SYMMETRIC_LEFT) {
				if (del)
					strbuf_addstr(&sb, del);
			}
			else if (add)
				strbuf_addstr(&sb, add);
			format_commit_message(commit, format, &sb, &ctx);
			if (reset)
				strbuf_addstr(&sb, reset);
			strbuf_addch(&sb, '\n');
			fprintf(f, "%s", sb.buf);
		}
		clear_commit_marks(left, ~0);
		clear_commit_marks(right, ~0);
	}
	strbuf_release(&sb);
}
Esempio n. 14
0
File: log.c Progetto: jjuran/git
int cmd_format_patch(int argc, const char **argv, const char *prefix)
{
#ifdef USE_CPLUSPLUS_FOR_INIT
#pragma cplusplus on
#endif

	struct commit *commit;
	struct commit **list = NULL;
	struct rev_info rev;
	struct setup_revision_opt s_r_opt;
	int nr = 0, total, i;
	int use_stdout = 0;
	int start_number = -1;
	int numbered_files = 0;		/* _just_ numbers */
	int ignore_if_in_upstream = 0;
	int cover_letter = 0;
	int boundary_count = 0;
	int no_binary_diff = 0;
	struct commit *origin = NULL, *head = NULL;
	const char *in_reply_to = NULL;
	struct patch_ids ids;
	char *add_signoff = NULL;
	struct strbuf buf = STRBUF_INIT;
	int use_patch_format = 0;
	int quiet = 0;
	const struct option builtin_format_patch_options[] = {
		{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
			    "use [PATCH n/m] even with a single patch",
			    PARSE_OPT_NOARG, numbered_callback },
		{ OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
			    "use [PATCH] even with multiple patches",
			    PARSE_OPT_NOARG, no_numbered_callback },
		OPT_BOOLEAN('s', "signoff", &do_signoff, "add Signed-off-by:"),
		OPT_BOOLEAN(0, "stdout", &use_stdout,
			    "print patches to standard out"),
		OPT_BOOLEAN(0, "cover-letter", &cover_letter,
			    "generate a cover letter"),
		OPT_BOOLEAN(0, "numbered-files", &numbered_files,
			    "use simple number sequence for output file names"),
		OPT_STRING(0, "suffix", &fmt_patch_suffix, "sfx",
			    "use <sfx> instead of '.patch'"),
		OPT_INTEGER(0, "start-number", &start_number,
			    "start numbering patches at <n> instead of 1"),
		{ OPTION_CALLBACK, 0, "subject-prefix", &rev, "prefix",
			    "Use [<prefix>] instead of [PATCH]",
			    PARSE_OPT_NONEG, subject_prefix_callback },
		{ OPTION_CALLBACK, 'o', "output-directory", &output_directory,
			    "dir", "store resulting files in <dir>",
			    PARSE_OPT_NONEG, output_directory_callback },
		{ OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL,
			    "don't strip/add [PATCH]",
			    PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback },
		OPT_BOOLEAN(0, "no-binary", &no_binary_diff,
			    "don't output binary diffs"),
		OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
			    "don't include a patch matching a commit upstream"),
		{ OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL,
		  "show patch format instead of default (patch + stat)",
		  PARSE_OPT_NONEG | PARSE_OPT_NOARG },
		OPT_GROUP("Messaging"),
		{ OPTION_CALLBACK, 0, "add-header", NULL, "header",
			    "add email header", 0, header_callback },
		{ OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header",
			    0, to_callback },
		{ OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header",
			    0, cc_callback },
		OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id",
			    "make first mail a reply to <message-id>"),
		{ OPTION_CALLBACK, 0, "attach", &rev, "boundary",
			    "attach the patch", PARSE_OPT_OPTARG,
			    attach_callback },
		{ OPTION_CALLBACK, 0, "inline", &rev, "boundary",
			    "inline the patch",
			    PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
			    inline_callback },
		{ OPTION_CALLBACK, 0, "thread", &thread, "style",
			    "enable message threading, styles: shallow, deep",
			    PARSE_OPT_OPTARG, thread_callback },
		OPT_STRING(0, "signature", &signature, "signature",
			    "add a signature"),
		OPT_BOOLEAN(0, "quiet", &quiet,
			    "don't print the patch filenames"),
		OPT_END()
	};

#ifdef USE_CPLUSPLUS_FOR_INIT
#pragma cplusplus reset
#endif

	extra_hdr.strdup_strings = 1;
	extra_to.strdup_strings = 1;
	extra_cc.strdup_strings = 1;
	git_config(git_format_config, NULL);
	init_revisions(&rev, prefix);
	rev.commit_format = CMIT_FMT_EMAIL;
	rev.verbose_header = 1;
	rev.diff = 1;
	rev.max_parents = 1;
	DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
	rev.subject_prefix = fmt_patch_subject_prefix;
	memset(&s_r_opt, 0, sizeof(s_r_opt));
	s_r_opt.def = "HEAD";

	if (default_attach) {
		rev.mime_boundary = default_attach;
		rev.no_inline = 1;
	}

	/*
	 * Parse the arguments before setup_revisions(), or something
	 * like "git format-patch -o a123 HEAD^.." may fail; a123 is
	 * possibly a valid SHA1.
	 */
	argc = parse_options(argc, argv, prefix, builtin_format_patch_options,
			     builtin_format_patch_usage,
			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
			     PARSE_OPT_KEEP_DASHDASH);

	if (do_signoff) {
		const char *committer;
		const char *endpos;
		committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
		endpos = strchr(committer, '>');
		if (!endpos)
			die(_("bogus committer info %s"), committer);
		add_signoff = xmemdupz(committer, endpos - committer + 1);
	}

	for (i = 0; i < extra_hdr.nr; i++) {
		strbuf_addstr(&buf, extra_hdr.items[i].string);
		strbuf_addch(&buf, '\n');
	}

	if (extra_to.nr)
		strbuf_addstr(&buf, "To: ");
	for (i = 0; i < extra_to.nr; i++) {
		if (i)
			strbuf_addstr(&buf, "    ");
		strbuf_addstr(&buf, extra_to.items[i].string);
		if (i + 1 < extra_to.nr)
			strbuf_addch(&buf, ',');
		strbuf_addch(&buf, '\n');
	}

	if (extra_cc.nr)
		strbuf_addstr(&buf, "Cc: ");
	for (i = 0; i < extra_cc.nr; i++) {
		if (i)
			strbuf_addstr(&buf, "    ");
		strbuf_addstr(&buf, extra_cc.items[i].string);
		if (i + 1 < extra_cc.nr)
			strbuf_addch(&buf, ',');
		strbuf_addch(&buf, '\n');
	}

	rev.extra_headers = strbuf_detach(&buf, NULL);

	if (start_number < 0)
		start_number = 1;

	/*
	 * If numbered is set solely due to format.numbered in config,
	 * and it would conflict with --keep-subject (-k) from the
	 * command line, reset "numbered".
	 */
	if (numbered && keep_subject && !numbered_cmdline_opt)
		numbered = 0;

	if (numbered && keep_subject)
		die (_("-n and -k are mutually exclusive."));
	if (keep_subject && subject_prefix)
		die (_("--subject-prefix and -k are mutually exclusive."));
	rev.preserve_subject = keep_subject;

	argc = setup_revisions(argc, argv, &rev, &s_r_opt);
	if (argc > 1)
		die (_("unrecognized argument: %s"), argv[1]);

	if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
		die(_("--name-only does not make sense"));
	if (rev.diffopt.output_format & DIFF_FORMAT_NAME_STATUS)
		die(_("--name-status does not make sense"));
	if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
		die(_("--check does not make sense"));

	if (!use_patch_format &&
		(!rev.diffopt.output_format ||
		 rev.diffopt.output_format == DIFF_FORMAT_PATCH))
		rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY;

	/* Always generate a patch */
	rev.diffopt.output_format |= DIFF_FORMAT_PATCH;

	if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)
		DIFF_OPT_SET(&rev.diffopt, BINARY);

	if (rev.show_notes)
		init_display_notes(&rev.notes_opt);

	if (!use_stdout)
		output_directory = set_outdir(prefix, output_directory);
	else
		setup_pager();

	if (output_directory) {
		if (use_stdout)
			die(_("standard output, or directory, which one?"));
		if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
			die_errno(_("Could not create directory '%s'"),
				  output_directory);
	}

	if (rev.pending.nr == 1) {
		if (rev.max_count < 0 && !rev.show_root_diff) {
			/*
			 * This is traditional behaviour of "git format-patch
			 * origin" that prepares what the origin side still
			 * does not have.
			 */
			rev.pending.objects[0].item->flags |= UNINTERESTING;
			add_head_to_pending(&rev);
		}
		/*
		 * Otherwise, it is "format-patch -22 HEAD", and/or
		 * "format-patch --root HEAD".  The user wants
		 * get_revision() to do the usual traversal.
		 */
	}

	/*
	 * We cannot move this anywhere earlier because we do want to
	 * know if --root was given explicitly from the command line.
	 */
	rev.show_root_diff = 1;

	if (cover_letter) {
		/* remember the range */
		int i;
		for (i = 0; i < rev.pending.nr; i++) {
			struct object *o = rev.pending.objects[i].item;
			if (!(o->flags & UNINTERESTING))
				head = (struct commit *)o;
		}
		/* We can't generate a cover letter without any patches */
		if (!head)
			return 0;
	}

	if (ignore_if_in_upstream) {
		/* Don't say anything if head and upstream are the same. */
		if (rev.pending.nr == 2) {
			struct object_array_entry *o = rev.pending.objects;
			if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
				return 0;
		}
		get_patch_ids(&rev, &ids, prefix);
	}

	if (!use_stdout)
		realstdout = xfdopen(xdup(1), "w");

	if (prepare_revision_walk(&rev))
		die(_("revision walk setup failed"));
	rev.boundary = 1;
	while ((commit = get_revision(&rev)) != NULL) {
		if (commit->object.flags & BOUNDARY) {
			boundary_count++;
			origin = (boundary_count == 1) ? commit : NULL;
			continue;
		}

		if (ignore_if_in_upstream &&
				has_commit_patch_id(commit, &ids))
			continue;

		nr++;
		list = xrealloc(list, nr * sizeof(list[0]));
		list[nr - 1] = commit;
	}
	total = nr;
	if (!keep_subject && auto_number && total > 1)
		numbered = 1;
	if (numbered)
		rev.total = total + start_number - 1;
	if (in_reply_to || thread || cover_letter)
		rev.ref_message_ids = xcalloc(1, sizeof(struct string_list));
	if (in_reply_to) {
		const char *msgid = clean_message_id(in_reply_to);
		string_list_append(rev.ref_message_ids, msgid);
	}
	rev.numbered_files = numbered_files;
	rev.patch_suffix = fmt_patch_suffix;
	if (cover_letter) {
		if (thread)
			gen_message_id(&rev, "cover");
		make_cover_letter(&rev, use_stdout, numbered, numbered_files,
				  origin, nr, list, head, quiet);
		total++;
		start_number--;
	}
	rev.add_signoff = add_signoff;
	while (0 <= --nr) {
		int shown;
		commit = list[nr];
		rev.nr = total - nr + (start_number - 1);
		/* Make the second and subsequent mails replies to the first */
		if (thread) {
			/* Have we already had a message ID? */
			if (rev.message_id) {
				/*
				 * For deep threading: make every mail
				 * a reply to the previous one, no
				 * matter what other options are set.
				 *
				 * For shallow threading:
				 *
				 * Without --cover-letter and
				 * --in-reply-to, make every mail a
				 * reply to the one before.
				 *
				 * With --in-reply-to but no
				 * --cover-letter, make every mail a
				 * reply to the <reply-to>.
				 *
				 * With --cover-letter, make every
				 * mail but the cover letter a reply
				 * to the cover letter.  The cover
				 * letter is a reply to the
				 * --in-reply-to, if specified.
				 */
				if (thread == THREAD_SHALLOW
				    && rev.ref_message_ids->nr > 0
				    && (!cover_letter || rev.nr > 1))
					free(rev.message_id);
				else
					string_list_append(rev.ref_message_ids,
							   rev.message_id);
			}
			gen_message_id(&rev, sha1_to_hex(commit->object.sha1));
		}

		if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit,
						 &rev, quiet))
			die(_("Failed to create output files"));
		shown = log_tree_commit(&rev, commit);
		free(commit->buffer);
		commit->buffer = NULL;

		/* We put one extra blank line between formatted
		 * patches and this flag is used by log-tree code
		 * to see if it needs to emit a LF before showing
		 * the log; when using one file per patch, we do
		 * not want the extra blank line.
		 */
		if (!use_stdout)
			rev.shown_one = 0;
		if (shown) {
			if (rev.mime_boundary)
				printf("\n--%s%s--\n\n\n",
				       mime_boundary_leader,
				       rev.mime_boundary);
			else
				print_signature();
		}
		if (!use_stdout)
			fclose(stdout);
	}
	free(list);
	string_list_clear(&extra_to, 0);
	string_list_clear(&extra_cc, 0);
	string_list_clear(&extra_hdr, 0);
	if (ignore_if_in_upstream)
		free_patch_ids(&ids);
	return 0;
}
Esempio n. 15
0
void cgit_print_patch(const char *new_rev, const char *old_rev,
		      const char *prefix)
{
	struct rev_info rev;
	struct commit *commit;
	unsigned char new_rev_sha1[20], old_rev_sha1[20];
	char rev_range[2 * 40 + 3];
	char *rev_argv[] = { NULL, "--reverse", "--format=email", rev_range };
	char *patchname;

	if (!new_rev)
		new_rev = ctx.qry.head;

	if (get_sha1(new_rev, new_rev_sha1)) {
		cgit_print_error("Bad object id: %s", new_rev);
		return;
	}
	commit = lookup_commit_reference(new_rev_sha1);
	if (!commit) {
		cgit_print_error("Bad commit reference: %s", new_rev);
		return;
	}

	if (old_rev) {
		if (get_sha1(old_rev, old_rev_sha1)) {
			cgit_print_error("Bad object id: %s", old_rev);
			return;
		}
		if (!lookup_commit_reference(old_rev_sha1)) {
			cgit_print_error("Bad commit reference: %s", old_rev);
			return;
		}
	} else if (commit->parents && commit->parents->item) {
		hashcpy(old_rev_sha1, commit->parents->item->object.sha1);
	} else {
		hashclr(old_rev_sha1);
	}

	if (is_null_sha1(old_rev_sha1)) {
		memcpy(rev_range, sha1_to_hex(new_rev_sha1), 41);
	} else {
		sprintf(rev_range, "%s..%s", sha1_to_hex(old_rev_sha1),
			sha1_to_hex(new_rev_sha1));
	}

	patchname = fmt("%s.patch", rev_range);
	ctx.page.mimetype = "text/plain";
	ctx.page.filename = patchname;
	cgit_print_http_headers();

	if (ctx.cfg.noplainemail) {
		rev_argv[2] = "--format=format:From %H Mon Sep 17 00:00:00 "
			      "2001%nFrom: %an%nDate: %aD%n%w(78,0,1)Subject: "
			      "%s%n%n%w(0)%b";
	}

	init_revisions(&rev, NULL);
	rev.abbrev = DEFAULT_ABBREV;
	rev.verbose_header = 1;
	rev.diff = 1;
	rev.show_root_diff = 1;
	rev.max_parents = 1;
	rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
	setup_revisions(ARRAY_SIZE(rev_argv), (const char **)rev_argv, &rev,
			NULL);
	prepare_revision_walk(&rev);

	while ((commit = get_revision(&rev)) != NULL) {
		log_tree_commit(&rev, commit);
		printf("-- \ncgit %s\n\n", cgit_version);
	}
}
Esempio n. 16
0
File: log.c Progetto: jjuran/git
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
			 struct rev_info *rev, struct setup_revision_opt *opt)
{
	struct userformat_want w;
	int quiet = 0, source = 0;

#ifdef USE_CPLUSPLUS_FOR_INIT
#pragma cplusplus on
#endif

	const struct option builtin_log_options[] = {
		OPT_BOOLEAN(0, "quiet", &quiet, "suppress diff output"),
		OPT_BOOLEAN(0, "source", &source, "show source"),
		{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, "decorate options",
		  PARSE_OPT_OPTARG, decorate_callback},
		OPT_END()
	};

#ifdef USE_CPLUSPLUS_FOR_INIT
#pragma cplusplus reset
#endif

	argc = parse_options(argc, argv, prefix,
			     builtin_log_options, builtin_log_usage,
			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
			     PARSE_OPT_KEEP_DASHDASH);

	argc = setup_revisions(argc, argv, rev, opt);
	if (quiet)
		rev->diffopt.output_format |= DIFF_FORMAT_NO_OUTPUT;

	/* Any arguments at this point are not recognized */
	if (argc > 1)
		die("unrecognized argument: %s", argv[1]);

	memset(&w, 0, sizeof(w));
	userformat_find_requirements(NULL, &w);

	if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
		rev->show_notes = 1;
	if (rev->show_notes)
		init_display_notes(&rev->notes_opt);

	if (rev->diffopt.pickaxe || rev->diffopt.filter)
		rev->always_show_header = 0;
	if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
		rev->always_show_header = 0;
		if (rev->diffopt.pathspec.nr != 1)
			usage("git logs can only follow renames on one pathname at a time");
	}

	if (source)
		rev->show_source = 1;

	if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {
		/*
		 * "log --pretty=raw" is special; ignore UI oriented
		 * configuration variables such as decoration.
		 */
		if (!decoration_given)
			decoration_style = 0;
		if (!rev->abbrev_commit_given)
			rev->abbrev_commit = 0;
	}

	if (decoration_style) {
		rev->show_decorations = 1;
		load_ref_decorations(decoration_style);
	}
	setup_pager();
}
Esempio n. 17
0
int cmd_diff(int argc, const char **argv, const char *prefix)
{
	int i;
	struct rev_info rev;
	struct object_array_entry ent[100];
	int ents = 0, 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);

	if (diff_use_color_default == -1)
		diff_use_color_default = git_use_color_default;

	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;

	/* 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;
		if (diff_setup_done(&rev.diffopt) < 0)
			die("diff_setup_done failed");
	}

	DIFF_OPT_SET(&rev.diffopt, RECURSIVE);

	/*
	 * If the user asked for our exit code then don't start a
	 * pager or we would end up reporting its exit code instead.
	 */
	if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) &&
	    check_pager_config("diff") != 0)
		setup_pager();

	/*
	 * 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)
					die("No HEAD commit to compare with (yet)");
				break;
			}
		}
	}

	for (i = 0; i < rev.pending.nr; i++) {
		struct object_array_entry *list = rev.pending.objects+i;
		struct object *obj = list->item;
		const char *name = list->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) {
			if (ARRAY_SIZE(ent) <= ents)
				die("more than %d trees given: '%s'",
				    (int) ARRAY_SIZE(ent), name);
			obj->flags |= flags;
			ent[ents].item = obj;
			ent[ents].name = name;
			ents++;
			continue;
		}
		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 = list->mode;
			blobs++;
			continue;

		}
		die("unhandled object '%s' given.", name);
	}
	if (rev.prune_data) {
		const char **pathspec = rev.prune_data;
		while (*pathspec) {
			if (!path)
				path = *pathspec;
			paths++;
			pathspec++;
		}
	}

	/*
	 * Now, do the arguments look reasonable?
	 */
	if (!ents) {
		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 (ents == 1)
		result = builtin_diff_index(&rev, argc, argv);
	else if (ents == 2)
		result = builtin_diff_tree(&rev, argc, argv, ent);
	else if (ent[0].item->flags & UNINTERESTING) {
		/*
		 * diff A...B where there is at least one merge base
		 * between A and B.  We have ent[0] == merge-base,
		 * ent[ents-2] == A, and ent[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.
		 */
		ent[1] = ent[ents-1];
		result = builtin_diff_tree(&rev, argc, argv, ent);
	} else
		result = builtin_diff_combined(&rev, argc, argv,
					       ent, ents);
	result = diff_result_code(&rev.diffopt, result);
	if (1 < rev.diffopt.skip_stat_unmatch)
		refresh_index_quietly();
	return result;
}
Esempio n. 18
0
static int prepare_to_commit(const char *index_file, const char *prefix)
{
	struct stat statbuf;
	int commitable, saved_color_setting;
	struct strbuf sb;
	char *buffer;
	FILE *fp;
	const char *hook_arg1 = NULL;
	const char *hook_arg2 = NULL;
	int ident_shown = 0;

	if (!no_verify && run_hook(index_file, "pre-commit", NULL))
		return 0;

	strbuf_init(&sb, 0);
	if (message.len) {
		strbuf_addbuf(&sb, &message);
		hook_arg1 = "message";
	} else if (logfile && !strcmp(logfile, "-")) {
		if (isatty(0))
			fprintf(stderr, "(reading log message from standard input)\n");
		if (strbuf_read(&sb, 0, 0) < 0)
			die("could not read log from standard input");
		hook_arg1 = "message";
	} else if (logfile) {
		if (strbuf_read_file(&sb, logfile, 0) < 0)
			die("could not read log file '%s': %s",
			    logfile, strerror(errno));
		hook_arg1 = "message";
	} else if (use_message) {
		buffer = strstr(use_message_buffer, "\n\n");
		if (!buffer || buffer[2] == '\0')
			die("commit has empty message");
		strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
		hook_arg1 = "commit";
		hook_arg2 = use_message;
	} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
		if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
			die("could not read MERGE_MSG: %s", strerror(errno));
		hook_arg1 = "merge";
	} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
		if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
			die("could not read SQUASH_MSG: %s", strerror(errno));
		hook_arg1 = "squash";
	} else if (template_file && !stat(template_file, &statbuf)) {
		if (strbuf_read_file(&sb, template_file, 0) < 0)
			die("could not read %s: %s",
			    template_file, strerror(errno));
		hook_arg1 = "template";
	}

	/*
	 * This final case does not modify the template message,
	 * it just sets the argument to the prepare-commit-msg hook.
	 */
	else if (in_merge)
		hook_arg1 = "merge";

	fp = fopen(git_path(commit_editmsg), "w");
	if (fp == NULL)
		die("could not open %s", git_path(commit_editmsg));

	if (cleanup_mode != CLEANUP_NONE)
		stripspace(&sb, 0);

	if (signoff) {
		struct strbuf sob;
		int i;

		strbuf_init(&sob, 0);
		strbuf_addstr(&sob, sign_off_header);
		strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"),
					     getenv("GIT_COMMITTER_EMAIL")));
		strbuf_addch(&sob, '\n');
		for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--)
			; /* do nothing */
		if (prefixcmp(sb.buf + i, sob.buf)) {
			if (prefixcmp(sb.buf + i, sign_off_header))
				strbuf_addch(&sb, '\n');
			strbuf_addbuf(&sb, &sob);
		}
		strbuf_release(&sob);
	}

	if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
		die("could not write commit template: %s", strerror(errno));

	strbuf_release(&sb);

	determine_author_info();

	/* This checks if committer ident is explicitly given */
	git_committer_info(0);
	if (use_editor) {
		char *author_ident;
		const char *committer_ident;

		if (in_merge)
			fprintf(fp,
				"#\n"
				"# It looks like you may be committing a MERGE.\n"
				"# If this is not correct, please remove the file\n"
				"#	%s\n"
				"# and try again.\n"
				"#\n",
				git_path("MERGE_HEAD"));

		fprintf(fp,
			"\n"
			"# Please enter the commit message for your changes.\n"
			"# (Comment lines starting with '#' will ");
		if (cleanup_mode == CLEANUP_ALL)
			fprintf(fp, "not be included)\n");
		else /* CLEANUP_SPACE, that is. */
			fprintf(fp, "be kept.\n"
				"# You can remove them yourself if you want to)\n");
		if (only_include_assumed)
			fprintf(fp, "# %s\n", only_include_assumed);

		author_ident = xstrdup(fmt_name(author_name, author_email));
		committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"),
					   getenv("GIT_COMMITTER_EMAIL"));
		if (strcmp(author_ident, committer_ident))
			fprintf(fp,
				"%s"
				"# Author:    %s\n",
				ident_shown++ ? "" : "#\n",
				author_ident);
		free(author_ident);

		if (!user_ident_explicitly_given)
			fprintf(fp,
				"%s"
				"# Committer: %s\n",
				ident_shown++ ? "" : "#\n",
				committer_ident);

		if (ident_shown)
			fprintf(fp, "#\n");

		saved_color_setting = wt_status_use_color;
		wt_status_use_color = 0;
		commitable = run_status(fp, index_file, prefix, 1);
		wt_status_use_color = saved_color_setting;
	} else {
		struct rev_info rev;
		unsigned char sha1[20];
		const char *parent = "HEAD";

		if (!active_nr && read_cache() < 0)
			die("Cannot read index");

		if (amend)
			parent = "HEAD^1";

		if (get_sha1(parent, sha1))
			commitable = !!active_nr;
		else {
			init_revisions(&rev, "");
			rev.abbrev = 0;
			setup_revisions(0, NULL, &rev, parent);
			DIFF_OPT_SET(&rev.diffopt, QUIET);
			DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
			run_diff_index(&rev, 1 /* cached */);

			commitable = !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
		}
	}

	fclose(fp);

	if (!commitable && !in_merge && !allow_empty &&
	    !(amend && is_a_merge(head_sha1))) {
		run_status(stdout, index_file, prefix, 0);
		unlink(commit_editmsg);
		return 0;
	}

	/*
	 * Re-read the index as pre-commit hook could have updated it,
	 * and write it out as a tree.  We must do this before we invoke
	 * the editor and after we invoke run_status above.
	 */
	discard_cache();
	read_cache_from(index_file);
	if (!active_cache_tree)
		active_cache_tree = cache_tree();
	if (cache_tree_update(active_cache_tree,
			      active_cache, active_nr, 0, 0) < 0) {
		error("Error building trees");
		return 0;
	}

	if (run_hook(index_file, "prepare-commit-msg",
		     git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
		return 0;

	if (use_editor) {
		char index[PATH_MAX];
		const char *env[2] = { index, NULL };
		snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
		launch_editor(git_path(commit_editmsg), NULL, env);
	}

	if (!no_verify &&
	    run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
		return 0;
	}

	return 1;
}
Esempio n. 19
0
File: bundle.c Progetto: 86joca/git
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);

	refs = revs.pending;
	revs.leak_pending = 1;

	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);
		}

	clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
	free(refs.objects);

	if (verbose) {
		struct ref_list *r;

		r = &header->references;
		printf_ln(Q_("The bundle contains this ref:",
			     "The bundle contains these %d refs:",
			     r->nr),
			  r->nr);
		list_refs(r, 0, NULL);
		r = &header->prerequisites;
		if (!r->nr) {
			printf_ln(_("The bundle records a complete history."));
		} else {
			printf_ln(Q_("The bundle requires this ref:",
				     "The bundle requires these %d refs:",
				     r->nr),
				  r->nr);
			list_refs(r, 0, NULL);
		}
	}
	return ret;
}
Esempio n. 20
0
File: diff.c Progetto: foggg7777/git
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 object_array_entry *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;
	}

	prefix = setup_git_directory_gently(&nongit);

	if (!no_index) {
		/*
		 * 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;
	}

	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 */
	rev.diffopt.flags.allow_external = 1;
	rev.diffopt.flags.allow_textconv = 1;

	/*
	 * Default to intent-to-add entries invisible in the
	 * index. This makes them show up as new files in diff-files
	 * and not at all in diff-cached.
	 */
	rev.diffopt.ita_invisible_in_index = 1;

	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);
	}

	rev.diffopt.flags.recursive = 1;

	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(the_repository,
							   the_repository->hash_algo->empty_tree);
					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(the_repository, &obj->oid);
		obj = deref_tag(the_repository, obj, NULL, 0);
		if (!obj)
			die(_("invalid object '%s' given."), name);
		if (obj->type == OBJ_COMMIT)
			obj = &get_commit_tree(((struct commit *)obj))->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);
			blob[blobs] = entry;
			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();
	UNLEAK(rev);
	UNLEAK(ent);
	UNLEAK(blob);
	return result;
}
Esempio n. 21
0
File: diff.c Progetto: 13leaf/git
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) {
		/* builtin_diff_b_f() */
		GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
		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;
}
Esempio n. 22
0
int cmd_diff_tree(int argc, const char **argv, const char *prefix)
{
	int nr_sha1;
	char line[1000];
	struct object *tree1, *tree2;
	static struct rev_info *opt = &log_tree_opt;
	struct setup_revision_opt s_r_opt;
	int read_stdin = 0;

	init_revisions(opt, prefix);
	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
	opt->abbrev = 0;
	opt->diff = 1;
	opt->disable_stdin = 1;
	memset(&s_r_opt, 0, sizeof(s_r_opt));
	s_r_opt.tweak = diff_tree_tweak_rev;
	argc = setup_revisions(argc, argv, opt, &s_r_opt);

	while (--argc > 0) {
		const char *arg = *++argv;

		if (!strcmp(arg, "--stdin")) {
			read_stdin = 1;
			continue;
		}
		usage(diff_tree_usage);
	}

	/*
	 * NOTE! We expect "a ^b" to be equal to "a..b", so we
	 * reverse the order of the objects if the second one
	 * is marked UNINTERESTING.
	 */
	nr_sha1 = opt->pending.nr;
	switch (nr_sha1) {
	case 0:
		if (!read_stdin)
			usage(diff_tree_usage);
		break;
	case 1:
		tree1 = opt->pending.objects[0].item;
		diff_tree_commit_sha1(tree1->sha1);
		break;
	case 2:
		tree1 = opt->pending.objects[0].item;
		tree2 = opt->pending.objects[1].item;
		if (tree2->flags & UNINTERESTING) {
			struct object *tmp = tree2;
			tree2 = tree1;
			tree1 = tmp;
		}
		diff_tree_sha1(tree1->sha1,
			       tree2->sha1,
			       "", &opt->diffopt);
		log_tree_diff_flush(opt);
		break;
	}

	if (read_stdin) {
		if (opt->diffopt.detect_rename)
			opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
					       DIFF_SETUP_USE_CACHE);
		while (fgets(line, sizeof(line), stdin)) {
			unsigned char sha1[20];

			if (get_sha1_hex(line, sha1)) {
				fputs(line, stdout);
				fflush(stdout);
			}
			else
				diff_tree_stdin(line);
		}
	}

	return diff_result_code(&opt->diffopt, 0);
}
Esempio n. 23
0
static void print_summary(const char *prefix, const unsigned char *sha1)
{
	struct rev_info rev;
	struct commit *commit;
	struct strbuf format = STRBUF_INIT;
	unsigned char junk_sha1[20];
	const char *head = resolve_ref("HEAD", junk_sha1, 0, NULL);
	struct pretty_print_context pctx = {0};
	struct strbuf author_ident = STRBUF_INIT;
	struct strbuf committer_ident = STRBUF_INIT;

	commit = lookup_commit(sha1);
	if (!commit)
		die("couldn't look up newly created commit");
	if (!commit || parse_commit(commit))
		die("could not parse newly created commit");

	strbuf_addstr(&format, "format:%h] %s");

	format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
	format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
	if (strbuf_cmp(&author_ident, &committer_ident)) {
		strbuf_addstr(&format, "\n Author: ");
		strbuf_addbuf_percentquote(&format, &author_ident);
	}
	if (!user_ident_sufficiently_given()) {
		strbuf_addstr(&format, "\n Committer: ");
		strbuf_addbuf_percentquote(&format, &committer_ident);
		if (advice_implicit_identity) {
			strbuf_addch(&format, '\n');
			strbuf_addstr(&format, implicit_ident_advice);
		}
	}
	strbuf_release(&author_ident);
	strbuf_release(&committer_ident);

	init_revisions(&rev, prefix);
	setup_revisions(0, NULL, &rev, NULL);

	rev.diff = 1;
	rev.diffopt.output_format =
		DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;

	rev.verbose_header = 1;
	rev.show_root_diff = 1;
	get_commit_format(format.buf, &rev);
	rev.always_show_header = 0;
	rev.diffopt.detect_rename = 1;
	rev.diffopt.rename_limit = 100;
	rev.diffopt.break_opt = 0;
	diff_setup_done(&rev.diffopt);

	printf("[%s%s ",
		!prefixcmp(head, "refs/heads/") ?
			head + 11 :
			!strcmp(head, "HEAD") ?
				"detached HEAD" :
				head,
		initial_commit ? " (root-commit)" : "");

	if (!log_tree_commit(&rev, commit)) {
		rev.always_show_header = 1;
		rev.use_terminator = 1;
		log_tree_commit(&rev, commit);
	}

	strbuf_release(&format);
}
Esempio n. 24
0
File: ui-log.c Progetto: p00ya/cgit
void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern,
		    char *path, int pager)
{
	struct rev_info rev;
	struct commit *commit;
	const char *argv[] = {NULL, NULL, NULL, NULL, NULL};
	int argc = 2;
	int i, columns = 3;

	if (!tip)
		tip = ctx.qry.head;

	argv[1] = disambiguate_ref(tip);

	if (grep && pattern) {
		if (!strcmp(grep, "grep") || !strcmp(grep, "author") ||
		    !strcmp(grep, "committer"))
			argv[argc++] = fmt("--%s=%s", grep, pattern);
		if (!strcmp(grep, "range"))
			argv[1] = pattern;
	}

	if (path) {
		argv[argc++] = "--";
		argv[argc++] = path;
	}
	init_revisions(&rev, NULL);
	rev.abbrev = DEFAULT_ABBREV;
	rev.commit_format = CMIT_FMT_DEFAULT;
	rev.verbose_header = 1;
	rev.show_root_diff = 0;
	setup_revisions(argc, argv, &rev, NULL);
	load_ref_decorations(DECORATE_FULL_REFS);
	rev.show_decorations = 1;
	rev.grep_filter.regflags |= REG_ICASE;
	compile_grep_patterns(&rev.grep_filter);
	prepare_revision_walk(&rev);

	if (pager)
		html("<table class='list nowrap'>");

	html("<tr class='nohover'><th class='left'>Age</th>"
	      "<th class='left'>Commit message");
	if (pager) {
		html(" (");
		cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL,
			      NULL, ctx.qry.head, ctx.qry.sha1,
			      ctx.qry.vpath, ctx.qry.ofs, ctx.qry.grep,
			      ctx.qry.search, ctx.qry.showmsg ? 0 : 1);
		html(")");
	}
	html("</th><th class='left'>Author</th>");
	if (ctx.repo->enable_log_filecount) {
		html("<th class='left'>Files</th>");
		columns++;
		if (ctx.repo->enable_log_linecount) {
			html("<th class='left'>Lines</th>");
			columns++;
		}
	}
	html("</tr>\n");

	if (ofs<0)
		ofs = 0;

	for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) {
		free(commit->buffer);
		commit->buffer = NULL;
		free_commit_list(commit->parents);
		commit->parents = NULL;
	}

	for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
		print_commit(commit);
		free(commit->buffer);
		commit->buffer = NULL;
		free_commit_list(commit->parents);
		commit->parents = NULL;
	}
	if (pager) {
		htmlf("</table><div class='pager'>",
		     columns);
		if (ofs > 0) {
			cgit_log_link("[prev]", NULL, NULL, ctx.qry.head,
				      ctx.qry.sha1, ctx.qry.vpath,
				      ofs - cnt, ctx.qry.grep,
				      ctx.qry.search, ctx.qry.showmsg);
			html("&nbsp;");
		}
		if ((commit = get_revision(&rev)) != NULL) {
			cgit_log_link("[next]", NULL, NULL, ctx.qry.head,
				      ctx.qry.sha1, ctx.qry.vpath,
				      ofs + cnt, ctx.qry.grep,
				      ctx.qry.search, ctx.qry.showmsg);
		}
		html("</div>");
	} else if ((commit = get_revision(&rev)) != NULL) {
		html("<tr class='nohover'><td colspan='3'>");
		cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL,
			      ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg);
		html("</td></tr>\n");
	}
}
Esempio n. 25
0
File: log.c Progetto: AkiraS/git
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
			 struct rev_info *rev, struct setup_revision_opt *opt)
{
	struct userformat_want w;
	int quiet = 0, source = 0, mailmap = 0;
	static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};

	const struct option builtin_log_options[] = {
		OPT_BOOL(0, "quiet", &quiet, N_("suppress diff output")),
		OPT_BOOL(0, "source", &source, N_("show source")),
		OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
		{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
		  PARSE_OPT_OPTARG, decorate_callback},
		OPT_CALLBACK('L', NULL, &line_cb, "n,m:file",
			     "Process line range n,m in file, counting from 1",
			     log_line_range_callback),
		OPT_END()
	};

	line_cb.rev = rev;
	line_cb.prefix = prefix;

	mailmap = use_mailmap_config;
	argc = parse_options(argc, argv, prefix,
			     builtin_log_options, builtin_log_usage,
			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
			     PARSE_OPT_KEEP_DASHDASH);

	if (quiet)
		rev->diffopt.output_format |= DIFF_FORMAT_NO_OUTPUT;
	argc = setup_revisions(argc, argv, rev, opt);

	/* Any arguments at this point are not recognized */
	if (argc > 1)
		die("unrecognized argument: %s", argv[1]);

	memset(&w, 0, sizeof(w));
	userformat_find_requirements(NULL, &w);

	if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
		rev->show_notes = 1;
	if (rev->show_notes)
		init_display_notes(&rev->notes_opt);

	if (rev->diffopt.pickaxe || rev->diffopt.filter)
		rev->always_show_header = 0;
	if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
		rev->always_show_header = 0;
		if (rev->diffopt.pathspec.nr != 1)
			usage("git logs can only follow renames on one pathname at a time");
	}

	if (source)
		rev->show_source = 1;

	if (mailmap) {
		rev->mailmap = xcalloc(1, sizeof(struct string_list));
		read_mailmap(rev->mailmap, NULL);
	}

	if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {
		/*
		 * "log --pretty=raw" is special; ignore UI oriented
		 * configuration variables such as decoration.
		 */
		if (!decoration_given)
			decoration_style = 0;
		if (!rev->abbrev_commit_given)
			rev->abbrev_commit = 0;
	}

	if (decoration_style) {
		rev->show_decorations = 1;
		load_ref_decorations(decoration_style);
	}

	if (rev->line_level_traverse)
		line_log_init(rev, line_cb.prefix, &line_cb.args);

	setup_pager();
}
Esempio n. 26
0
int cmd_shortlog(int argc, const char **argv, const char *prefix)
{
	struct shortlog log = { STRING_LIST_INIT_NODUP };
	struct rev_info rev;
	int nongit = !startup_info->have_repository;

	const struct option options[] = {
		OPT_BOOL('c', "committer", &log.committer,
			 N_("Group by committer rather than author")),
		OPT_BOOL('n', "numbered", &log.sort_by_number,
			 N_("sort output according to the number of commits per author")),
		OPT_BOOL('s', "summary", &log.summary,
			 N_("Suppress commit descriptions, only provides commit count")),
		OPT_BOOL('e', "email", &log.email,
			 N_("Show the email address of each author")),
		{ OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
			N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
		OPT_END(),
	};

	struct parse_opt_ctx_t ctx;

	git_config(git_default_config, NULL);
	shortlog_init(&log);
	init_revisions(&rev, prefix);
	parse_options_start(&ctx, argc, argv, prefix, options,
			    PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);

	for (;;) {
		switch (parse_options_step(&ctx, options, shortlog_usage)) {
		case PARSE_OPT_HELP:
			exit(129);
		case PARSE_OPT_DONE:
			goto parse_done;
		}
		parse_revision_opt(&rev, &ctx, options, shortlog_usage);
	}
parse_done:
	argc = parse_options_end(&ctx);

	if (setup_revisions(argc, argv, &rev, NULL) != 1) {
		error(_("unrecognized argument: %s"), argv[1]);
		usage_with_options(shortlog_usage, options);
	}

	log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
	log.abbrev = rev.abbrev;
	log.file = rev.diffopt.file;

	/* assume HEAD if from a tty */
	if (!nongit && !rev.pending.nr && isatty(0))
		add_head_to_pending(&rev);
	if (rev.pending.nr == 0) {
		if (isatty(0))
			fprintf(stderr, _("(reading log message from standard input)\n"));
		read_from_stdin(&log);
	}
	else
		get_from_rev(&rev, &log);

	shortlog_output(&log);
	if (log.file != stdout)
		fclose(log.file);
	return 0;
}
Esempio n. 27
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;
}
Esempio n. 28
0
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;
}
Esempio n. 29
0
void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern,
		    char *path, int pager, int commit_graph, int commit_sort)
{
	struct rev_info rev;
	struct commit *commit;
	struct argv_array rev_argv = ARGV_ARRAY_INIT;
	int i, columns = commit_graph ? 4 : 3;
	int must_free_tip = 0;

	/* rev_argv.argv[0] will be ignored by setup_revisions */
	argv_array_push(&rev_argv, "log_rev_setup");

	if (!tip)
		tip = ctx.qry.head;
	tip = disambiguate_ref(tip, &must_free_tip);
	argv_array_push(&rev_argv, tip);

	if (grep && pattern && *pattern) {
		pattern = xstrdup(pattern);
		if (!strcmp(grep, "grep") || !strcmp(grep, "author") ||
		    !strcmp(grep, "committer")) {
			argv_array_pushf(&rev_argv, "--%s=%s", grep, pattern);
		} else if (!strcmp(grep, "range")) {
			char *arg;
			/* Split the pattern at whitespace and add each token
			 * as a revision expression. Do not accept other
			 * rev-list options. Also, replace the previously
			 * pushed tip (it's no longer relevant).
			 */
			argv_array_pop(&rev_argv);
			while ((arg = next_token(&pattern))) {
				if (*arg == '-') {
					fprintf(stderr, "Bad range expr: %s\n",
						arg);
					break;
				}
				argv_array_push(&rev_argv, arg);
			}
		}
	}
	if (commit_graph) {
		argv_array_push(&rev_argv, "--graph");
		argv_array_push(&rev_argv, "--color");
		graph_set_column_colors(column_colors_html,
					COLUMN_COLORS_HTML_MAX);
	}

	if (commit_sort == 1)
		argv_array_push(&rev_argv, "--date-order");
	else if (commit_sort == 2)
		argv_array_push(&rev_argv, "--topo-order");

	if (path) {
		argv_array_push(&rev_argv, "--");
		argv_array_push(&rev_argv, path);
	}

	init_revisions(&rev, NULL);
	rev.abbrev = DEFAULT_ABBREV;
	rev.commit_format = CMIT_FMT_DEFAULT;
	rev.verbose_header = 1;
	rev.show_root_diff = 0;
	setup_revisions(rev_argv.argc, rev_argv.argv, &rev, NULL);
	load_ref_decorations(DECORATE_FULL_REFS);
	rev.show_decorations = 1;
	rev.grep_filter.regflags |= REG_ICASE;
	compile_grep_patterns(&rev.grep_filter);
	prepare_revision_walk(&rev);

	if (pager)
		html("<table class='list nowrap'>");

	html("<tr class='nohover'>");
	if (commit_graph)
		html("<th></th>");
	else
		html("<th class='left'>Age</th>");
	html("<th class='left'>Commit message");
	if (pager) {
		html(" (");
		cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL,
			      NULL, ctx.qry.head, ctx.qry.sha1,
			      ctx.qry.vpath, ctx.qry.ofs, ctx.qry.grep,
			      ctx.qry.search, ctx.qry.showmsg ? 0 : 1);
		html(")");
	}
	html("</th><th class='left'>Author</th>");
	if (commit_graph)
		html("<th class='left'>Age</th>");
	if (ctx.repo->enable_log_filecount) {
		html("<th class='left'>Files</th>");
		columns++;
	}
	if (ctx.repo->enable_log_linecount) {
		html("<th class='left'>Lines</th>");
		columns++;
	}
	html("</tr>\n");

	if (ofs<0)
		ofs = 0;

	for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) {
		free(commit->buffer);
		commit->buffer = NULL;
		free_commit_list(commit->parents);
		commit->parents = NULL;
	}

	for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
		print_commit(commit, &rev);
		free(commit->buffer);
		commit->buffer = NULL;
		free_commit_list(commit->parents);
		commit->parents = NULL;
	}
	if (pager) {
		html("</table><ul class='pager'>");
		if (ofs > 0) {
			html("<li>");
			cgit_log_link("[prev]", NULL, NULL, ctx.qry.head,
				      ctx.qry.sha1, ctx.qry.vpath,
				      ofs - cnt, ctx.qry.grep,
				      ctx.qry.search, ctx.qry.showmsg);
			html("</li>");
		}
		if ((commit = get_revision(&rev)) != NULL) {
			html("<li>");
			cgit_log_link("[next]", NULL, NULL, ctx.qry.head,
				      ctx.qry.sha1, ctx.qry.vpath,
				      ofs + cnt, ctx.qry.grep,
				      ctx.qry.search, ctx.qry.showmsg);
			html("</li>");
		}
		html("</ul>");
	} else if ((commit = get_revision(&rev)) != NULL) {
		htmlf("<tr class='nohover'><td colspan='%d'>", columns);
		cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL,
			      ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg);
		html("</td></tr>\n");
	}

	/* If we allocated tip then it is safe to cast away const. */
	if (must_free_tip)
		free((char*) tip);
}