Esempio n. 1
0
static int merge(int argc, const char **argv, const char *prefix)
{
	struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;
	struct object_id result_oid;
	struct notes_tree *t;
	struct notes_merge_options o;
	int do_merge = 0, do_commit = 0, do_abort = 0;
	int verbosity = 0, result;
	const char *strategy = NULL;
	struct option options[] = {
		OPT_GROUP(N_("General options")),
		OPT__VERBOSITY(&verbosity),
		OPT_GROUP(N_("Merge options")),
		OPT_STRING('s', "strategy", &strategy, N_("strategy"),
			   N_("resolve notes conflicts using the given strategy "
			      "(manual/ours/theirs/union/cat_sort_uniq)")),
		OPT_GROUP(N_("Committing unmerged notes")),
		{ OPTION_SET_INT, 0, "commit", &do_commit, NULL,
			N_("finalize notes merge by committing unmerged notes"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
		OPT_GROUP(N_("Aborting notes merge resolution")),
		{ OPTION_SET_INT, 0, "abort", &do_abort, NULL,
			N_("abort notes merge"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
		OPT_END()
	};

	argc = parse_options(argc, argv, prefix, options,
			     git_notes_merge_usage, 0);

	if (strategy || do_commit + do_abort == 0)
		do_merge = 1;
	if (do_merge + do_commit + do_abort != 1) {
		error(_("cannot mix --commit, --abort or -s/--strategy"));
		usage_with_options(git_notes_merge_usage, options);
	}

	if (do_merge && argc != 1) {
		error(_("must specify a notes ref to merge"));
		usage_with_options(git_notes_merge_usage, options);
	} else if (!do_merge && argc) {
		error(_("too many parameters"));
		usage_with_options(git_notes_merge_usage, options);
	}

	init_notes_merge_options(&o);
	o.verbosity = verbosity + NOTES_MERGE_VERBOSITY_DEFAULT;

	if (do_abort)
		return merge_abort(&o);
	if (do_commit)
		return merge_commit(&o);

	o.local_ref = default_notes_ref();
	strbuf_addstr(&remote_ref, argv[0]);
	expand_loose_notes_ref(&remote_ref);
	o.remote_ref = remote_ref.buf;

	t = init_notes_check("merge", NOTES_INIT_WRITABLE);

	if (strategy) {
		if (parse_notes_merge_strategy(strategy, &o.strategy)) {
			error(_("unknown -s/--strategy: %s"), strategy);
			usage_with_options(git_notes_merge_usage, options);
		}
	} else {
		struct strbuf merge_key = STRBUF_INIT;
		const char *short_ref = NULL;

		if (!skip_prefix(o.local_ref, "refs/notes/", &short_ref))
			die("BUG: local ref %s is outside of refs/notes/",
			    o.local_ref);

		strbuf_addf(&merge_key, "notes.%s.mergeStrategy", short_ref);

		if (git_config_get_notes_strategy(merge_key.buf, &o.strategy))
			git_config_get_notes_strategy("notes.mergeStrategy", &o.strategy);

		strbuf_release(&merge_key);
	}

	strbuf_addf(&msg, "notes: Merged notes from %s into %s",
		    remote_ref.buf, default_notes_ref());
	strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */

	result = notes_merge(&o, t, &result_oid);

	if (result >= 0) /* Merge resulted (trivially) in result_oid */
		/* Update default notes ref with new commit */
		update_ref(msg.buf, default_notes_ref(), result_oid.hash, NULL,
			   0, UPDATE_REFS_DIE_ON_ERR);
	else { /* Merge has unresolved conflicts */
		const struct worktree *wt;
		/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
		update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_oid.hash, NULL,
			   0, UPDATE_REFS_DIE_ON_ERR);
		/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
		wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
		if (wt)
			die(_("a notes merge into %s is already in-progress at %s"),
			    default_notes_ref(), wt->path);
		if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
			die(_("failed to store link to current notes ref (%s)"),
			    default_notes_ref());
		printf(_("Automatic notes merge failed. Fix conflicts in %s and "
			 "commit the result with 'git notes merge --commit', or "
			 "abort the merge with 'git notes merge --abort'.\n"),
		       git_path(NOTES_MERGE_WORKTREE));
	}

	free_notes(t);
	strbuf_release(&remote_ref);
	strbuf_release(&msg);
	return result < 0; /* return non-zero on conflicts */
}
Esempio n. 2
0
File: ls-remote.c Progetto: avar/git
int cmd_ls_remote(int argc, const char **argv, const char *prefix)
{
	const char *dest = NULL;
	unsigned flags = 0;
	int get_url = 0;
	int quiet = 0;
	int status = 0;
	int show_symref_target = 0;
	const char *uploadpack = NULL;
	const char **pattern = NULL;

	struct remote *remote;
	struct transport *transport;
	const struct ref *ref;

	struct option options[] = {
		OPT__QUIET(&quiet, N_("do not print remote URL")),
		OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"),
			   N_("path of git-upload-pack on the remote host")),
		{ OPTION_STRING, 0, "exec", &uploadpack, N_("exec"),
			   N_("path of git-upload-pack on the remote host"),
			   PARSE_OPT_HIDDEN },
		OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS),
		OPT_BIT('h', "heads", &flags, N_("limit to heads"), REF_HEADS),
		OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL),
		OPT_BOOL(0, "get-url", &get_url,
			 N_("take url.<base>.insteadOf into account")),
		OPT_SET_INT(0, "exit-code", &status,
			    N_("exit with exit code 2 if no matching refs are found"), 2),
		OPT_BOOL(0, "symref", &show_symref_target,
			 N_("show underlying ref in addition to the object pointed by it")),
		OPT_END()
	};

	argc = parse_options(argc, argv, prefix, options, ls_remote_usage,
			     PARSE_OPT_STOP_AT_NON_OPTION);
	dest = argv[0];

	if (argc > 1) {
		int i;
		pattern = xcalloc(argc, sizeof(const char *));
		for (i = 1; i < argc; i++)
			pattern[i - 1] = xstrfmt("*/%s", argv[i]);
	}

	remote = remote_get(dest);
	if (!remote) {
		if (dest)
			die("bad repository '%s'", dest);
		die("No remote configured to list refs from.");
	}
	if (!remote->url_nr)
		die("remote %s has no configured URL", dest);

	if (get_url) {
		printf("%s\n", *remote->url);
		return 0;
	}

	transport = transport_get(remote, NULL);
	if (uploadpack != NULL)
		transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);

	ref = transport_get_remote_refs(transport);
	if (transport_disconnect(transport))
		return 1;

	if (!dest && !quiet)
		fprintf(stderr, "From %s\n", *remote->url);
	for ( ; ref; ref = ref->next) {
		if (!check_ref_type(ref, flags))
			continue;
		if (!tail_match(pattern, ref->name))
			continue;
		if (show_symref_target && ref->symref)
			printf("ref: %s\t%s\n", ref->symref, ref->name);
		printf("%s\t%s\n", oid_to_hex(&ref->old_oid), ref->name);
		status = 0; /* we found something */
	}
	return status;
}
Esempio n. 3
0
	OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
	OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"),
	OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),

	OPT_GROUP("Commit contents options"),
	OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
	OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
	OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
	OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
	OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
	OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
	{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
	OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
	OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),

	OPT_END()
};

static void rollback_index_files(void)
{
	switch (commit_style) {
	case COMMIT_AS_IS:
		break; /* nothing to do */
	case COMMIT_NORMAL:
		rollback_lock_file(&index_lock);
		break;
	case COMMIT_PARTIAL:
		rollback_lock_file(&index_lock);
		rollback_lock_file(&false_lock);
		break;
	}
Esempio n. 4
0
int main(int argc, char **argv)
{
    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [-vusoxm] [-d DIR]/[-D] [FILE]\n"
        "\n"
        "Extract oops from FILE (or standard input)"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_s = 1 << 1,
        OPT_o = 1 << 2,
        OPT_d = 1 << 3,
        OPT_D = 1 << 4,
        OPT_u = 1 << 5,
        OPT_x = 1 << 6,
        OPT_t = 1 << 7,
        OPT_m = 1 << 8,
    };
    char *problem_dir = NULL;
    char *dump_location = NULL;
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_BOOL(  's', NULL, NULL, _("Log to syslog")),
        OPT_BOOL(  'o', NULL, NULL, _("Print found oopses on standard output")),
        /* oopses don't contain any sensitive info, and even
         * the old koops app was showing the oopses to all users
         */
        OPT_STRING('d', NULL, &dump_location, "DIR", _("Create new problem directory in DIR for every oops found")),
        OPT_BOOL(  'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")),
        OPT_STRING('u', NULL, &problem_dir, "PROBLEM", _("Save the extracted information in PROBLEM")),
        OPT_BOOL(  'x', NULL, NULL, _("Make the problem directory world readable")),
        OPT_BOOL(  't', NULL, NULL, _("Throttle problem directory creation to 1 per second")),
        OPT_BOOL(  'm', NULL, NULL, _("Print search string(s) to stdout and exit")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    msg_prefix = g_progname;
    if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
    {
        logmode = LOGMODE_JOURNAL;
    }

    if (opts & OPT_m)
    {
        char *oops_string_filter_regex = abrt_oops_string_filter_regex();
        if (oops_string_filter_regex)
        {
            regex_t filter_re;
            if (regcomp(&filter_re, oops_string_filter_regex, REG_NOSUB) != 0)
                perror_msg_and_die(_("Failed to compile regex"));

            const regex_t *filter[] = { &filter_re, NULL };

            koops_print_suspicious_strings_filtered(filter);

            regfree(&filter_re);
            free(oops_string_filter_regex);
        }
        else
            koops_print_suspicious_strings();

        return 1;
    }

    if (opts & OPT_D)
    {
        if (opts & OPT_d)
            show_usage_and_die(program_usage_string, program_options);
        load_abrt_conf();
        dump_location = g_settings_dump_location;
        g_settings_dump_location = NULL;
        free_abrt_conf_data();
    }

    int oops_utils_flags = 0;
    if ((opts & OPT_x))
        oops_utils_flags |= ABRT_OOPS_WORLD_READABLE;

    if ((opts & OPT_t))
        oops_utils_flags |= ABRT_OOPS_THROTTLE_CREATION;

    if ((opts & OPT_o))
        oops_utils_flags |= ABRT_OOPS_PRINT_STDOUT;

    argv += optind;
    if (argv[0])
        xmove_fd(xopen(argv[0], O_RDONLY), STDIN_FILENO);

    GList *oops_list = NULL;
    scan_syslog_file(&oops_list, STDIN_FILENO);

    unsigned errors = 0;
    if (opts & OPT_u)
    {
        log("Updating problem directory");
        switch (g_list_length(oops_list))
        {
            case 0:
                {
                    error_msg(_("Can't update the problem: no oops found"));
                    errors = 1;
                    break;
                }
            default:
                {
                    log_notice(_("More oopses found: process only the first one"));
                }
                /* falls trought */
            case 1:
                {
                    struct dump_dir *dd = dd_opendir(problem_dir, /*open for writing*/0);
                    if (dd)
                    {
                        abrt_oops_save_data_in_dump_dir(dd, (char *)oops_list->data, /*no proc modules*/NULL);
                        dd_close(dd);
                    }
                }
        }
    }
    else
        errors = abrt_oops_process_list(oops_list, dump_location,
                                        ABRT_DUMP_OOPS_ANALYZER, oops_utils_flags);

    list_free_with_free(oops_list);
    //oops_list = NULL;

    return errors;
}
Esempio n. 5
0
static int update_clone(int argc, const char **argv, const char *prefix)
{
	const char *update = NULL;
	int max_jobs = -1;
	struct string_list_item *item;
	struct pathspec pathspec;
	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;

	struct option module_update_clone_options[] = {
		OPT_STRING(0, "prefix", &prefix,
			   N_("path"),
			   N_("path into the working tree")),
		OPT_STRING(0, "recursive-prefix", &suc.recursive_prefix,
			   N_("path"),
			   N_("path into the working tree, across nested "
			      "submodule boundaries")),
		OPT_STRING(0, "update", &update,
			   N_("string"),
			   N_("rebase, merge, checkout or none")),
		OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
			   N_("reference repository")),
		OPT_STRING(0, "depth", &suc.depth, "<depth>",
			   N_("Create a shallow clone truncated to the "
			      "specified number of revisions")),
		OPT_INTEGER('j', "jobs", &max_jobs,
			    N_("parallel jobs")),
		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
			    N_("whether the initial clone should follow the shallow recommendation")),
		OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
		OPT_BOOL(0, "progress", &suc.progress,
			    N_("force cloning progress")),
		OPT_END()
	};

	const char *const git_submodule_helper_usage[] = {
		N_("git submodule--helper update_clone [--prefix=<path>] [<path>...]"),
		NULL
	};
	suc.prefix = prefix;

	argc = parse_options(argc, argv, prefix, module_update_clone_options,
			     git_submodule_helper_usage, 0);

	if (update)
		if (parse_submodule_update_strategy(update, &suc.update) < 0)
			die(_("bad value for update parameter"));

	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
		return 1;

	if (pathspec.nr)
		suc.warn_if_uninitialized = 1;

	/* Overlay the parsed .gitmodules file with .git/config */
	gitmodules_config();
	git_config(submodule_config, NULL);

	if (max_jobs < 0)
		max_jobs = parallel_submodules();

	run_processes_parallel(max_jobs,
			       update_clone_get_next_task,
			       update_clone_start_failure,
			       update_clone_task_finished,
			       &suc);

	/*
	 * We saved the output and put it out all at once now.
	 * That means:
	 * - the listener does not have to interleave their (checkout)
	 *   work with our fetching.  The writes involved in a
	 *   checkout involve more straightforward sequential I/O.
	 * - the listener can avoid doing any work if fetching failed.
	 */
	if (suc.quickstop)
		return 1;

	for_each_string_list_item(item, &suc.projectlines)
		utf8_fprintf(stdout, "%s", item->string);

	return 0;
}
Esempio n. 6
0
int main(int argc, char** argv)
{
    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    int parent_pid = getpid();

    const char *program_usage_string = _(
        "& [options]"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_s = 1 << 2,
// TODO: get rid of -t NUM, it is no longer useful since dbus is moved to a separate tool
        OPT_t = 1 << 3,
        OPT_p = 1 << 4,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_BOOL(   'd', NULL, NULL      , _("Do not daemonize")),
        OPT_BOOL(   's', NULL, NULL      , _("Log to syslog even with -d")),
        OPT_INTEGER('t', NULL, &s_timeout, _("Exit after NUM seconds of inactivity")),
        OPT_BOOL(   'p', NULL, NULL      , _("Add program names to log")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(opts & OPT_p);

#if 0 /* We no longer use dbus */
    /* When dbus daemon starts us, it doesn't set PATH
     * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE).
     * In this case, set something sane:
     */
    const char *env_path = getenv("PATH");
    if (!env_path || !env_path[0])
        putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin");
#endif

    unsetenv("ABRT_SYSLOG");
    msg_prefix = g_progname; /* for log_warning(), error_msg() and such */

    if (getuid() != 0)
        error_msg_and_die("Must be run as root");

    if (opts & OPT_s)
        start_logging();

    xpipe(s_signal_pipe);
    close_on_exec_on(s_signal_pipe[0]);
    close_on_exec_on(s_signal_pipe[1]);
    ndelay_on(s_signal_pipe[0]); /* I/O should not block - */
    ndelay_on(s_signal_pipe[1]); /* especially writes! they happen in signal handler! */
    signal(SIGTERM, handle_signal);
    signal(SIGINT,  handle_signal);
    signal(SIGCHLD, handle_signal);

    GIOChannel* channel_signal = NULL;
    guint channel_id_signal_event = 0;
    bool pidfile_created = false;
    struct abrt_inotify_watch *aiw = NULL;
    int ret = 1;

    /* Initialization */
    log_notice("Loading settings");
    if (load_abrt_conf() != 0)
        goto init_error;

    /* Moved before daemonization because parent waits for signal from daemon
     * only for short period and time consumed by
     * mark_unprocessed_dump_dirs_not_reportable() is slightly unpredictable.
     */
    sanitize_dump_dir_rights();
    mark_unprocessed_dump_dirs_not_reportable(g_settings_dump_location);

    /* Daemonize unless -d */
    if (!(opts & OPT_d))
    {
        /* forking to background */
        fflush(NULL); /* paranoia */
        pid_t pid = fork();
        if (pid < 0)
        {
            perror_msg_and_die("fork");
        }
        if (pid > 0)
        {
            /* Parent */
            /* Wait for child to notify us via SIGTERM that it feels ok */
            int i = 20; /* 2 sec */
            while (s_sig_caught == 0 && --i)
            {
                usleep(100 * 1000);
            }
            if (s_sig_caught == SIGTERM)
            {
                exit(0);
            }
            if (s_sig_caught)
            {
                error_msg_and_die("Failed to start: got sig %d", s_sig_caught);
            }
            error_msg_and_die("Failed to start: timeout waiting for child");
        }
        /* Child (daemon) continues */
        if (setsid() < 0)
            perror_msg_and_die("setsid");
        if (g_verbose == 0 && logmode != LOGMODE_JOURNAL)
            start_logging();
    }

    log_notice("Creating glib main loop");
    s_main_loop = g_main_loop_new(NULL, FALSE);

    /* Watching 'g_settings_dump_location' for delete self
     * because hooks expects that the dump location exists if abrtd is running
     */
    aiw = abrt_inotify_watch_init(g_settings_dump_location,
            IN_DUMP_LOCATION_FLAGS, handle_inotify_cb, /*user data*/NULL);

    /* Add an event source which waits for INT/TERM signal */
    log_notice("Adding signal pipe watch to glib main loop");
    channel_signal = abrt_gio_channel_unix_new(s_signal_pipe[0]);
    channel_id_signal_event = add_watch_or_die(channel_signal,
                        G_IO_IN | G_IO_PRI | G_IO_HUP,
                        handle_signal_cb);

    guint name_id = 0;

    /* Mark the territory */
    log_notice("Creating pid file");
    if (create_pidfile() != 0)
        goto init_error;
    pidfile_created = true;

    /* Open socket to receive new problem data (from python etc). */
    dumpsocket_init();

    /* Inform parent that we initialized ok */
    if (!(opts & OPT_d))
    {
        log_notice("Signalling parent");
        kill(parent_pid, SIGTERM);
        if (logmode != LOGMODE_JOURNAL)
            start_logging();
    }

    /* Only now we want signal pipe to work */
    s_signal_pipe_write = s_signal_pipe[1];

    /* Own a name on D-Bus */
    name_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
                             ABRTD_DBUS_NAME,
                             G_BUS_NAME_OWNER_FLAGS_NONE,
                             on_bus_acquired,
                             on_name_acquired,
                             on_name_lost,
                             NULL, NULL);

    start_idle_timeout();

    /* Enter the event loop */
    log_debug("Init complete, entering main loop");
    g_main_loop_run(s_main_loop);

    ret = 0;
    /* Jump to exit */
    goto cleanup;


 init_error:
    /* Initialization error */
    error_msg("Error while initializing daemon");
    /* Inform parent that initialization failed */
    if (!(opts & OPT_d))
        kill(parent_pid, SIGINT);


 cleanup:
    if (name_id > 0)
        g_bus_unown_name (name_id);

    /* Error or INT/TERM. Clean up, in reverse order.
     * Take care to not undo things we did not do.
     */
    dumpsocket_shutdown();
    if (pidfile_created)
        unlink(VAR_RUN_PIDFILE);

    if (channel_id_signal_event > 0)
        g_source_remove(channel_id_signal_event);
    if (channel_signal)
        g_io_channel_unref(channel_signal);

    abrt_inotify_watch_destroy(aiw);

    if (s_main_loop)
        g_main_loop_unref(s_main_loop);

    free_abrt_conf_data();

    if (s_sig_caught && s_sig_caught != SIGCHLD)
    {
        /* We use TERM to stop abrtd, so not printing out error message. */
        if (s_sig_caught != SIGTERM)
        {
            error_msg("Got signal %d, exiting", s_sig_caught);
            signal(s_sig_caught, SIG_DFL);
            raise(s_sig_caught);
        }
    }

    /* Exiting */
    log_notice("Exiting");
    return ret;
}
Esempio n. 7
0
int cmd_merge_file(int argc, const char **argv, const char *prefix)
{
	const char *names[3] = { NULL, NULL, NULL };
	mmfile_t mmfs[3];
	mmbuffer_t result = {NULL, 0};
	xmparam_t xmp = {{XDF_NEED_MINIMAL}};
	int ret = 0, i = 0, to_stdout = 0;
	int quiet = 0;
	int nongit;
	struct option options[] = {
		OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
		OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3),
		OPT_SET_INT(0, "ours", &xmp.favor, "for conflicts, use our version",
			    XDL_MERGE_FAVOR_OURS),
		OPT_SET_INT(0, "theirs", &xmp.favor, "for conflicts, use their version",
			    XDL_MERGE_FAVOR_THEIRS),
		OPT_SET_INT(0, "union", &xmp.favor, "for conflicts, use a union version",
			    XDL_MERGE_FAVOR_UNION),
		OPT_INTEGER(0, "marker-size", &xmp.marker_size,
			    "for conflicts, use this marker size"),
		OPT__QUIET(&quiet),
		OPT_CALLBACK('L', NULL, names, "name",
			     "set labels for file1/orig_file/file2", &label_cb),
		OPT_END(),
	};

	xmp.level = XDL_MERGE_ZEALOUS_ALNUM;
	xmp.style = 0;
	xmp.favor = 0;

	prefix = setup_git_directory_gently(&nongit);
	if (!nongit) {
		/* Read the configuration file */
		git_config(git_xmerge_config, NULL);
		if (0 <= git_xmerge_style)
			xmp.style = git_xmerge_style;
	}

	argc = parse_options(argc, argv, prefix, options, merge_file_usage, 0);
	if (argc != 3)
		usage_with_options(merge_file_usage, options);
	if (quiet) {
		if (!freopen("/dev/null", "w", stderr))
			return error("failed to redirect stderr to /dev/null: "
				     "%s\n", strerror(errno));
	}

	for (i = 0; i < 3; i++) {
		if (!names[i])
			names[i] = argv[i];
		if (read_mmfile(mmfs + i, argv[i]))
			return -1;
		if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
			return error("Cannot merge binary files: %s\n",
					argv[i]);
	}

	xmp.ancestor = names[1];
	xmp.file1 = names[0];
	xmp.file2 = names[2];
	ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);

	for (i = 0; i < 3; i++)
		free(mmfs[i].ptr);

	if (ret >= 0) {
		const char *filename = argv[0];
		FILE *f = to_stdout ? stdout : fopen(filename, "wb");

		if (!f)
			ret = error("Could not open %s for writing", filename);
		else if (result.size &&
			 fwrite(result.ptr, result.size, 1, f) != 1)
			ret = error("Could not write to %s", filename);
		else if (fclose(f))
			ret = error("Could not close %s", filename);
		free(result.ptr);
	}

	return ret;
}
Esempio n. 8
0
File: mv.c Progetto: DoWonJin/git
int cmd_mv(int argc, const char **argv, const char *prefix)
{
	int i, flags, gitmodules_modified = 0;
	int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
	struct option builtin_mv_options[] = {
		OPT__VERBOSE(&verbose, N_("be verbose")),
		OPT__DRY_RUN(&show_only, N_("dry run")),
		OPT__FORCE(&force, N_("force move/rename even if target exists"),
			   PARSE_OPT_NOCOMPLETE),
		OPT_BOOL('k', NULL, &ignore_errors, N_("skip move/rename errors")),
		OPT_END(),
	};
	const char **source, **destination, **dest_path, **submodule_gitfile;
	enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
	struct stat st;
	struct string_list src_for_dst = STRING_LIST_INIT_NODUP;

	git_config(git_default_config, NULL);

	argc = parse_options(argc, argv, prefix, builtin_mv_options,
			     builtin_mv_usage, 0);
	if (--argc < 1)
		usage_with_options(builtin_mv_usage, builtin_mv_options);

	hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
	if (read_cache() < 0)
		die(_("index file corrupt"));

	source = internal_prefix_pathspec(prefix, argv, argc, 0);
	modes = xcalloc(argc, sizeof(enum update_mode));
	/*
	 * Keep trailing slash, needed to let
	 * "git mv file no-such-dir/" error out, except in the case
	 * "git mv directory no-such-dir/".
	 */
	flags = KEEP_TRAILING_SLASH;
	if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
		flags = 0;
	dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
	submodule_gitfile = xcalloc(argc, sizeof(char *));

	if (dest_path[0][0] == '\0')
		/* special case: "." was normalized to "" */
		destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
	else if (!lstat(dest_path[0], &st) &&
			S_ISDIR(st.st_mode)) {
		dest_path[0] = add_slash(dest_path[0]);
		destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
	} else {
		if (argc != 1)
			die(_("destination '%s' is not a directory"), dest_path[0]);
		destination = dest_path;
	}

	/* Checking */
	for (i = 0; i < argc; i++) {
		const char *src = source[i], *dst = destination[i];
		int length, src_is_dir;
		const char *bad = NULL;

		if (show_only)
			printf(_("Checking rename of '%s' to '%s'\n"), src, dst);

		length = strlen(src);
		if (lstat(src, &st) < 0)
			bad = _("bad source");
		else if (!strncmp(src, dst, length) &&
				(dst[length] == 0 || dst[length] == '/')) {
			bad = _("can not move directory into itself");
		} else if ((src_is_dir = S_ISDIR(st.st_mode))
				&& lstat(dst, &st) == 0)
			bad = _("cannot move directory over file");
		else if (src_is_dir) {
			int first = cache_name_pos(src, length), last;

			if (first >= 0)
				prepare_move_submodule(src, first,
						       submodule_gitfile + i);
			else if (index_range_of_same_dir(src, length,
							 &first, &last) < 1)
				bad = _("source directory is empty");
			else { /* last - first >= 1 */
				int j, dst_len, n;

				modes[i] = WORKING_DIRECTORY;
				n = argc + last - first;
				REALLOC_ARRAY(source, n);
				REALLOC_ARRAY(destination, n);
				REALLOC_ARRAY(modes, n);
				REALLOC_ARRAY(submodule_gitfile, n);

				dst = add_slash(dst);
				dst_len = strlen(dst);

				for (j = 0; j < last - first; j++) {
					const char *path = active_cache[first + j]->name;
					source[argc + j] = path;
					destination[argc + j] =
						prefix_path(dst, dst_len, path + length + 1);
					modes[argc + j] = INDEX;
					submodule_gitfile[argc + j] = NULL;
				}
				argc += last - first;
			}
		} else if (cache_name_pos(src, length) < 0)
			bad = _("not under version control");
		else if (lstat(dst, &st) == 0 &&
			 (!ignore_case || strcasecmp(src, dst))) {
			bad = _("destination exists");
			if (force) {
				/*
				 * only files can overwrite each other:
				 * check both source and destination
				 */
				if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
					if (verbose)
						warning(_("overwriting '%s'"), dst);
					bad = NULL;
				} else
					bad = _("Cannot overwrite");
			}
		} else if (string_list_has_string(&src_for_dst, dst))
			bad = _("multiple sources for the same target");
		else if (is_dir_sep(dst[strlen(dst) - 1]))
			bad = _("destination directory does not exist");
		else
			string_list_insert(&src_for_dst, dst);

		if (!bad)
			continue;
		if (!ignore_errors)
			die(_("%s, source=%s, destination=%s"),
			     bad, src, dst);
		if (--argc > 0) {
			int n = argc - i;
			memmove(source + i, source + i + 1,
				n * sizeof(char *));
			memmove(destination + i, destination + i + 1,
				n * sizeof(char *));
			memmove(modes + i, modes + i + 1,
				n * sizeof(enum update_mode));
			memmove(submodule_gitfile + i, submodule_gitfile + i + 1,
				n * sizeof(char *));
			i--;
		}
	}

	for (i = 0; i < argc; i++) {
		const char *src = source[i], *dst = destination[i];
		enum update_mode mode = modes[i];
		int pos;
		if (show_only || verbose)
			printf(_("Renaming %s to %s\n"), src, dst);
		if (show_only)
			continue;
		if (mode != INDEX && rename(src, dst) < 0) {
			if (ignore_errors)
				continue;
			die_errno(_("renaming '%s' failed"), src);
		}
		if (submodule_gitfile[i]) {
			if (!update_path_in_gitmodules(src, dst))
				gitmodules_modified = 1;
			if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
				connect_work_tree_and_git_dir(dst,
							      submodule_gitfile[i],
							      1);
		}

		if (mode == WORKING_DIRECTORY)
			continue;

		pos = cache_name_pos(src, strlen(src));
		assert(pos >= 0);
		rename_cache_entry_at(pos, dst);
	}

	if (gitmodules_modified)
		stage_updated_gitmodules(&the_index);

	if (write_locked_index(&the_index, &lock_file,
			       COMMIT_LOCK | SKIP_IF_UNCHANGED))
		die(_("Unable to write new index file"));

	return 0;
}
Esempio n. 9
0
static int parse_archive_args(int argc, const char **argv,
		const struct archiver **ar, struct archiver_args *args,
		const char *name_hint, int is_remote)
{
	const char *format = NULL;
	const char *base = NULL;
	const char *remote = NULL;
	const char *exec = NULL;
	const char *output = NULL;
	int compression_level = -1;
	int verbose = 0;
	int i;
	int list = 0;
	int worktree_attributes = 0;
	struct option opts[] = {
		OPT_GROUP(""),
		OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
		OPT_STRING(0, "prefix", &base, N_("prefix"),
			N_("prepend prefix to each pathname in the archive")),
		OPT_STRING('o', "output", &output, N_("file"),
			N_("write the archive to this file")),
		OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
			N_("read .gitattributes in working directory")),
		OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
		OPT__COMPR('0', &compression_level, N_("store only"), 0),
		OPT__COMPR('1', &compression_level, N_("compress faster"), 1),
		OPT__COMPR_HIDDEN('2', &compression_level, 2),
		OPT__COMPR_HIDDEN('3', &compression_level, 3),
		OPT__COMPR_HIDDEN('4', &compression_level, 4),
		OPT__COMPR_HIDDEN('5', &compression_level, 5),
		OPT__COMPR_HIDDEN('6', &compression_level, 6),
		OPT__COMPR_HIDDEN('7', &compression_level, 7),
		OPT__COMPR_HIDDEN('8', &compression_level, 8),
		OPT__COMPR('9', &compression_level, N_("compress better"), 9),
		OPT_GROUP(""),
		OPT_BOOL('l', "list", &list,
			N_("list supported archive formats")),
		OPT_GROUP(""),
		OPT_STRING(0, "remote", &remote, N_("repo"),
			N_("retrieve the archive from remote repository <repo>")),
		OPT_STRING(0, "exec", &exec, N_("command"),
			N_("path to the remote git-upload-archive command")),
		OPT_END()
	};

	argc = parse_options(argc, argv, NULL, opts, archive_usage, 0);

	if (remote)
		die("Unexpected option --remote");
	if (exec)
		die("Option --exec can only be used together with --remote");
	if (output)
		die("Unexpected option --output");

	if (!base)
		base = "";

	if (list) {
		for (i = 0; i < nr_archivers; i++)
			if (!is_remote || archivers[i]->flags & ARCHIVER_REMOTE)
				printf("%s\n", archivers[i]->name);
		exit(0);
	}

	if (!format && name_hint)
		format = archive_format_from_filename(name_hint);
	if (!format)
		format = "tar";

	/* We need at least one parameter -- tree-ish */
	if (argc < 1)
		usage_with_options(archive_usage, opts);
	*ar = lookup_archiver(format);
	if (!*ar || (is_remote && !((*ar)->flags & ARCHIVER_REMOTE)))
		die("Unknown archive format '%s'", format);

	args->compression_level = Z_DEFAULT_COMPRESSION;
	if (compression_level != -1) {
		if ((*ar)->flags & ARCHIVER_WANT_COMPRESSION_LEVELS)
			args->compression_level = compression_level;
		else {
			die("Argument not supported for format '%s': -%d",
					format, compression_level);
		}
	}
	args->verbose = verbose;
	args->base = base;
	args->baselen = strlen(base);
	args->worktree_attributes = worktree_attributes;

	return argc;
}
Esempio n. 10
0
int cmd_describe(int argc, const char **argv, const char *prefix)
{
    int contains = 0;
    struct option options[] = {
        OPT_BOOLEAN(0, "contains",   &contains, N_("find the tag that comes after the commit")),
        OPT_BOOLEAN(0, "debug",      &debug, N_("debug search strategy on stderr")),
        OPT_BOOLEAN(0, "all",        &all, N_("use any ref")),
        OPT_BOOLEAN(0, "tags",       &tags, N_("use any tag, even unannotated")),
        OPT_BOOLEAN(0, "long",       &longformat, N_("always use long format")),
        OPT_BOOLEAN(0, "first-parent", &first_parent, N_("only follow first parent")),
        OPT__ABBREV(&abbrev),
        OPT_SET_INT(0, "exact-match", &max_candidates,
        N_("only output exact matches"), 0),
        OPT_INTEGER(0, "candidates", &max_candidates,
        N_("consider <n> most recent tags (default: 10)")),
        OPT_STRING(0, "match",       &pattern, N_("pattern"),
        N_("only consider tags matching <pattern>")),
        OPT_BOOLEAN(0, "always",     &always,
        N_("show abbreviated commit object as fallback")),
        {   OPTION_STRING, 0, "dirty",  &dirty, N_("mark"),
            N_("append <mark> on dirty working tree (default: \"-dirty\")"),
            PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"
        },
        OPT_END(),
    };

    git_config(git_default_config, NULL);
    argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
    if (abbrev < 0)
        abbrev = DEFAULT_ABBREV;

    if (max_candidates < 0)
        max_candidates = 0;
    else if (max_candidates > MAX_TAGS)
        max_candidates = MAX_TAGS;

    save_commit_buffer = 0;

    if (longformat && abbrev == 0)
        die(_("--long is incompatible with --abbrev=0"));

    if (contains) {
        struct argv_array args;

        argv_array_init(&args);
        argv_array_pushl(&args, "name-rev",
                         "--peel-tag", "--name-only", "--no-undefined",
                         NULL);
        if (always)
            argv_array_push(&args, "--always");
        if (!all) {
            argv_array_push(&args, "--tags");
            if (pattern)
                argv_array_pushf(&args, "--refs=refs/tags/%s", pattern);
        }
        while (*argv) {
            argv_array_push(&args, *argv);
            argv++;
        }
        return cmd_name_rev(args.argc, args.argv, prefix);
    }

    init_hash(&names);
    for_each_rawref(get_name, NULL);
    if (!names.nr && !always)
        die(_("No names found, cannot describe anything."));

    if (argc == 0) {
        if (dirty) {
            static struct lock_file index_lock;
            int fd;

            read_cache_preload(NULL);
            refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
                          NULL, NULL, NULL);
            fd = hold_locked_index(&index_lock, 0);
            if (0 <= fd)
                update_index_if_able(&the_index, &index_lock);

            if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
                                diff_index_args, prefix))
                dirty = NULL;
        }
        describe("HEAD", 1);
    } else if (dirty) {
        die(_("--dirty is incompatible with committishes"));
    } else {
        while (argc-- > 0) {
            describe(*argv++, argc == 0);
        }
    }
    return 0;
}
Esempio n. 11
0
int cmd_reset(int argc, const char **argv, const char *prefix)
{
	int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;
	int patch_mode = 0;
	const char *rev = "HEAD";
	unsigned char sha1[20], *orig = NULL, sha1_orig[20],
				*old_orig = NULL, sha1_old_orig[20];
	struct commit *commit;
	char *reflog_action, msg[1024];
	const struct option options[] = {
		OPT__QUIET(&quiet),
		OPT_SET_INT(0, "mixed", &reset_type,
						"reset HEAD and index", MIXED),
		OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
		OPT_SET_INT(0, "hard", &reset_type,
				"reset HEAD, index and working tree", HARD),
		OPT_SET_INT(0, "merge", &reset_type,
				"reset HEAD, index and working tree", MERGE),
		OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
		OPT_END()
	};

	git_config(git_default_config, NULL);

	argc = parse_options(argc, argv, prefix, options, git_reset_usage,
						PARSE_OPT_KEEP_DASHDASH);
	reflog_action = args_to_str(argv);
	setenv("GIT_REFLOG_ACTION", reflog_action, 0);

	/*
	 * Possible arguments are:
	 *
	 * git reset [-opts] <rev> <paths>...
	 * git reset [-opts] <rev> -- <paths>...
	 * git reset [-opts] -- <paths>...
	 * git reset [-opts] <paths>...
	 *
	 * At this point, argv[i] points immediately after [-opts].
	 */

	if (i < argc) {
		if (!strcmp(argv[i], "--")) {
			i++; /* reset to HEAD, possibly with paths */
		} else if (i + 1 < argc && !strcmp(argv[i+1], "--")) {
			rev = argv[i];
			i += 2;
		}
		/*
		 * Otherwise, argv[i] could be either <rev> or <paths> and
		 * has to be unambiguous.
		 */
		else if (!get_sha1(argv[i], sha1)) {
			/*
			 * Ok, argv[i] looks like a rev; it should not
			 * be a filename.
			 */
			verify_non_filename(prefix, argv[i]);
			rev = argv[i++];
		} else {
			/* Otherwise we treat this as a filename */
			verify_filename(prefix, argv[i]);
		}
	}

	if (get_sha1(rev, sha1))
		die("Failed to resolve '%s' as a valid ref.", rev);

	commit = lookup_commit_reference(sha1);
	if (!commit)
		die("Could not parse object '%s'.", rev);
	hashcpy(sha1, commit->object.sha1);

	if (patch_mode) {
		if (reset_type != NONE)
			die("--patch is incompatible with --{hard,mixed,soft}");
		return interactive_reset(rev, argv + i, prefix);
	}

	/* git reset tree [--] paths... can be used to
	 * load chosen paths from the tree into the index without
	 * affecting the working tree nor HEAD. */
	if (i < argc) {
		if (reset_type == MIXED)
			warning("--mixed option is deprecated with paths.");
		else if (reset_type != NONE)
			die("Cannot do %s reset with paths.",
					reset_type_names[reset_type]);
		return read_from_tree(prefix, argv + i, sha1,
				quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
	}
	if (reset_type == NONE)
		reset_type = MIXED; /* by default */

	if (reset_type == HARD || reset_type == MERGE)
		setup_work_tree();

	if (reset_type == MIXED && is_bare_repository())
		die("%s reset is not allowed in a bare repository",
		    reset_type_names[reset_type]);

	/* Soft reset does not touch the index file nor the working tree
	 * at all, but requires them in a good order.  Other resets reset
	 * the index file to the tree object we are switching to. */
	if (reset_type == SOFT) {
		if (is_merge() || read_cache() < 0 || unmerged_cache())
			die("Cannot do a soft reset in the middle of a merge.");
	}
	else if (reset_index_file(sha1, reset_type, quiet))
		die("Could not reset index file to revision '%s'.", rev);

	/* Any resets update HEAD to the head being switched to,
	 * saving the previous head in ORIG_HEAD before. */
	if (!get_sha1("ORIG_HEAD", sha1_old_orig))
		old_orig = sha1_old_orig;
	if (!get_sha1("HEAD", sha1_orig)) {
		orig = sha1_orig;
		prepend_reflog_action("updating ORIG_HEAD", msg, sizeof(msg));
		update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
	}
	else if (old_orig)
		delete_ref("ORIG_HEAD", old_orig, 0);
	prepend_reflog_action("updating HEAD", msg, sizeof(msg));
	update_ref_status = update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);

	switch (reset_type) {
	case HARD:
		if (!update_ref_status && !quiet)
			print_new_head_line(commit);
		break;
	case SOFT: /* Nothing else to do. */
		break;
	case MIXED: /* Report what has not been updated. */
		update_index_refresh(0, NULL,
				quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
		break;
	}

	remove_branch_state();

	free(reflog_action);

	return update_ref_status;
}
Esempio n. 12
0
static int module_clone(int argc, const char **argv, const char *prefix)
{
	const char *name = NULL, *url = NULL;
	const char *reference = NULL, *depth = NULL;
	int quiet = 0;
	FILE *submodule_dot_git;
	char *p, *path = NULL, *sm_gitdir;
	struct strbuf rel_path = STRBUF_INIT;
	struct strbuf sb = STRBUF_INIT;

	struct option module_clone_options[] = {
		OPT_STRING(0, "prefix", &prefix,
			   N_("path"),
			   N_("alternative anchor for relative paths")),
		OPT_STRING(0, "path", &path,
			   N_("path"),
			   N_("where the new submodule will be cloned to")),
		OPT_STRING(0, "name", &name,
			   N_("string"),
			   N_("name of the new submodule")),
		OPT_STRING(0, "url", &url,
			   N_("string"),
			   N_("url where to clone the submodule from")),
		OPT_STRING(0, "reference", &reference,
			   N_("string"),
			   N_("reference repository")),
		OPT_STRING(0, "depth", &depth,
			   N_("string"),
			   N_("depth for shallow clones")),
		OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
		OPT_END()
	};

	const char *const git_submodule_helper_usage[] = {
		N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
		   "[--reference <repository>] [--name <name>] [--depth <depth>] "
		   "--url <url> --path <path>"),
		NULL
	};

	argc = parse_options(argc, argv, prefix, module_clone_options,
			     git_submodule_helper_usage, 0);

	if (argc || !url || !path || !*path)
		usage_with_options(git_submodule_helper_usage,
				   module_clone_options);

	strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
	sm_gitdir = xstrdup(absolute_path(sb.buf));
	strbuf_reset(&sb);

	if (!is_absolute_path(path)) {
		strbuf_addf(&sb, "%s/%s", get_git_work_tree(), path);
		path = strbuf_detach(&sb, NULL);
	} else
		path = xstrdup(path);

	if (!file_exists(sm_gitdir)) {
		if (safe_create_leading_directories_const(sm_gitdir) < 0)
			die(_("could not create directory '%s'"), sm_gitdir);
		if (clone_submodule(path, sm_gitdir, url, depth, reference, quiet))
			die(_("clone of '%s' into submodule path '%s' failed"),
			    url, path);
	} else {
		if (safe_create_leading_directories_const(path) < 0)
			die(_("could not create directory '%s'"), path);
		strbuf_addf(&sb, "%s/index", sm_gitdir);
		unlink_or_warn(sb.buf);
		strbuf_reset(&sb);
	}

	/* Write a .git file in the submodule to redirect to the superproject. */
	strbuf_addf(&sb, "%s/.git", path);
	if (safe_create_leading_directories_const(sb.buf) < 0)
		die(_("could not create leading directories of '%s'"), sb.buf);
	submodule_dot_git = fopen(sb.buf, "w");
	if (!submodule_dot_git)
		die_errno(_("cannot open file '%s'"), sb.buf);

	fprintf_or_die(submodule_dot_git, "gitdir: %s\n",
		       relative_path(sm_gitdir, path, &rel_path));
	if (fclose(submodule_dot_git))
		die(_("could not close file %s"), sb.buf);
	strbuf_reset(&sb);
	strbuf_reset(&rel_path);

	/* Redirect the worktree of the submodule in the superproject's config */
	p = git_pathdup_submodule(path, "config");
	if (!p)
		die(_("could not get submodule directory for '%s'"), path);
	git_config_set_in_file(p, "core.worktree",
			       relative_path(path, sm_gitdir, &rel_path));
	strbuf_release(&sb);
	strbuf_release(&rel_path);
	free(sm_gitdir);
	free(path);
	free(p);
	return 0;
}
Esempio n. 13
0
int cmd_update_index(int argc, const char **argv, const char *prefix)
{
	int newfd, entries, has_errors = 0, nul_term_line = 0;
	enum uc_mode untracked_cache = UC_UNSPECIFIED;
	int read_from_stdin = 0;
	int prefix_length = prefix ? strlen(prefix) : 0;
	int preferred_index_format = 0;
	char set_executable_bit = 0;
	struct refresh_params refresh_args = {0, &has_errors};
	int lock_error = 0;
	int split_index = -1;
	int force_write = 0;
	int fsmonitor = -1;
	struct lock_file lock_file = LOCK_INIT;
	struct parse_opt_ctx_t ctx;
	strbuf_getline_fn getline_fn;
	int parseopt_state = PARSE_OPT_UNKNOWN;
	struct option options[] = {
		OPT_BIT('q', NULL, &refresh_args.flags,
			N_("continue refresh even when index needs update"),
			REFRESH_QUIET),
		OPT_BIT(0, "ignore-submodules", &refresh_args.flags,
			N_("refresh: ignore submodules"),
			REFRESH_IGNORE_SUBMODULES),
		OPT_SET_INT(0, "add", &allow_add,
			N_("do not ignore new files"), 1),
		OPT_SET_INT(0, "replace", &allow_replace,
			N_("let files replace directories and vice-versa"), 1),
		OPT_SET_INT(0, "remove", &allow_remove,
			N_("notice files missing from worktree"), 1),
		OPT_BIT(0, "unmerged", &refresh_args.flags,
			N_("refresh even if index contains unmerged entries"),
			REFRESH_UNMERGED),
		{OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL,
			N_("refresh stat information"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
			refresh_callback},
		{OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL,
			N_("like --refresh, but ignore assume-unchanged setting"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
			really_refresh_callback},
		{OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL,
			N_("<mode>,<object>,<path>"),
			N_("add the specified entry to the index"),
			PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
			PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
			(parse_opt_cb *) cacheinfo_callback},
		{OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x",
			N_("override the executable bit of the listed files"),
			PARSE_OPT_NONEG,
			chmod_callback},
		{OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL,
			N_("mark files as \"not changing\""),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
		{OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL,
			N_("clear assumed-unchanged bit"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
		{OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL,
			N_("mark files as \"index-only\""),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
		{OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL,
			N_("clear skip-worktree bit"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
		OPT_SET_INT(0, "info-only", &info_only,
			N_("add to index only; do not add content to object database"), 1),
		OPT_SET_INT(0, "force-remove", &force_remove,
			N_("remove named paths even if present in worktree"), 1),
		OPT_BOOL('z', NULL, &nul_term_line,
			 N_("with --stdin: input lines are terminated by null bytes")),
		{OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL,
			N_("read list of paths to be updated from standard input"),
			PARSE_OPT_NONEG | PARSE_OPT_NOARG,
			(parse_opt_cb *) stdin_callback},
		{OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL,
			N_("add entries from standard input to the index"),
			PARSE_OPT_NONEG | PARSE_OPT_NOARG,
			(parse_opt_cb *) stdin_cacheinfo_callback},
		{OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL,
			N_("repopulate stages #2 and #3 for the listed paths"),
			PARSE_OPT_NONEG | PARSE_OPT_NOARG,
			(parse_opt_cb *) unresolve_callback},
		{OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL,
			N_("only update entries that differ from HEAD"),
			PARSE_OPT_NONEG | PARSE_OPT_NOARG,
			(parse_opt_cb *) reupdate_callback},
		OPT_BIT(0, "ignore-missing", &refresh_args.flags,
			N_("ignore files missing from worktree"),
			REFRESH_IGNORE_MISSING),
		OPT_SET_INT(0, "verbose", &verbose,
			N_("report actions to standard output"), 1),
		{OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL,
			N_("(for porcelains) forget saved unresolved conflicts"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
			resolve_undo_clear_callback},
		OPT_INTEGER(0, "index-version", &preferred_index_format,
			N_("write index in this format")),
		OPT_BOOL(0, "split-index", &split_index,
			N_("enable or disable split index")),
		OPT_BOOL(0, "untracked-cache", &untracked_cache,
			N_("enable/disable untracked cache")),
		OPT_SET_INT(0, "test-untracked-cache", &untracked_cache,
			    N_("test if the filesystem supports untracked cache"), UC_TEST),
		OPT_SET_INT(0, "force-untracked-cache", &untracked_cache,
			    N_("enable untracked cache without testing the filesystem"), UC_FORCE),
		OPT_SET_INT(0, "force-write-index", &force_write,
			N_("write out the index even if is not flagged as changed"), 1),
		OPT_BOOL(0, "fsmonitor", &fsmonitor,
			N_("enable or disable file system monitor")),
		{OPTION_SET_INT, 0, "fsmonitor-valid", &mark_fsmonitor_only, NULL,
			N_("mark files as fsmonitor valid"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
		{OPTION_SET_INT, 0, "no-fsmonitor-valid", &mark_fsmonitor_only, NULL,
			N_("clear fsmonitor valid bit"),
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
		OPT_END()
	};

	if (argc == 2 && !strcmp(argv[1], "-h"))
		usage_with_options(update_index_usage, options);

	git_config(git_default_config, NULL);

	/* we will diagnose later if it turns out that we need to update it */
	newfd = hold_locked_index(&lock_file, 0);
	if (newfd < 0)
		lock_error = errno;

	entries = read_cache();
	if (entries < 0)
		die("cache corrupted");

	/*
	 * Custom copy of parse_options() because we want to handle
	 * filename arguments as they come.
	 */
	parse_options_start(&ctx, argc, argv, prefix,
			    options, PARSE_OPT_STOP_AT_NON_OPTION);
	while (ctx.argc) {
		if (parseopt_state != PARSE_OPT_DONE)
			parseopt_state = parse_options_step(&ctx, options,
							    update_index_usage);
		if (!ctx.argc)
			break;
		switch (parseopt_state) {
		case PARSE_OPT_HELP:
		case PARSE_OPT_ERROR:
			exit(129);
		case PARSE_OPT_NON_OPTION:
		case PARSE_OPT_DONE:
		{
			const char *path = ctx.argv[0];
			char *p;

			setup_work_tree();
			p = prefix_path(prefix, prefix_length, path);
			update_one(p);
			if (set_executable_bit)
				chmod_path(set_executable_bit, p);
			free(p);
			ctx.argc--;
			ctx.argv++;
			break;
		}
		case PARSE_OPT_UNKNOWN:
			if (ctx.argv[0][1] == '-')
				error("unknown option '%s'", ctx.argv[0] + 2);
			else
				error("unknown switch '%c'", *ctx.opt);
			usage_with_options(update_index_usage, options);
		}
	}
	argc = parse_options_end(&ctx);

	getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
	if (preferred_index_format) {
		if (preferred_index_format < INDEX_FORMAT_LB ||
		    INDEX_FORMAT_UB < preferred_index_format)
			die("index-version %d not in range: %d..%d",
			    preferred_index_format,
			    INDEX_FORMAT_LB, INDEX_FORMAT_UB);

		if (the_index.version != preferred_index_format)
			active_cache_changed |= SOMETHING_CHANGED;
		the_index.version = preferred_index_format;
	}

	if (read_from_stdin) {
		struct strbuf buf = STRBUF_INIT;
		struct strbuf unquoted = STRBUF_INIT;

		setup_work_tree();
		while (getline_fn(&buf, stdin) != EOF) {
			char *p;
			if (!nul_term_line && buf.buf[0] == '"') {
				strbuf_reset(&unquoted);
				if (unquote_c_style(&unquoted, buf.buf, NULL))
					die("line is badly quoted");
				strbuf_swap(&buf, &unquoted);
			}
			p = prefix_path(prefix, prefix_length, buf.buf);
			update_one(p);
			if (set_executable_bit)
				chmod_path(set_executable_bit, p);
			free(p);
		}
		strbuf_release(&unquoted);
		strbuf_release(&buf);
	}

	if (split_index > 0) {
		if (git_config_get_split_index() == 0)
			warning(_("core.splitIndex is set to false; "
				  "remove or change it, if you really want to "
				  "enable split index"));
		if (the_index.split_index)
			the_index.cache_changed |= SPLIT_INDEX_ORDERED;
		else
			add_split_index(&the_index);
	} else if (!split_index) {
		if (git_config_get_split_index() == 1)
			warning(_("core.splitIndex is set to true; "
				  "remove or change it, if you really want to "
				  "disable split index"));
		remove_split_index(&the_index);
	}

	switch (untracked_cache) {
	case UC_UNSPECIFIED:
		break;
	case UC_DISABLE:
		if (git_config_get_untracked_cache() == 1)
			warning(_("core.untrackedCache is set to true; "
				  "remove or change it, if you really want to "
				  "disable the untracked cache"));
		remove_untracked_cache(&the_index);
		report(_("Untracked cache disabled"));
		break;
	case UC_TEST:
		setup_work_tree();
		return !test_if_untracked_cache_is_supported();
	case UC_ENABLE:
	case UC_FORCE:
		if (git_config_get_untracked_cache() == 0)
			warning(_("core.untrackedCache is set to false; "
				  "remove or change it, if you really want to "
				  "enable the untracked cache"));
		add_untracked_cache(&the_index);
		report(_("Untracked cache enabled for '%s'"), get_git_work_tree());
		break;
	default:
		BUG("bad untracked_cache value: %d", untracked_cache);
	}

	if (fsmonitor > 0) {
		if (git_config_get_fsmonitor() == 0)
			warning(_("core.fsmonitor is unset; "
				"set it if you really want to "
				"enable fsmonitor"));
		add_fsmonitor(&the_index);
		report(_("fsmonitor enabled"));
	} else if (!fsmonitor) {
		if (git_config_get_fsmonitor() == 1)
			warning(_("core.fsmonitor is set; "
				"remove it if you really want to "
				"disable fsmonitor"));
		remove_fsmonitor(&the_index);
		report(_("fsmonitor disabled"));
	}

	if (active_cache_changed || force_write) {
		if (newfd < 0) {
			if (refresh_args.flags & REFRESH_QUIET)
				exit(128);
			unable_to_lock_die(get_index_file(), lock_error);
		}
		if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
			die("Unable to write new index file");
	}

	rollback_lock_file(&lock_file);

	return has_errors ? 1 : 0;
}
Esempio n. 14
0
int cmd_status(int argc, const char **argv, const char *prefix)
{
	struct wt_status s;
	unsigned char sha1[20];
	static struct option builtin_status_options[] = {
		OPT__VERBOSE(&verbose),
		OPT_SET_INT('s', "short", &status_format,
			    "show status concisely", STATUS_FORMAT_SHORT),
		OPT_SET_INT(0, "porcelain", &status_format,
			    "show porcelain output format",
			    STATUS_FORMAT_PORCELAIN),
		OPT_BOOLEAN('z', "null", &null_termination,
			    "terminate entries with NUL"),
		{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
		  "mode",
		  "show untracked files, optional modes: all, normal, no. (Default: all)",
		  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
		OPT_END(),
	};

	if (null_termination && status_format == STATUS_FORMAT_LONG)
		status_format = STATUS_FORMAT_PORCELAIN;

	wt_status_prepare(&s);
	git_config(git_status_config, &s);
	in_merge = file_exists(git_path("MERGE_HEAD"));
	argc = parse_options(argc, argv, prefix,
			     builtin_status_options,
			     builtin_status_usage, 0);
	handle_untracked_files_arg(&s);

	if (*argv)
		s.pathspec = get_pathspec(prefix, argv);

	read_cache_preload(s.pathspec);
	refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
	s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
	s.in_merge = in_merge;
	wt_status_collect(&s);

	if (s.relative_paths)
		s.prefix = prefix;
	if (s.use_color == -1)
		s.use_color = git_use_color_default;
	if (diff_use_color_default == -1)
		diff_use_color_default = git_use_color_default;

	switch (status_format) {
	case STATUS_FORMAT_SHORT:
		wt_shortstatus_print(&s, null_termination);
		break;
	case STATUS_FORMAT_PORCELAIN:
		wt_porcelain_print(&s, null_termination);
		break;
	case STATUS_FORMAT_LONG:
		s.verbose = verbose;
		wt_status_print(&s);
		break;
	}
	return 0;
}
Esempio n. 15
0
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;

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

	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. 16
0
File: gc.c Progetto: oleganza/git
int cmd_gc(int argc, const char **argv, const char *prefix)
{
	int aggressive = 0;
	int auto_gc = 0;
	int quiet = 0;
	int progress_flag = 0;
	
	struct option builtin_gc_options[] = {
		OPT__QUIET(&quiet, N_("suppress progress reporting")),
		{ OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
			N_("prune unreferenced objects"),
			PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
		OPT_BOOLEAN(0, "progress", &progress_flag, "force progress reporting"),
		OPT_BOOLEAN(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
		OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")),
		OPT_END()
	};

	if (argc == 2 && !strcmp(argv[1], "-h"))
		usage_with_options(builtin_gc_usage, builtin_gc_options);

	argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
	argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL);
	argv_array_pushl(&repack, "repack", "-d", "-l", NULL);
	argv_array_pushl(&prune, "prune", "--expire", NULL );
	argv_array_pushl(&rerere, "rerere", "gc", NULL);

	git_config(gc_config, NULL);

	if (pack_refs < 0)
		pack_refs = !is_bare_repository();

	argc = parse_options(argc, argv, prefix, builtin_gc_options,
			     builtin_gc_usage, 0);
	if (argc > 0)
		usage_with_options(builtin_gc_usage, builtin_gc_options);

	if (aggressive) {
		argv_array_push(&repack, "-f");
		argv_array_push(&repack, "--depth=250");
		if (aggressive_window > 0)
			argv_array_pushf(&repack, "--window=%d", aggressive_window);
	}
	if (quiet)
		argv_array_push(&repack, "-q");

	if (progress_flag)
		argv_array_push(&repack, "--progress");

	if (auto_gc) {
		/*
		 * Auto-gc should be least intrusive as possible.
		 */
		if (!need_to_gc())
			return 0;
		if (!quiet)
			fprintf(stderr,
					_("Auto packing the repository for optimum performance. You may also\n"
					"run \"git gc\" manually. See "
					"\"git help gc\" for more information.\n"));
	} else
		add_repack_all_option();

	if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
		return error(FAILED_RUN, pack_refs_cmd.argv[0]);

	if (run_command_v_opt(reflog.argv, RUN_GIT_CMD))
		return error(FAILED_RUN, reflog.argv[0]);

	if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
		return error(FAILED_RUN, repack.argv[0]);

	if (prune_expire) {
		argv_array_push(&prune, prune_expire);
		if (quiet)
			argv_array_push(&prune, "--no-progress");
		if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
			return error(FAILED_RUN, prune.argv[0]);
	}

	if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
		return error(FAILED_RUN, rerere.argv[0]);

	if (auto_gc && too_many_loose_objects())
		warning(_("There are too many unreachable loose objects; "
			"run 'git prune' to remove them."));

	return 0;
}
Esempio n. 17
0
int cmd_gc(int argc, const char **argv, const char *prefix)
{
	int aggressive = 0;
	int auto_gc = 0;
	int quiet = 0;
	char buf[80];

	struct option builtin_gc_options[] = {
		{ OPTION_STRING, 0, "prune", &prune_expire, "date",
			"prune unreferenced objects",
			PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
		OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
		OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
		OPT_BOOLEAN('q', "quiet", &quiet, "suppress progress reports"),
		OPT_END()
	};

	git_config(gc_config, NULL);

	if (pack_refs < 0)
		pack_refs = !is_bare_repository();

	argc = parse_options(argc, argv, prefix, builtin_gc_options,
			     builtin_gc_usage, 0);
	if (argc > 0)
		usage_with_options(builtin_gc_usage, builtin_gc_options);

	if (aggressive) {
		append_option(argv_repack, "-f", MAX_ADD);
		append_option(argv_repack, "--depth=250", MAX_ADD);
		if (aggressive_window > 0) {
			sprintf(buf, "--window=%d", aggressive_window);
			append_option(argv_repack, buf, MAX_ADD);
		}
	}
	if (quiet)
		append_option(argv_repack, "-q", MAX_ADD);

	if (auto_gc) {
		/*
		 * Auto-gc should be least intrusive as possible.
		 */
		if (!need_to_gc())
			return 0;
		fprintf(stderr,
			"Auto packing the repository for optimum performance.%s\n",
			quiet
			? ""
			: (" You may also\n"
			   "run \"git gc\" manually. See "
			   "\"git help gc\" for more information."));
	} else
		append_option(argv_repack,
			      prune_expire && !strcmp(prune_expire, "now")
			      ? "-a" : "-A",
			      MAX_ADD);

	if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
		return error(FAILED_RUN, argv_pack_refs[0]);

	if (run_command_v_opt(argv_reflog, RUN_GIT_CMD))
		return error(FAILED_RUN, argv_reflog[0]);

	if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
		return error(FAILED_RUN, argv_repack[0]);

	if (prune_expire) {
		argv_prune[2] = prune_expire;
		if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
			return error(FAILED_RUN, argv_prune[0]);
	}

	if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
		return error(FAILED_RUN, argv_rerere[0]);

	if (auto_gc && too_many_loose_objects())
		warning("There are too many unreachable loose objects; "
			"run 'git prune' to remove them.");

	return 0;
}
Esempio n. 18
0
int cmd_name_rev(int argc, const char **argv, const char *prefix)
{
	struct object_array revs = OBJECT_ARRAY_INIT;
	int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
	struct name_ref_data data = { 0, 0, NULL };
	struct option opts[] = {
		OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
		OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
				   N_("only use refs matching <pattern>")),
		OPT_GROUP(""),
		OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
		OPT_BOOL(0, "stdin", &transform_stdin, N_("read from stdin")),
		OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
		OPT_BOOL(0, "always",     &always,
			   N_("show abbreviated commit object as fallback")),
		{
			/* A Hidden OPT_BOOL */
			OPTION_SET_INT, 0, "peel-tag", &peel_tag, NULL,
			N_("dereference tags in the input (internal use)"),
			PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1,
		},
		OPT_END(),
	};

	git_config(git_default_config, NULL);
	argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
	if (all + transform_stdin + !!argc > 1) {
		error("Specify either a list, or --all, not both!");
		usage_with_options(name_rev_usage, opts);
	}
	if (all || transform_stdin)
		cutoff = 0;

	for (; argc; argc--, argv++) {
		unsigned char sha1[20];
		struct object *object;
		struct commit *commit;

		if (get_sha1(*argv, sha1)) {
			fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
					*argv);
			continue;
		}

		commit = NULL;
		object = parse_object(sha1);
		if (object) {
			struct object *peeled = deref_tag(object, *argv, 0);
			if (peeled && peeled->type == OBJ_COMMIT)
				commit = (struct commit *)peeled;
		}

		if (!object) {
			fprintf(stderr, "Could not get object for %s. Skipping.\n",
					*argv);
			continue;
		}

		if (commit) {
			if (cutoff > commit->date)
				cutoff = commit->date;
		}

		if (peel_tag) {
			if (!commit) {
				fprintf(stderr, "Could not get commit for %s. Skipping.\n",
					*argv);
				continue;
			}
			object = (struct object *)commit;
		}
		add_object_array(object, *argv, &revs);
	}

	if (cutoff)
		cutoff = cutoff - CUTOFF_DATE_SLOP;
	for_each_ref(name_ref, &data);

	if (transform_stdin) {
		char buffer[2048];

		while (!feof(stdin)) {
			char *p = fgets(buffer, sizeof(buffer), stdin);
			if (!p)
				break;
			name_rev_line(p, &data);
		}
	} else if (all) {
		int i, max;

		max = get_max_object_index();
		for (i = 0; i < max; i++) {
			struct object *obj = get_indexed_object(i);
			if (!obj || obj->type != OBJ_COMMIT)
				continue;
			show_name(obj, NULL,
				  always, allow_undefined, data.name_only);
		}
	} else {
		int i;
		for (i = 0; i < revs.nr; i++)
			show_name(revs.objects[i].item, revs.objects[i].name,
				  always, allow_undefined, data.name_only);
	}

	return 0;
}
Esempio n. 19
0
int main(int argc, char **argv)
{
    int expert_mode = 0;

    const char *prgname = "abrt";
    abrt_init(argv);

    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    /* without this the name is set to argv[0] which confuses
     * desktops which uses the name to find the corresponding .desktop file
     * trac#180
     *
     * env variable can be used to override the default prgname, so it's the
     * same as the application which is calling us (trac#303)
     *
     * note that g_set_prgname has to be called before gtk_init
     */
    char *env_prgname = getenv("LIBREPORT_PRGNAME");
    g_set_prgname(env_prgname ? env_prgname : prgname);

    gtk_init(&argc, &argv);

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [-vpdx] [-e EVENT]... [-g GUI_FILE] PROBLEM_DIR\n"
        "\n"
        "GUI tool to analyze and report problem saved in specified PROBLEM_DIR"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_g = 1 << 1,
        OPT_p = 1 << 2,
        OPT_d = 1 << 3,
        OPT_e = 1 << 4,
        OPT_x = 1 << 5,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('g', NULL, &g_glade_file, "FILE",          _("Alternate GUI file")),
        OPT_BOOL(  'p', NULL, NULL,                           _("Add program names to log")),
        OPT_BOOL(  'd', "delete", NULL,                       _("Remove PROBLEM_DIR after reporting")),
        OPT_LIST(  'e', "event", &g_auto_event_list, "EVENT", _("Run only these events")),
        OPT_BOOL(  'x', "expert", &expert_mode,               _("Expert mode")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
    argv += optind;
    if (!argv[0] || argv[1]) /* zero or >1 arguments */
        show_usage_and_die(program_usage_string, program_options);

    /* Allow algorithms to add mallocated strings */
    for (GList *elem = g_auto_event_list; elem; elem = g_list_next(elem))
        elem->data = xstrdup((const char *)elem->data);

    export_abrt_envvars(opts & OPT_p);

    g_dump_dir_name = xstrdup(argv[0]);

    /* load /etc/abrt/events/foo.{conf,xml} stuff
       and $XDG_CACHE_HOME/abrt/events/foo.conf */
    g_event_config_list = load_event_config_data();
    load_event_config_data_from_user_storage(g_event_config_list);
    load_user_settings("report-gtk");

    load_workflow_config_data(WORKFLOWS_DIR);

    /* list of workflows applicable to the currently processed problem */
    GList *possible_names = list_possible_events_glist(g_dump_dir_name, "workflow");
    GHashTable *possible_workflows = load_workflow_config_data_from_list(possible_names, WORKFLOWS_DIR);
    g_list_free_full(possible_names, free);

    /* if we have only 1 workflow, we can use the events from it as default */
    if (!expert_mode && g_auto_event_list == NULL && g_hash_table_size(possible_workflows) == 1)
    {
        GHashTableIter iter;
        gpointer key, value;

        g_hash_table_iter_init(&iter, possible_workflows);
        if (g_hash_table_iter_next(&iter, &key, &value))
        {
            log_notice("autoselected workflow: '%s'", (char *)key);
            g_auto_event_list = wf_get_event_names((workflow_t *)value);
        }
    }
    g_hash_table_destroy(possible_workflows);

    problem_data_reload_from_dump_dir();

    g_custom_logger = &show_error_as_msgbox;
    GtkApplication *app = gtk_application_new("org.freedesktop.libreport.report", G_APPLICATION_NON_UNIQUE);
    g_signal_connect(app, "activate", G_CALLBACK(activate_wizard), (gpointer)&expert_mode);
    g_signal_connect(app, "startup",  G_CALLBACK(startup_wizard),  NULL);
    /* Enter main loop */
    g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    if (opts & OPT_d)
        delete_dump_dir_possibly_using_abrtd(g_dump_dir_name);

    save_user_settings();

    return 0;
}
Esempio n. 20
0
int cmd_prune(int argc, const char **argv, const char *prefix)
{
	struct rev_info revs;
	struct progress *progress = NULL;
	int prune_repos = 0;
	const struct option options[] = {
		OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
		OPT__VERBOSE(&verbose, N_("report pruned objects")),
		OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
		OPT_BOOL(0, "repos", &prune_repos, N_("prune .git/repos/")),
		OPT_EXPIRY_DATE(0, "expire", &expire,
				N_("expire objects older than <time>")),
		OPT_END()
	};
	char *s;

	expire = ULONG_MAX;
	save_commit_buffer = 0;
	check_replace_refs = 0;
	init_revisions(&revs, prefix);

	argc = parse_options(argc, argv, prefix, options, prune_usage, 0);

	if (prune_repos) {
		if (argc)
			die(_("--repos does not take extra arguments"));
		prune_repos_dir();
		return 0;
	}

	while (argc--) {
		unsigned char sha1[20];
		const char *name = *argv++;

		if (!get_sha1(name, sha1)) {
			struct object *object = parse_object_or_die(sha1, name);
			add_pending_object(&revs, object, "");
		}
		else
			die("unrecognized argument: %s", name);
	}

	if (show_progress == -1)
		show_progress = isatty(2);
	if (show_progress)
		progress = start_progress_delay(_("Checking connectivity"), 0, 0, 2);

	mark_reachable_objects(&revs, 1, progress);
	stop_progress(&progress);
	prune_object_dir(get_object_directory());

	prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);
	remove_temporary_files(get_object_directory());
	s = mkpathdup("%s/pack", get_object_directory());
	remove_temporary_files(s);
	free(s);

	if (is_repository_shallow())
		prune_shallow(show_only);

	return 0;
}
Esempio n. 21
0
int cmd_checkout_index(int argc, const char **argv, const char *prefix)
{
	int i;
	int newfd = -1;
	int all = 0;
	int read_from_stdin = 0;
	int prefix_length;
	int force = 0, quiet = 0, not_new = 0;
	struct option builtin_checkout_index_options[] = {
		OPT_BOOLEAN('a', "all", &all,
			"checks out all files in the index"),
		OPT__FORCE(&force, "forces overwrite of existing files"),
		OPT__QUIET(&quiet,
			"no warning for existing files and files not in index"),
		OPT_BOOLEAN('n', "no-create", &not_new,
			"don't checkout new files"),
		{ OPTION_CALLBACK, 'u', "index", &newfd, NULL,
			"update stat information in the index file",
			PARSE_OPT_NOARG, option_parse_u },
		{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
			"paths are separated with NUL character",
			PARSE_OPT_NOARG, option_parse_z },
		OPT_BOOLEAN(0, "stdin", &read_from_stdin,
			"read list of paths from the standard input"),
		OPT_BOOLEAN(0, "temp", &to_tempfile,
			"write the content to temporary files"),
		OPT_CALLBACK(0, "prefix", NULL, "string",
			"when creating files, prepend <string>",
			option_parse_prefix),
		OPT_CALLBACK(0, "stage", NULL, NULL,
			"copy out the files from named stage",
			option_parse_stage),
		OPT_END()
	};

	if (argc == 2 && !strcmp(argv[1], "-h"))
		usage_with_options(builtin_checkout_index_usage,
				   builtin_checkout_index_options);
	git_config(git_default_config, NULL);
	state.base_dir = "";
	prefix_length = prefix ? strlen(prefix) : 0;

	if (read_cache() < 0) {
		die("invalid cache");
	}

	argc = parse_options(argc, argv, prefix, builtin_checkout_index_options,
			builtin_checkout_index_usage, 0);
	state.force = force;
	state.quiet = quiet;
	state.not_new = not_new;

	if (state.base_dir_len || to_tempfile) {
		/* when --prefix is specified we do not
		 * want to update cache.
		 */
		if (state.refresh_cache) {
			rollback_lock_file(&lock_file);
			newfd = -1;
		}
		state.refresh_cache = 0;
	}

	/* Check out named files first */
	for (i = 0; i < argc; i++) {
		const char *arg = argv[i];
		const char *p;

		if (all)
			die("git checkout-index: don't mix '--all' and explicit filenames");
		if (read_from_stdin)
			die("git checkout-index: don't mix '--stdin' and explicit filenames");
		p = prefix_path(prefix, prefix_length, arg);
		checkout_file(p, prefix_length);
		if (p < arg || p > arg + strlen(arg))
			free((char *)p);
	}

	if (read_from_stdin) {
		struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;

		if (all)
			die("git checkout-index: don't mix '--all' and '--stdin'");

		while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
			const char *p;
			if (line_termination && buf.buf[0] == '"') {
				strbuf_reset(&nbuf);
				if (unquote_c_style(&nbuf, buf.buf, NULL))
					die("line is badly quoted");
				strbuf_swap(&buf, &nbuf);
			}
			p = prefix_path(prefix, prefix_length, buf.buf);
			checkout_file(p, prefix_length);
			if (p < buf.buf || p > buf.buf + buf.len)
				free((char *)p);
		}
		strbuf_release(&nbuf);
		strbuf_release(&buf);
	}

	if (all)
		checkout_all(prefix, prefix_length);

	if (0 <= newfd &&
	    (write_cache(newfd, active_cache, active_nr) ||
	     commit_locked_index(&lock_file)))
		die("Unable to write new index file");
	return 0;
}
Esempio n. 22
0
int cmd_show_branch(int ac, const char **av, const char *prefix)
{
	struct commit *rev[MAX_REVS], *commit;
	char *reflog_msg[MAX_REVS];
	struct commit_list *list = NULL, *seen = NULL;
	unsigned int rev_mask[MAX_REVS];
	int num_rev, i, extra = 0;
	int all_heads = 0, all_remotes = 0;
	int all_mask, all_revs;
	int lifo = 1;
	char head[128];
	const char *head_p;
	int head_len;
	unsigned char head_sha1[20];
	int merge_base = 0;
	int independent = 0;
	int no_name = 0;
	int sha1_name = 0;
	int shown_merge_point = 0;
	int with_current_branch = 0;
	int head_at = -1;
	int topics = 0;
	int dense = 1;
	const char *reflog_base = NULL;
	struct option builtin_show_branch_options[] = {
		OPT_BOOLEAN('a', "all", &all_heads,
			    "show remote-tracking and local branches"),
		OPT_BOOLEAN('r', "remotes", &all_remotes,
			    "show remote-tracking branches"),
		OPT__COLOR(&showbranch_use_color,
			    "color '*!+-' corresponding to the branch"),
		{ OPTION_INTEGER, 0, "more", &extra, "n",
			    "show <n> more commits after the common ancestor",
			    PARSE_OPT_OPTARG, NULL, (intptr_t)1 },
		OPT_SET_INT(0, "list", &extra, "synonym to more=-1", -1),
		OPT_BOOLEAN(0, "no-name", &no_name, "suppress naming strings"),
		OPT_BOOLEAN(0, "current", &with_current_branch,
			    "include the current branch"),
		OPT_BOOLEAN(0, "sha1-name", &sha1_name,
			    "name commits with their object names"),
		OPT_BOOLEAN(0, "merge-base", &merge_base,
			    "show possible merge bases"),
		OPT_BOOLEAN(0, "independent", &independent,
			    "show refs unreachable from any other ref"),
		OPT_BOOLEAN(0, "topo-order", &lifo,
			    "show commits in topological order"),
		OPT_BOOLEAN(0, "topics", &topics,
			    "show only commits not on the first branch"),
		OPT_SET_INT(0, "sparse", &dense,
			    "show merges reachable from only one tip", 0),
		OPT_SET_INT(0, "date-order", &lifo,
			    "show commits where no parent comes before its "
			    "children", 0),
		{ OPTION_CALLBACK, 'g', "reflog", &reflog_base, "<n>[,<base>]",
			    "show <n> most recent ref-log entries starting at "
			    "base",
			    PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP,
			    parse_reflog_param },
		OPT_END()
	};

	git_config(git_show_branch_config, NULL);

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

	/* If nothing is specified, try the default first */
	if (ac == 1 && default_num) {
		ac = default_num;
		av = default_arg;
	}

	ac = parse_options(ac, av, prefix, builtin_show_branch_options,
			   show_branch_usage, PARSE_OPT_STOP_AT_NON_OPTION);
	if (all_heads)
		all_remotes = 1;

	if (extra || reflog) {
		/* "listing" mode is incompatible with
		 * independent nor merge-base modes.
		 */
		if (independent || merge_base)
			usage_with_options(show_branch_usage,
					   builtin_show_branch_options);
		if (reflog && ((0 < extra) || all_heads || all_remotes))
			/*
			 * Asking for --more in reflog mode does not
			 * make sense.  --list is Ok.
			 *
			 * Also --all and --remotes do not make sense either.
			 */
			die("--reflog is incompatible with --all, --remotes, "
			    "--independent or --merge-base");
	}

	/* If nothing is specified, show all branches by default */
	if (ac + all_heads + all_remotes == 0)
		all_heads = 1;

	if (reflog) {
		unsigned char sha1[20];
		char nth_desc[256];
		char *ref;
		int base = 0;

		if (ac == 0) {
			static const char *fake_av[2];
			const char *refname;

			refname = resolve_ref("HEAD", sha1, 1, NULL);
			fake_av[0] = xstrdup(refname);
			fake_av[1] = NULL;
			av = fake_av;
			ac = 1;
		}
		if (ac != 1)
			die("--reflog option needs one branch name");

		if (MAX_REVS < reflog)
			die("Only %d entries can be shown at one time.",
			    MAX_REVS);
		if (!dwim_ref(*av, strlen(*av), sha1, &ref))
			die("No such ref %s", *av);

		/* Has the base been specified? */
		if (reflog_base) {
			char *ep;
			base = strtoul(reflog_base, &ep, 10);
			if (*ep) {
				/* Ah, that is a date spec... */
				unsigned long at;
				at = approxidate(reflog_base);
				read_ref_at(ref, at, -1, sha1, NULL,
					    NULL, NULL, &base);
			}
		}

		for (i = 0; i < reflog; i++) {
			char *logmsg, *m;
			const char *msg;
			unsigned long timestamp;
			int tz;

			if (read_ref_at(ref, 0, base+i, sha1, &logmsg,
					&timestamp, &tz, NULL)) {
				reflog = i;
				break;
			}
			msg = strchr(logmsg, '\t');
			if (!msg)
				msg = "(none)";
			else
				msg++;
			m = xmalloc(strlen(msg) + 200);
			sprintf(m, "(%s) %s",
				show_date(timestamp, tz, 1),
				msg);
			reflog_msg[i] = m;
			free(logmsg);
			sprintf(nth_desc, "%s@{%d}", *av, base+i);
			append_ref(nth_desc, sha1, 1);
		}
	}
	else if (all_heads + all_remotes)
		snarf_refs(all_heads, all_remotes);
	else {
		while (0 < ac) {
			append_one_rev(*av);
			ac--; av++;
		}
	}

	head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
	if (head_p) {
		head_len = strlen(head_p);
		memcpy(head, head_p, head_len + 1);
	}
	else {
		head_len = 0;
		head[0] = 0;
	}

	if (with_current_branch && head_p) {
		int has_head = 0;
		for (i = 0; !has_head && i < ref_name_cnt; i++) {
			/* We are only interested in adding the branch
			 * HEAD points at.
			 */
			if (rev_is_head(head,
					head_len,
					ref_name[i],
					head_sha1, NULL))
				has_head++;
		}
		if (!has_head) {
			int offset = !prefixcmp(head, "refs/heads/") ? 11 : 0;
			append_one_rev(head + offset);
		}
	}

	if (!ref_name_cnt) {
		fprintf(stderr, "No revs to be shown.\n");
		exit(0);
	}

	for (num_rev = 0; ref_name[num_rev]; num_rev++) {
		unsigned char revkey[20];
		unsigned int flag = 1u << (num_rev + REV_SHIFT);

		if (MAX_REVS <= num_rev)
			die("cannot handle more than %d revs.", MAX_REVS);
		if (get_sha1(ref_name[num_rev], revkey))
			die("'%s' is not a valid ref.", ref_name[num_rev]);
		commit = lookup_commit_reference(revkey);
		if (!commit)
			die("cannot find commit %s (%s)",
			    ref_name[num_rev], revkey);
		parse_commit(commit);
		mark_seen(commit, &seen);

		/* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
		 * and so on.  REV_SHIFT bits from bit 0 are used for
		 * internal bookkeeping.
		 */
		commit->object.flags |= flag;
		if (commit->object.flags == flag)
			commit_list_insert_by_date(commit, &list);
		rev[num_rev] = commit;
	}
	for (i = 0; i < num_rev; i++)
		rev_mask[i] = rev[i]->object.flags;

	if (0 <= extra)
		join_revs(&list, &seen, num_rev, extra);

	commit_list_sort_by_date(&seen);

	if (merge_base)
		return show_merge_base(seen, num_rev);

	if (independent)
		return show_independent(rev, num_rev, ref_name, rev_mask);

	/* Show list; --more=-1 means list-only */
	if (1 < num_rev || extra < 0) {
		for (i = 0; i < num_rev; i++) {
			int j;
			int is_head = rev_is_head(head,
						  head_len,
						  ref_name[i],
						  head_sha1,
						  rev[i]->object.sha1);
			if (extra < 0)
				printf("%c [%s] ",
				       is_head ? '*' : ' ', ref_name[i]);
			else {
				for (j = 0; j < i; j++)
					putchar(' ');
				printf("%s%c%s [%s] ",
				       get_color_code(i),
				       is_head ? '*' : '!',
				       get_color_reset_code(), ref_name[i]);
			}

			if (!reflog) {
				/* header lines never need name */
				show_one_commit(rev[i], 1);
			}
			else
				puts(reflog_msg[i]);

			if (is_head)
				head_at = i;
		}
		if (0 <= extra) {
			for (i = 0; i < num_rev; i++)
				putchar('-');
			putchar('\n');
		}
	}
	if (extra < 0)
		exit(0);

	/* Sort topologically */
	sort_in_topological_order(&seen, lifo);

	/* Give names to commits */
	if (!sha1_name && !no_name)
		name_commits(seen, rev, ref_name, num_rev);

	all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
	all_revs = all_mask & ~((1u << REV_SHIFT) - 1);

	while (seen) {
		struct commit *commit = pop_one_commit(&seen);
		int this_flag = commit->object.flags;
		int is_merge_point = ((this_flag & all_revs) == all_revs);

		shown_merge_point |= is_merge_point;

		if (1 < num_rev) {
			int is_merge = !!(commit->parents &&
					  commit->parents->next);
			if (topics &&
			    !is_merge_point &&
			    (this_flag & (1u << REV_SHIFT)))
				continue;
			if (dense && is_merge &&
			    omit_in_dense(commit, rev, num_rev))
				continue;
			for (i = 0; i < num_rev; i++) {
				int mark;
				if (!(this_flag & (1u << (i + REV_SHIFT))))
					mark = ' ';
				else if (is_merge)
					mark = '-';
				else if (i == head_at)
					mark = '*';
				else
					mark = '+';
				printf("%s%c%s",
				       get_color_code(i),
				       mark, get_color_reset_code());
			}
			putchar(' ');
		}
		show_one_commit(commit, no_name);

		if (shown_merge_point && --extra < 0)
			break;
	}
	return 0;
}
Esempio n. 23
0
static int module_clone(int argc, const char **argv, const char *prefix)
{
	const char *name = NULL, *url = NULL, *depth = NULL;
	int quiet = 0;
	int progress = 0;
	char *p, *path = NULL, *sm_gitdir;
	struct strbuf sb = STRBUF_INIT;
	struct string_list reference = STRING_LIST_INIT_NODUP;
	char *sm_alternate = NULL, *error_strategy = NULL;

	struct option module_clone_options[] = {
		OPT_STRING(0, "prefix", &prefix,
			   N_("path"),
			   N_("alternative anchor for relative paths")),
		OPT_STRING(0, "path", &path,
			   N_("path"),
			   N_("where the new submodule will be cloned to")),
		OPT_STRING(0, "name", &name,
			   N_("string"),
			   N_("name of the new submodule")),
		OPT_STRING(0, "url", &url,
			   N_("string"),
			   N_("url where to clone the submodule from")),
		OPT_STRING_LIST(0, "reference", &reference,
			   N_("repo"),
			   N_("reference repository")),
		OPT_STRING(0, "depth", &depth,
			   N_("string"),
			   N_("depth for shallow clones")),
		OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
		OPT_BOOL(0, "progress", &progress,
			   N_("force cloning progress")),
		OPT_END()
	};

	const char *const git_submodule_helper_usage[] = {
		N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
		   "[--reference <repository>] [--name <name>] [--depth <depth>] "
		   "--url <url> --path <path>"),
		NULL
	};

	argc = parse_options(argc, argv, prefix, module_clone_options,
			     git_submodule_helper_usage, 0);

	if (argc || !url || !path || !*path)
		usage_with_options(git_submodule_helper_usage,
				   module_clone_options);

	strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
	sm_gitdir = absolute_pathdup(sb.buf);
	strbuf_reset(&sb);

	if (!is_absolute_path(path)) {
		strbuf_addf(&sb, "%s/%s", get_git_work_tree(), path);
		path = strbuf_detach(&sb, NULL);
	} else
		path = xstrdup(path);

	if (!file_exists(sm_gitdir)) {
		if (safe_create_leading_directories_const(sm_gitdir) < 0)
			die(_("could not create directory '%s'"), sm_gitdir);

		prepare_possible_alternates(name, &reference);

		if (clone_submodule(path, sm_gitdir, url, depth, &reference,
				    quiet, progress))
			die(_("clone of '%s' into submodule path '%s' failed"),
			    url, path);
	} else {
		if (safe_create_leading_directories_const(path) < 0)
			die(_("could not create directory '%s'"), path);
		strbuf_addf(&sb, "%s/index", sm_gitdir);
		unlink_or_warn(sb.buf);
		strbuf_reset(&sb);
	}

	/* Connect module worktree and git dir */
	connect_work_tree_and_git_dir(path, sm_gitdir);

	p = git_pathdup_submodule(path, "config");
	if (!p)
		die(_("could not get submodule directory for '%s'"), path);

	/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
	git_config_get_string("submodule.alternateLocation", &sm_alternate);
	if (sm_alternate)
		git_config_set_in_file(p, "submodule.alternateLocation",
					   sm_alternate);
	git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
	if (error_strategy)
		git_config_set_in_file(p, "submodule.alternateErrorStrategy",
					   error_strategy);

	free(sm_alternate);
	free(error_strategy);

	strbuf_release(&sb);
	free(sm_gitdir);
	free(path);
	free(p);
	return 0;
}
Esempio n. 24
0
int cmd_hash_object(int argc, const char **argv, const char *prefix)
{
	static const char * const hash_object_usage[] = {
		N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] [--] <file>..."),
		N_("git hash-object  --stdin-paths"),
		NULL
	};
	const char *type = blob_type;
	int hashstdin = 0;
	int stdin_paths = 0;
	int no_filters = 0;
	int literally = 0;
	int nongit = 0;
	unsigned flags = HASH_FORMAT_CHECK;
	const char *vpath = NULL;
	const struct option hash_object_options[] = {
		OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
		OPT_BIT('w', NULL, &flags, N_("write the object into the object database"),
			HASH_WRITE_OBJECT),
		OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
		OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
		OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
		OPT_BOOL( 0, "literally", &literally, N_("just hash any random garbage to create corrupt objects for debugging Git")),
		OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
		OPT_END()
	};
	int i;
	const char *errstr = NULL;

	argc = parse_options(argc, argv, NULL, hash_object_options,
			     hash_object_usage, 0);

	if (flags & HASH_WRITE_OBJECT)
		prefix = setup_git_directory();
	else
		prefix = setup_git_directory_gently(&nongit);

	if (vpath && prefix)
		vpath = xstrdup(prefix_filename(prefix, vpath));

	git_config(git_default_config, NULL);

	if (stdin_paths) {
		if (hashstdin)
			errstr = "Can't use --stdin-paths with --stdin";
		else if (argc)
			errstr = "Can't specify files with --stdin-paths";
		else if (vpath)
			errstr = "Can't use --stdin-paths with --path";
	}
	else {
		if (hashstdin > 1)
			errstr = "Multiple --stdin arguments are not supported";
		if (vpath && no_filters)
			errstr = "Can't use --path with --no-filters";
	}

	if (errstr) {
		error("%s", errstr);
		usage_with_options(hash_object_usage, hash_object_options);
	}

	if (hashstdin)
		hash_fd(0, type, vpath, flags, literally);

	for (i = 0 ; i < argc; i++) {
		const char *arg = argv[i];
		char *to_free = NULL;

		if (prefix)
			arg = to_free = prefix_filename(prefix, arg);
		hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
			    flags, literally);
		free(to_free);
	}

	if (stdin_paths)
		hash_stdin_paths(type, no_filters, flags, literally);

	return 0;
}
Esempio n. 25
0
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
{
    static int keep_dashdash = 0, stop_at_non_option = 0;
    static char const * const parseopt_usage[] = {
        N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
        NULL
    };
    static struct option parseopt_opts[] = {
        OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
        N_("keep the `--` passed as an arg")),
        OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
        N_("stop parsing after the "
        "first non-option argument")),
        OPT_BOOL(0, "stuck-long", &stuck_long,
        N_("output in stuck long form")),
        OPT_END(),
    };

    struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
    const char **usage = NULL;
    struct option *opts = NULL;
    int onb = 0, osz = 0, unb = 0, usz = 0;

    strbuf_addstr(&parsed, "set --");
    argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage,
                         PARSE_OPT_KEEP_DASHDASH);
    if (argc < 1 || strcmp(argv[0], "--"))
        usage_with_options(parseopt_usage, parseopt_opts);

    /* get the usage up to the first line with a -- on it */
    for (;;) {
        if (strbuf_getline(&sb, stdin, '\n') == EOF)
            die("premature end of input");
        ALLOC_GROW(usage, unb + 1, usz);
        if (!strcmp("--", sb.buf)) {
            if (unb < 1)
                die("no usage string given before the `--' separator");
            usage[unb] = NULL;
            break;
        }
        usage[unb++] = strbuf_detach(&sb, NULL);
    }

    /* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
    while (strbuf_getline(&sb, stdin, '\n') != EOF) {
        const char *s;
        const char *end;
        struct option *o;

        if (!sb.len)
            continue;

        ALLOC_GROW(opts, onb + 1, osz);
        memset(opts + onb, 0, sizeof(opts[onb]));

        o = &opts[onb++];
        s = strchr(sb.buf, ' ');
        if (!s || *sb.buf == ' ') {
            o->type = OPTION_GROUP;
            o->help = xstrdup(skipspaces(sb.buf));
            continue;
        }

        o->type = OPTION_CALLBACK;
        o->help = xstrdup(skipspaces(s));
        o->value = &parsed;
        o->flags = PARSE_OPT_NOARG;
        o->callback = &parseopt_dump;

        /* Possible argument name hint */
        end = s;
        while (s > sb.buf && strchr("*=?!", s[-1]) == NULL)
            --s;
        if (s != sb.buf && s != end)
            o->argh = xmemdupz(s, end - s);
        if (s == sb.buf)
            s = end;

        while (s > sb.buf && strchr("*=?!", s[-1])) {
            switch (*--s) {
            case '=':
                o->flags &= ~PARSE_OPT_NOARG;
                break;
            case '?':
                o->flags &= ~PARSE_OPT_NOARG;
                o->flags |= PARSE_OPT_OPTARG;
                break;
            case '!':
                o->flags |= PARSE_OPT_NONEG;
                break;
            case '*':
                o->flags |= PARSE_OPT_HIDDEN;
                break;
            }
        }

        if (s - sb.buf == 1) /* short option only */
            o->short_name = *sb.buf;
        else if (sb.buf[1] != ',') /* long option only */
            o->long_name = xmemdupz(sb.buf, s - sb.buf);
        else {
            o->short_name = *sb.buf;
            o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2);
        }
    }
    strbuf_release(&sb);

    /* put an OPT_END() */
    ALLOC_GROW(opts, onb + 1, osz);
    memset(opts + onb, 0, sizeof(opts[onb]));
    argc = parse_options(argc, argv, prefix, opts, usage,
                         (keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) |
                         (stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
                         PARSE_OPT_SHELL_EVAL);

    strbuf_addf(&parsed, " --");
    sq_quote_argv(&parsed, argv, 0);
    puts(parsed.buf);
    return 0;
}
Esempio n. 26
0
int cmd_format_patch(int argc, const char **argv, const char *prefix)
{
	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()
	};

	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. 27
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 reset = 0;
	int contin = 0;
	struct option options[] = {
		OPT_BOOLEAN(0, "reset", &reset, "forget the current operation"),
		OPT_BOOLEAN(0, "continue", &contin, "continue the current operation"),
		OPT_BOOLEAN('n', "no-commit", &opts->no_commit, "don't automatically commit"),
		OPT_BOOLEAN('e', "edit", &opts->edit, "edit the commit message"),
		OPT_NOOP_NOARG('r', NULL),
		OPT_BOOLEAN('s', "signoff", &opts->signoff, "add Signed-off-by:"),
		OPT_INTEGER('m', "mainline", &opts->mainline, "parent number"),
		OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
		OPT_STRING(0, "strategy", &opts->strategy, "strategy", "merge strategy"),
		OPT_CALLBACK('X', "strategy-option", &opts, "option",
			"option for merge strategy", option_parse_x),
		OPT_END(),
		OPT_END(),
		OPT_END(),
	};

	if (opts->action == CHERRY_PICK) {
		struct option cp_extra[] = {
			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
			OPT_END(),
		};
		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
			die(_("program error"));
	}

	opts->commit_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,
				"--reset", reset,
				"--continue", contin,
				NULL);

	/* Set the subcommand */
	if (reset)
		opts->subcommand = REPLAY_RESET;
	else if (contin)
		opts->subcommand = REPLAY_CONTINUE;
	else
		opts->subcommand = REPLAY_NONE;

	/* Check for incompatible command line arguments */
	if (opts->subcommand != REPLAY_NONE) {
		char *this_operation;
		if (opts->subcommand == REPLAY_RESET)
			this_operation = "--reset";
		else
			this_operation = "--continue";

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

	else if (opts->commit_argc < 2)
		usage_with_options(usage_str, options);

	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);
	opts->commit_argv = argv;
}
Esempio n. 28
0
int cmd_cherry(int argc, const char **argv, const char *prefix)
{
	struct rev_info revs;
	struct patch_ids ids;
	struct commit *commit;
	struct commit_list *list = NULL;
	struct branch *current_branch;
	const char *upstream;
	const char *head = "HEAD";
	const char *limit = NULL;
	int verbose = 0, abbrev = 0;

	struct option options[] = {
		OPT__ABBREV(&abbrev),
		OPT__VERBOSE(&verbose, "be verbose"),
		OPT_END()
	};

	argc = parse_options(argc, argv, prefix, options, cherry_usage, 0);

	switch (argc) {
	case 3:
		limit = argv[2];
		/* FALLTHROUGH */
	case 2:
		head = argv[1];
		/* FALLTHROUGH */
	case 1:
		upstream = argv[0];
		break;
	default:
		current_branch = branch_get(NULL);
		if (!current_branch || !current_branch->merge
					|| !current_branch->merge[0]
					|| !current_branch->merge[0]->dst) {
			fprintf(stderr, _("Could not find a tracked"
					" remote branch, please"
					" specify <upstream> manually.\n"));
			usage_with_options(cherry_usage, options);
		}

		upstream = current_branch->merge[0]->dst;
	}

	init_revisions(&revs, prefix);
	revs.diff = 1;
	revs.combine_merges = 0;
	revs.ignore_merges = 1;
	DIFF_OPT_SET(&revs.diffopt, RECURSIVE);

	if (add_pending_commit(head, &revs, 0))
		die(_("Unknown commit %s"), head);
	if (add_pending_commit(upstream, &revs, UNINTERESTING))
		die(_("Unknown commit %s"), upstream);

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

	get_patch_ids(&revs, &ids, prefix);

	if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
		die(_("Unknown commit %s"), limit);

	/* reverse the list of commits */
	if (prepare_revision_walk(&revs))
		die(_("revision walk setup failed"));
	while ((commit = get_revision(&revs)) != NULL) {
		/* ignore merges */
		if (commit->parents && commit->parents->next)
			continue;

		commit_list_insert(commit, &list);
	}

	while (list) {
		char sign = '+';

		commit = list->item;
		if (has_commit_patch_id(commit, &ids))
			sign = '-';
		print_commit(sign, commit, verbose, abbrev);
		list = list->next;
	}

	free_patch_ids(&ids);
	return 0;
}
Esempio n. 29
0
int cmd_grep(int argc, const char **argv, const char *prefix)
{
	int hit = 0;
	int cached = 0, untracked = 0, opt_exclude = -1;
	int seen_dashdash = 0;
	int external_grep_allowed__ignored;
	const char *show_in_pager = NULL, *default_pager = "dummy";
	struct grep_opt opt;
	struct object_array list = OBJECT_ARRAY_INIT;
	const char **paths = NULL;
	struct pathspec pathspec;
	struct string_list path_list = STRING_LIST_INIT_NODUP;
	int i;
	int dummy;
	int use_index = 1;
	enum {
		pattern_type_unspecified = 0,
		pattern_type_bre,
		pattern_type_ere,
		pattern_type_fixed,
		pattern_type_pcre,
	};
	int pattern_type = pattern_type_unspecified;

	struct option options[] = {
		OPT_BOOLEAN(0, "cached", &cached,
			"search in index instead of in the work tree"),
		{ OPTION_BOOLEAN, 0, "index", &use_index, NULL,
			"finds in contents not managed by git",
			PARSE_OPT_NOARG | PARSE_OPT_NEGHELP },
		OPT_BOOLEAN(0, "untracked", &untracked,
			"search in both tracked and untracked files"),
		OPT_SET_INT(0, "exclude-standard", &opt_exclude,
			    "search also in ignored files", 1),
		OPT_GROUP(""),
		OPT_BOOLEAN('v', "invert-match", &opt.invert,
			"show non-matching lines"),
		OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case,
			"case insensitive matching"),
		OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
			"match patterns only at word boundaries"),
		OPT_SET_INT('a', "text", &opt.binary,
			"process binary files as text", GREP_BINARY_TEXT),
		OPT_SET_INT('I', NULL, &opt.binary,
			"don't match patterns in binary files",
			GREP_BINARY_NOMATCH),
		{ OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth",
			"descend at most <depth> levels", PARSE_OPT_NONEG,
			NULL, 1 },
		OPT_GROUP(""),
		OPT_SET_INT('E', "extended-regexp", &pattern_type,
			    "use extended POSIX regular expressions",
			    pattern_type_ere),
		OPT_SET_INT('G', "basic-regexp", &pattern_type,
			    "use basic POSIX regular expressions (default)",
			    pattern_type_bre),
		OPT_SET_INT('F', "fixed-strings", &pattern_type,
			    "interpret patterns as fixed strings",
			    pattern_type_fixed),
		OPT_SET_INT('P', "perl-regexp", &pattern_type,
			    "use Perl-compatible regular expressions",
			    pattern_type_pcre),
		OPT_GROUP(""),
		OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"),
		OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
		OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
		OPT_NEGBIT(0, "full-name", &opt.relative,
			"show filenames relative to top directory", 1),
		OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
			"show only filenames instead of matching lines"),
		OPT_BOOLEAN(0, "name-only", &opt.name_only,
			"synonym for --files-with-matches"),
		OPT_BOOLEAN('L', "files-without-match",
			&opt.unmatch_name_only,
			"show only the names of files without match"),
		OPT_BOOLEAN('z', "null", &opt.null_following_name,
			"print NUL after filenames"),
		OPT_BOOLEAN('c', "count", &opt.count,
			"show the number of matches instead of matching lines"),
		OPT__COLOR(&opt.color, "highlight matches"),
		OPT_BOOLEAN(0, "break", &opt.file_break,
			"print empty line between matches from different files"),
		OPT_BOOLEAN(0, "heading", &opt.heading,
			"show filename only once above matches from same file"),
		OPT_GROUP(""),
		OPT_CALLBACK('C', "context", &opt, "n",
			"show <n> context lines before and after matches",
			context_callback),
		OPT_INTEGER('B', "before-context", &opt.pre_context,
			"show <n> context lines before matches"),
		OPT_INTEGER('A', "after-context", &opt.post_context,
			"show <n> context lines after matches"),
		OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
			context_callback),
		OPT_BOOLEAN('p', "show-function", &opt.funcname,
			"show a line with the function name before matches"),
		OPT_BOOLEAN('W', "function-context", &opt.funcbody,
			"show the surrounding function"),
		OPT_GROUP(""),
		OPT_CALLBACK('f', NULL, &opt, "file",
			"read patterns from file", file_callback),
		{ OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
			"match <pattern>", PARSE_OPT_NONEG, pattern_callback },
		{ OPTION_CALLBACK, 0, "and", &opt, NULL,
		  "combine patterns specified with -e",
		  PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
		OPT_BOOLEAN(0, "or", &dummy, ""),
		{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
		  PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
		{ OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
		  PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
		  open_callback },
		{ OPTION_CALLBACK, ')', NULL, &opt, NULL, "",
		  PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
		  close_callback },
		OPT__QUIET(&opt.status_only,
			   "indicate hit with exit status without output"),
		OPT_BOOLEAN(0, "all-match", &opt.all_match,
			"show only matches from files that match all patterns"),
		OPT_GROUP(""),
		{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
			"pager", "show matching files in the pager",
			PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
		OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored,
			    "allow calling of grep(1) (ignored by this build)"),
		{ OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
		  PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
		OPT_END()
	};

	/*
	 * 'git grep -h', unlike 'git grep -h <pattern>', is a request
	 * to show usage information and exit.
	 */
	if (argc == 2 && !strcmp(argv[1], "-h"))
		usage_with_options(grep_usage, options);

	memset(&opt, 0, sizeof(opt));
	opt.prefix = prefix;
	opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
	opt.relative = 1;
	opt.pathname = 1;
	opt.pattern_tail = &opt.pattern_list;
	opt.header_tail = &opt.header_list;
	opt.regflags = REG_NEWLINE;
	opt.max_depth = -1;

	strcpy(opt.color_context, "");
	strcpy(opt.color_filename, "");
	strcpy(opt.color_function, "");
	strcpy(opt.color_lineno, "");
	strcpy(opt.color_match, GIT_COLOR_BOLD_RED);
	strcpy(opt.color_selected, "");
	strcpy(opt.color_sep, GIT_COLOR_CYAN);
	opt.color = -1;
	git_config(grep_config, &opt);

	/*
	 * If there is no -- then the paths must exist in the working
	 * tree.  If there is no explicit pattern specified with -e or
	 * -f, we take the first unrecognized non option to be the
	 * pattern, but then what follows it must be zero or more
	 * valid refs up to the -- (if exists), and then existing
	 * paths.  If there is an explicit pattern, then the first
	 * unrecognized non option is the beginning of the refs list
	 * that continues up to the -- (if exists), and then paths.
	 */
	argc = parse_options(argc, argv, prefix, options, grep_usage,
			     PARSE_OPT_KEEP_DASHDASH |
			     PARSE_OPT_STOP_AT_NON_OPTION |
			     PARSE_OPT_NO_INTERNAL_HELP);
	switch (pattern_type) {
	case pattern_type_fixed:
		opt.fixed = 1;
		opt.pcre = 0;
		break;
	case pattern_type_bre:
		opt.fixed = 0;
		opt.pcre = 0;
		opt.regflags &= ~REG_EXTENDED;
		break;
	case pattern_type_ere:
		opt.fixed = 0;
		opt.pcre = 0;
		opt.regflags |= REG_EXTENDED;
		break;
	case pattern_type_pcre:
		opt.fixed = 0;
		opt.pcre = 1;
		break;
	default:
		break; /* nothing */
	}

	if (use_index && !startup_info->have_repository)
		/* die the same way as if we did it at the beginning */
		setup_git_directory();

	/*
	 * skip a -- separator; we know it cannot be
	 * separating revisions from pathnames if
	 * we haven't even had any patterns yet
	 */
	if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) {
		argv++;
		argc--;
	}

	/* First unrecognized non-option token */
	if (argc > 0 && !opt.pattern_list) {
		append_grep_pattern(&opt, argv[0], "command line", 0,
				    GREP_PATTERN);
		argv++;
		argc--;
	}

	if (show_in_pager == default_pager)
		show_in_pager = git_pager(1);
	if (show_in_pager) {
		opt.color = 0;
		opt.name_only = 1;
		opt.null_following_name = 1;
		opt.output_priv = &path_list;
		opt.output = append_path;
		string_list_append(&path_list, show_in_pager);
		use_threads = 0;
	}

	if (!opt.pattern_list)
		die(_("no pattern given."));
	if (!opt.fixed && opt.ignore_case)
		opt.regflags |= REG_ICASE;

	compile_grep_patterns(&opt);

	/* Check revs and then paths */
	for (i = 0; i < argc; i++) {
		const char *arg = argv[i];
		unsigned char sha1[20];
		/* Is it a rev? */
		if (!get_sha1(arg, sha1)) {
			struct object *object = parse_object(sha1);
			if (!object)
				die(_("bad object %s"), arg);
			add_object_array(object, arg, &list);
			continue;
		}
		if (!strcmp(arg, "--")) {
			i++;
			seen_dashdash = 1;
		}
		break;
	}

#ifndef NO_PTHREADS
	if (list.nr || cached || online_cpus() == 1)
		use_threads = 0;
#else
	use_threads = 0;
#endif

#ifndef NO_PTHREADS
	if (use_threads) {
		if (!(opt.name_only || opt.unmatch_name_only || opt.count)
		    && (opt.pre_context || opt.post_context ||
			opt.file_break || opt.funcbody))
			skip_first_line = 1;
		start_threads(&opt);
	}
#endif

	/* The rest are paths */
	if (!seen_dashdash) {
		int j;
		for (j = i; j < argc; j++)
			verify_filename(prefix, argv[j]);
	}

	paths = get_pathspec(prefix, argv + i);
	init_pathspec(&pathspec, paths);
	pathspec.max_depth = opt.max_depth;
	pathspec.recursive = 1;

	if (show_in_pager && (cached || list.nr))
		die(_("--open-files-in-pager only works on the worktree"));

	if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) {
		const char *pager = path_list.items[0].string;
		int len = strlen(pager);

		if (len > 4 && is_dir_sep(pager[len - 5]))
			pager += len - 4;

		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
			struct strbuf buf = STRBUF_INIT;
			strbuf_addf(&buf, "+/%s%s",
					strcmp("less", pager) ? "" : "*",
					opt.pattern_list->pattern);
			string_list_append(&path_list, buf.buf);
			strbuf_detach(&buf, NULL);
		}
	}

	if (!show_in_pager)
		setup_pager();

	if (!use_index && (untracked || cached))
		die(_("--cached or --untracked cannot be used with --no-index."));

	if (!use_index || untracked) {
		int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
		if (list.nr)
			die(_("--no-index or --untracked cannot be used with revs."));
		hit = grep_directory(&opt, &pathspec, use_exclude);
	} else if (0 <= opt_exclude) {
		die(_("--[no-]exclude-standard cannot be used for tracked contents."));
	} else if (!list.nr) {
		if (!cached)
			setup_work_tree();

		hit = grep_cache(&opt, &pathspec, cached);
	} else {
		if (cached)
			die(_("both --cached and trees are given."));
		hit = grep_objects(&opt, &pathspec, &list);
	}

	if (use_threads)
		hit |= wait_all();
	if (hit && show_in_pager)
		run_pager(&opt, prefix);
	free_grep_patterns(&opt);
	return !hit;
}
Esempio n. 30
0
static int append_edit(int argc, const char **argv, const char *prefix)
{
	int allow_empty = 0;
	const char *object_ref;
	struct notes_tree *t;
	struct object_id object, new_note;
	const struct object_id *note;
	char *logmsg;
	const char * const *usage;
	struct note_data d = { 0, 0, NULL, STRBUF_INIT };
	struct option options[] = {
		{ OPTION_CALLBACK, 'm', "message", &d, N_("message"),
			N_("note contents as a string"), PARSE_OPT_NONEG,
			parse_msg_arg},
		{ OPTION_CALLBACK, 'F', "file", &d, N_("file"),
			N_("note contents in a file"), PARSE_OPT_NONEG,
			parse_file_arg},
		{ OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"),
			N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
			parse_reedit_arg},
		{ OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"),
			N_("reuse specified note object"), PARSE_OPT_NONEG,
			parse_reuse_arg},
		OPT_BOOL(0, "allow-empty", &allow_empty,
			N_("allow storing empty note")),
		OPT_END()
	};
	int edit = !strcmp(argv[0], "edit");

	usage = edit ? git_notes_edit_usage : git_notes_append_usage;
	argc = parse_options(argc, argv, prefix, options, usage,
			     PARSE_OPT_KEEP_ARGV0);

	if (2 < argc) {
		error(_("too many parameters"));
		usage_with_options(usage, options);
	}

	if (d.given && edit)
		fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
			"for the 'edit' subcommand.\n"
			"Please use 'git notes add -f -m/-F/-c/-C' instead.\n"));

	object_ref = 1 < argc ? argv[1] : "HEAD";

	if (get_oid(object_ref, &object))
		die(_("failed to resolve '%s' as a valid ref."), object_ref);

	t = init_notes_check(argv[0], NOTES_INIT_WRITABLE);
	note = get_note(t, &object);

	prepare_note_data(&object, &d, edit && note ? note->hash : NULL);

	if (note && !edit) {
		/* Append buf to previous note contents */
		unsigned long size;
		enum object_type type;
		char *prev_buf = read_sha1_file(note->hash, &type, &size);

		strbuf_grow(&d.buf, size + 1);
		if (d.buf.len && prev_buf && size)
			strbuf_insert(&d.buf, 0, "\n", 1);
		if (prev_buf && size)
			strbuf_insert(&d.buf, 0, prev_buf, size);
		free(prev_buf);
	}

	if (d.buf.len || allow_empty) {
		write_note_data(&d, new_note.hash);
		if (add_note(t, &object, &new_note, combine_notes_overwrite))
			die("BUG: combine_notes_overwrite failed");
		logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
	} else {
		fprintf(stderr, _("Removing note for object %s\n"),
			oid_to_hex(&object));
		remove_note(t, object.hash);
		logmsg = xstrfmt("Notes removed by 'git notes %s'", argv[0]);
	}
	commit_notes(t, logmsg);

	free(logmsg);
	free_note_data(&d);
	free_notes(t);
	return 0;
}