int run_add_interactive(const char *revision, const char *patch_mode, const struct pathspec *pathspec) { int status, i; struct argv_array argv = ARGV_ARRAY_INIT; argv_array_push(&argv, "add--interactive"); if (patch_mode) argv_array_push(&argv, patch_mode); if (revision) argv_array_push(&argv, revision); argv_array_push(&argv, "--"); for (i = 0; i < pathspec->nr; i++) /* pass original pathspec, to be re-parsed */ argv_array_push(&argv, pathspec->items[i].original); status = run_command_v_opt(argv.argv, RUN_GIT_CMD); argv_array_clear(&argv); return status; }
/** * Given the current HEAD SHA1, the merge head returned from git-fetch and the * fork point calculated by get_rebase_fork_point(), runs git-rebase with the * appropriate arguments and returns its exit status. */ static int run_rebase(const unsigned char *curr_head, const unsigned char *merge_head, const unsigned char *fork_point) { int ret; unsigned char oct_merge_base[GIT_SHA1_RAWSZ]; struct argv_array args = ARGV_ARRAY_INIT; if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point)) if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point)) fork_point = NULL; argv_array_push(&args, "rebase"); /* Shared options */ argv_push_verbosity(&args); /* Options passed to git-rebase */ if (opt_rebase == REBASE_PRESERVE) argv_array_push(&args, "--preserve-merges"); else if (opt_rebase == REBASE_INTERACTIVE) argv_array_push(&args, "--interactive"); if (opt_diffstat) argv_array_push(&args, opt_diffstat); argv_array_pushv(&args, opt_strategies.argv); argv_array_pushv(&args, opt_strategy_opts.argv); if (opt_gpg_sign) argv_array_push(&args, opt_gpg_sign); argv_array_push(&args, "--onto"); argv_array_push(&args, sha1_to_hex(merge_head)); if (fork_point && !is_null_sha1(fork_point)) argv_array_push(&args, sha1_to_hex(fork_point)); else argv_array_push(&args, sha1_to_hex(merge_head)); ret = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); return ret; }
/** * Runs git-merge, returning its exit status. */ static int run_merge(void) { int ret; struct argv_array args = ARGV_ARRAY_INIT; argv_array_pushl(&args, "merge", NULL); /* Shared options */ argv_push_verbosity(&args); if (opt_progress) argv_array_push(&args, opt_progress); /* Options passed to git-merge */ if (opt_diffstat) argv_array_push(&args, opt_diffstat); if (opt_log) argv_array_push(&args, opt_log); if (opt_signoff) argv_array_push(&args, opt_signoff); if (opt_squash) argv_array_push(&args, opt_squash); if (opt_commit) argv_array_push(&args, opt_commit); if (opt_edit) argv_array_push(&args, opt_edit); if (opt_ff) argv_array_push(&args, opt_ff); if (opt_verify_signatures) argv_array_push(&args, opt_verify_signatures); argv_array_pushv(&args, opt_strategies.argv); argv_array_pushv(&args, opt_strategy_opts.argv); if (opt_gpg_sign) argv_array_push(&args, opt_gpg_sign); if (opt_allow_unrelated_histories > 0) argv_array_push(&args, "--allow-unrelated-histories"); argv_array_push(&args, "FETCH_HEAD"); ret = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); return ret; }
static int push_dav(int nr_spec, char **specs) { const char **argv = xmalloc((10 + nr_spec) * sizeof(char*)); int argc = 0, i; argv[argc++] = "http-push"; argv[argc++] = "--helper-status"; if (options.dry_run) argv[argc++] = "--dry-run"; if (options.verbosity > 1) argv[argc++] = "--verbose"; argv[argc++] = url; for (i = 0; i < nr_spec; i++) argv[argc++] = specs[i]; argv[argc++] = NULL; if (run_command_v_opt(argv, RUN_GIT_CMD)) die("git-%s failed", argv[0]); free(argv); return 0; }
static void restore_state(void) { struct strbuf sb = STRBUF_INIT; const char *args[] = { "stash", "apply", NULL, NULL }; if (is_null_sha1(stash)) return; reset_hard(head, 1); args[2] = sha1_to_hex(stash); /* * It is OK to ignore error here, for example when there was * nothing to restore. */ run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&sb); refresh_cache(REFRESH_QUIET); }
int run_add_interactive(const char *revision, const char *patch_mode, const struct pathspec *pathspec) { int status, ac, i; const char **args; args = xcalloc(sizeof(const char *), (pathspec->nr + 6)); ac = 0; args[ac++] = "add--interactive"; if (patch_mode) args[ac++] = patch_mode; if (revision) args[ac++] = revision; args[ac++] = "--"; for (i = 0; i < pathspec->nr; i++) /* pass original pathspec, to be re-parsed */ args[ac++] = pathspec->items[i].original; status = run_command_v_opt(args, RUN_GIT_CMD); free(args); return status; }
static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { const char **argv; int argc; int err; if (flags & TRANSPORT_PUSH_MIRROR) return error("http transport does not support mirror mode"); argv = xmalloc((refspec_nr + 12) * sizeof(char *)); argv[0] = "http-push"; argc = 1; if (flags & TRANSPORT_PUSH_ALL) argv[argc++] = "--all"; if (flags & TRANSPORT_PUSH_FORCE) argv[argc++] = "--force"; if (flags & TRANSPORT_PUSH_DRY_RUN) argv[argc++] = "--dry-run"; if (flags & TRANSPORT_PUSH_VERBOSE) argv[argc++] = "--verbose"; argv[argc++] = transport->url; while (refspec_nr--) argv[argc++] = *refspec++; argv[argc] = NULL; err = run_command_v_opt(argv, RUN_GIT_CMD); switch (err) { case -ERR_RUN_COMMAND_FORK: error("unable to fork for %s", argv[0]); case -ERR_RUN_COMMAND_EXEC: error("unable to exec %s", argv[0]); break; case -ERR_RUN_COMMAND_WAITPID: case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: case -ERR_RUN_COMMAND_WAITPID_SIGNAL: case -ERR_RUN_COMMAND_WAITPID_NOEXIT: error("%s died with strange error", argv[0]); } return !!err; }
static void execv_dashed_external(const char **argv) { struct strbuf cmd = STRBUF_INIT; const char *tmp; int status; if (get_super_prefix()) die("%s doesn't support --super-prefix", argv[0]); if (use_pager == -1) use_pager = check_pager_config(argv[0]); commit_pager_choice(); strbuf_addf(&cmd, "git-%s", argv[0]); /* * argv[0] must be the git command, but the argv array * belongs to the caller, and may be reused in * subsequent loop iterations. Save argv[0] and * restore it on error. */ tmp = argv[0]; argv[0] = cmd.buf; trace_argv_printf(argv, "trace: exec:"); /* * if we fail because the command is not found, it is * OK to return. Otherwise, we just pass along the status code. */ status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE | RUN_CLEAN_ON_EXIT); if (status >= 0 || errno != ENOENT) exit(status); argv[0] = tmp; strbuf_release(&cmd); }
static void execv_dashed_external(const char **argv) { struct strbuf cmd = STRBUF_INIT; const char *tmp; int status; strbuf_addf(&cmd, "perf-%s", argv[0]); tmp = argv[0]; argv[0] = cmd.buf; status = run_command_v_opt(argv, 0); if (status != -ERR_RUN_COMMAND_EXEC) { if (IS_RUN_COMMAND_ERR(status)) die("unable to run '%s'", argv[0]); exit(-status); } errno = ENOENT; argv[0] = tmp; strbuf_release(&cmd); }
static int sequencer_skip(struct replay_opts *opts) { const char *argv[3]; /* reset --hard + NULL */ struct string_list merge_rr = STRING_LIST_INIT_DUP; int ret; if (setup_rerere(&merge_rr, 0) >= 0) { rerere_clear(&merge_rr); string_list_clear(&merge_rr, 1); } argv[0] = "reset"; argv[1] = "--hard"; argv[2] = NULL; ret = run_command_v_opt(argv, RUN_GIT_CMD); if (ret) return ret; discard_cache(); read_cache(); return sequencer_continue(opts, 1); }
static void execv_dashed_external(const char **argv) { char *cmd; const char *tmp; int status; if (asprintf(&cmd, "perf-%s", argv[0]) < 0) goto do_die; /* * argv[0] must be the perf command, but the argv array * belongs to the caller, and may be reused in * subsequent loop iterations. Save argv[0] and * restore it on error. */ tmp = argv[0]; argv[0] = cmd; /* * if we fail because the command is not found, it is * OK to return. Otherwise, we just pass along the status code. */ status = run_command_v_opt(argv, 0); if (status != -ERR_RUN_COMMAND_EXEC) { if (IS_RUN_COMMAND_ERR(status)) { do_die: pr_err("FATAL: unable to run '%s'", argv[0]); status = -128; } exit(-status); } errno = ENOENT; /* as if we called execvp */ argv[0] = tmp; zfree(&cmd); }
static int merge_entry(int pos, const char *path) { int found; const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL }; char hexbuf[4][GIT_SHA1_HEXSZ + 1]; char ownbuf[4][60]; if (pos >= active_nr) die("git merge-index: %s not in the cache", path); found = 0; do { const struct cache_entry *ce = active_cache[pos]; int stage = ce_stage(ce); if (strcmp(ce->name, path)) break; found++; oid_to_hex_r(hexbuf[stage], &ce->oid); xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; } while (++pos < active_nr); if (!found) die("git merge-index: %s not in the cache", path); if (run_command_v_opt(arguments, 0)) { if (one_shot) err++; else { if (!quiet) die("merge program failed"); exit(1); } } return found; }
static int reset_index_file(const unsigned char *sha1, int reset_type, int quiet) { int i = 0; const char *args[6]; args[i++] = "read-tree"; if (!quiet) args[i++] = "-v"; switch (reset_type) { case MERGE: args[i++] = "-u"; args[i++] = "-m"; break; case HARD: args[i++] = "-u"; /* fallthrough */ default: args[i++] = "--reset"; } args[i++] = sha1_to_hex(sha1); args[i] = NULL; return run_command_v_opt(args, RUN_GIT_CMD); }
/* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original * author date and name. * If we are revert, or if our cherry-pick results in a hand merge, * we had better say that the current user is responsible for that. */ static int run_git_commit(const char *defmsg, struct replay_opts *opts, int allow_empty) { struct argv_array array; int rc; char *gpg_sign; argv_array_init(&array); argv_array_push(&array, "commit"); argv_array_push(&array, "-n"); if (opts->quiet) argv_array_push(&array, "-q"); if (opts->gpg_sign) { gpg_sign = xmalloc(3 + strlen(opts->gpg_sign)); sprintf(gpg_sign, "-S%s", opts->gpg_sign); argv_array_push(&array, gpg_sign); free(gpg_sign); } if (opts->signoff) argv_array_push(&array, "-s"); if (!opts->edit) { argv_array_push(&array, "-F"); argv_array_push(&array, defmsg); } if (allow_empty) argv_array_push(&array, "--allow-empty"); if (opts->allow_empty_message) argv_array_push(&array, "--allow-empty-message"); rc = run_command_v_opt(array.argv, RUN_GIT_CMD); argv_array_clear(&array); return rc; }
int cmd_gc(int argc, const char **argv, const char *prefix) { int aggressive = 0; int auto_gc = 0; int quiet = 0; int force = 0; const char *name; pid_t pid; 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_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), OPT_BOOL(0, "auto", &auto_gc, N_("enable auto-gc mode")), OPT_BOOL(0, "force", &force, N_("force running gc even if there may be another gc running")), 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 (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(); name = lock_repo_for_gc(force, &pid); if (name) { if (auto_gc) return 0; /* be quiet on --auto */ die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"), name, (uintmax_t)pid); } 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; }
static const char *unpack(void) { struct pack_header hdr; const char *hdr_err; char hdr_arg[38]; hdr_err = parse_pack_header(&hdr); if (hdr_err) return hdr_err; snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { int code, i = 0; const char *unpacker[4]; unpacker[i++] = "unpack-objects"; if (receive_fsck_objects) unpacker[i++] = "--strict"; unpacker[i++] = hdr_arg; unpacker[i++] = NULL; code = run_command_v_opt(unpacker, RUN_GIT_CMD); switch (code) { case 0: return NULL; case -ERR_RUN_COMMAND_FORK: return "unpack fork failed"; case -ERR_RUN_COMMAND_EXEC: return "unpack execute failed"; case -ERR_RUN_COMMAND_WAITPID: return "waitpid failed"; case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: return "waitpid is confused"; case -ERR_RUN_COMMAND_WAITPID_SIGNAL: return "unpacker died of signal"; case -ERR_RUN_COMMAND_WAITPID_NOEXIT: return "unpacker died strangely"; default: return "unpacker exited with error code"; } } else { const char *keeper[7]; int s, status, i = 0; char keep_arg[256]; struct child_process ip; s = sprintf(keep_arg, "--keep=receive-pack %"PRIuMAX" on ", (uintmax_t) getpid()); if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); keeper[i++] = "index-pack"; keeper[i++] = "--stdin"; if (receive_fsck_objects) keeper[i++] = "--strict"; keeper[i++] = "--fix-thin"; keeper[i++] = hdr_arg; keeper[i++] = keep_arg; keeper[i++] = NULL; memset(&ip, 0, sizeof(ip)); ip.argv = keeper; ip.out = -1; ip.git_cmd = 1; if (start_command(&ip)) return "index-pack fork failed"; pack_lockfile = index_pack_lockfile(ip.out); close(ip.out); status = finish_command(&ip); if (!status) { reprepare_packed_git(); return NULL; } return "index-pack abnormal exit"; } }
static int handle_alias(int *argcp, const char ***argv) { int envchanged = 0, ret = 0, saved_errno = errno; const char *subdir; int count, option_count; const char **new_argv; const char *alias_command; char *alias_string; int unused_nongit; subdir = setup_git_directory_gently(&unused_nongit); alias_command = (*argv)[0]; alias_string = alias_lookup(alias_command); if (alias_string) { if (alias_string[0] == '!') { const char **alias_argv; int argc = *argcp, i; commit_pager_choice(); /* build alias_argv */ alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1)); alias_argv[0] = alias_string + 1; for (i = 1; i < argc; ++i) alias_argv[i] = (*argv)[i]; alias_argv[argc] = NULL; ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); if (ret >= 0) /* normal exit */ exit(ret); die_errno("While expanding alias '%s': '%s'", alias_command, alias_string + 1); } count = split_cmdline(alias_string, &new_argv); if (count < 0) die("Bad alias.%s string: %s", alias_command, split_cmdline_strerror(count)); option_count = handle_options(&new_argv, &count, &envchanged); if (envchanged) die("alias '%s' changes environment variables\n" "You can use '!git' in the alias to do this.", alias_command); memmove(new_argv - option_count, new_argv, count * sizeof(char *)); new_argv -= option_count; if (count < 1) die("empty alias for %s", alias_command); if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); trace_argv_printf(new_argv, "trace: alias expansion: %s =>", alias_command); new_argv = xrealloc(new_argv, sizeof(char *) * (count + *argcp)); /* insert after command name */ memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); *argv = new_argv; *argcp += count - 1; ret = 1; } if (subdir && chdir(subdir)) die_errno("Cannot change to '%s'", subdir); errno = saved_errno; return ret; }
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[] = { OPT__QUIET(&quiet, "suppress progress reporting"), { 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_END() }; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_gc_usage, builtin_gc_options); 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; }
int cmd_gc(int argc, const char **argv, const char *prefix) { int aggressive = 0; int auto_gc = 0; int quiet = 0; int force = 0; const char *name; pid_t pid; int daemonized = 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_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), OPT_BOOL(0, "auto", &auto_gc, N_("enable auto-gc mode")), OPT_BOOL(0, "force", &force, N_("force running gc even if there may be another gc running")), 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(&prune_worktrees, "worktree", "prune", "--expire", NULL); argv_array_pushl(&rerere, "rerere", "gc", NULL); gc_config(); 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"); if (aggressive_depth > 0) argv_array_pushf(&repack, "--depth=%d", aggressive_depth); if (aggressive_window > 0) argv_array_pushf(&repack, "--window=%d", aggressive_window); } if (quiet) argv_array_push(&repack, "-q"); if (auto_gc) { /* * Auto-gc should be least intrusive as possible. */ if (!need_to_gc()) return 0; if (!quiet) { if (detach_auto) fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n")); else fprintf(stderr, _("Auto packing the repository for optimum performance.\n")); fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n")); } if (detach_auto) { if (report_last_gc_error()) return -1; if (gc_before_repack()) return -1; /* * failure to daemonize is ok, we'll continue * in foreground */ daemonized = !daemonize(); } } else add_repack_all_option(); name = lock_repo_for_gc(force, &pid); if (name) { if (auto_gc) return 0; /* be quiet on --auto */ die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"), name, (uintmax_t)pid); } if (daemonized) { hold_lock_file_for_update(&log_lock, git_path("gc.log"), LOCK_DIE_ON_ERROR); dup2(get_lock_file_fd(&log_lock), 2); sigchain_push_common(process_log_file_on_signal); atexit(process_log_file_at_exit); } if (gc_before_repack()) return -1; if (!repository_format_precious_objects) { 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 (prune_worktrees_expire) { argv_array_push(&prune_worktrees, prune_worktrees_expire); if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD)) return error(FAILED_RUN, prune_worktrees.argv[0]); } if (run_command_v_opt(rerere.argv, RUN_GIT_CMD)) return error(FAILED_RUN, rerere.argv[0]); report_garbage = report_pack_garbage; reprepare_packed_git(); if (pack_garbage.nr > 0) clean_pack_garbage(); if (auto_gc && too_many_loose_objects()) warning(_("There are too many unreachable loose objects; " "run 'git prune' to remove them.")); return 0; }
int cmd_gc(int argc, const char **argv, const char *prefix) { int aggressive = 0; int auto_gc = 0; int quiet = 0; int force = 0; const char *name; pid_t pid; int daemonized = 0; int keep_base_pack = -1; timestamp_t dummy; 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_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"), PARSE_OPT_NOCOMPLETE), OPT_BOOL_F(0, "force", &force, N_("force running gc even if there may be another gc running"), PARSE_OPT_NOCOMPLETE), OPT_BOOL(0, "keep-largest-pack", &keep_base_pack, N_("repack all other packs except the largest pack")), 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(&prune_worktrees, "worktree", "prune", "--expire", NULL); argv_array_pushl(&rerere, "rerere", "gc", NULL); /* default expiry time, overwritten in gc_config */ gc_config(); if (parse_expiry_date(gc_log_expire, &gc_log_expire_time)) die(_("failed to parse gc.logexpiry value %s"), gc_log_expire); 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 (prune_expire && parse_expiry_date(prune_expire, &dummy)) die(_("failed to parse prune expiry value %s"), prune_expire); if (aggressive) { argv_array_push(&repack, "-f"); if (aggressive_depth > 0) argv_array_pushf(&repack, "--depth=%d", aggressive_depth); if (aggressive_window > 0) argv_array_pushf(&repack, "--window=%d", aggressive_window); } if (quiet) argv_array_push(&repack, "-q"); if (auto_gc) { /* * Auto-gc should be least intrusive as possible. */ if (!need_to_gc()) return 0; if (!quiet) { if (detach_auto) fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n")); else fprintf(stderr, _("Auto packing the repository for optimum performance.\n")); fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n")); } if (detach_auto) { int ret = report_last_gc_error(); if (ret < 0) /* an I/O error occured, already reported */ exit(128); if (ret == 1) /* Last gc --auto failed. Skip this one. */ return 0; if (lock_repo_for_gc(force, &pid)) return 0; gc_before_repack(); /* dies on failure */ delete_tempfile(&pidfile); /* * failure to daemonize is ok, we'll continue * in foreground */ daemonized = !daemonize(); } } else { struct string_list keep_pack = STRING_LIST_INIT_NODUP; if (keep_base_pack != -1) { if (keep_base_pack) find_base_packs(&keep_pack, 0); } else if (big_pack_threshold) { find_base_packs(&keep_pack, big_pack_threshold); } add_repack_all_option(&keep_pack); string_list_clear(&keep_pack, 0); } name = lock_repo_for_gc(force, &pid); if (name) { if (auto_gc) return 0; /* be quiet on --auto */ die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"), name, (uintmax_t)pid); } if (daemonized) { hold_lock_file_for_update(&log_lock, git_path("gc.log"), LOCK_DIE_ON_ERROR); dup2(get_lock_file_fd(&log_lock), 2); sigchain_push_common(process_log_file_on_signal); atexit(process_log_file_at_exit); } gc_before_repack(); if (!repository_format_precious_objects) { close_all_packs(the_repository->objects); if (run_command_v_opt(repack.argv, RUN_GIT_CMD)) die(FAILED_RUN, repack.argv[0]); if (prune_expire) { argv_array_push(&prune, prune_expire); if (quiet) argv_array_push(&prune, "--no-progress"); if (repository_format_partial_clone) argv_array_push(&prune, "--exclude-promisor-objects"); if (run_command_v_opt(prune.argv, RUN_GIT_CMD)) die(FAILED_RUN, prune.argv[0]); } } if (prune_worktrees_expire) { argv_array_push(&prune_worktrees, prune_worktrees_expire); if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD)) die(FAILED_RUN, prune_worktrees.argv[0]); } if (run_command_v_opt(rerere.argv, RUN_GIT_CMD)) die(FAILED_RUN, rerere.argv[0]); report_garbage = report_pack_garbage; reprepare_packed_git(the_repository); if (pack_garbage.nr > 0) clean_pack_garbage(); if (gc_write_commit_graph) write_commit_graph_reachable(get_object_directory(), 0, !quiet && !daemonized); if (auto_gc && too_many_loose_objects()) warning(_("There are too many unreachable loose objects; " "run 'git prune' to remove them.")); if (!daemonized) unlink(git_path("gc.log")); return 0; }
int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0; struct stat buf; const char *repo_name, *repo, *work_tree, *git_dir; char *path, *dir; int dest_exists; const struct ref *refs, *remote_head; const struct ref *remote_head_points_at; const struct ref *our_head_points_at; struct ref *mapped_refs; struct strbuf key = STRBUF_INIT, value = STRBUF_INIT; struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT; struct transport *transport = NULL; char *src_ref_prefix = "refs/heads/"; int err = 0; struct refspec *refspec; const char *fetch_pattern; junk_pid = getpid(); argc = parse_options(argc, argv, prefix, builtin_clone_options, builtin_clone_usage, 0); if (argc > 2) usage_msg_opt("Too many arguments.", builtin_clone_usage, builtin_clone_options); if (argc == 0) usage_msg_opt("You must specify a repository to clone.", builtin_clone_usage, builtin_clone_options); if (option_mirror) option_bare = 1; if (option_bare) { if (option_origin) die("--bare and --origin %s options are incompatible.", option_origin); option_no_checkout = 1; } if (!option_origin) option_origin = "origin"; repo_name = argv[0]; path = get_repo_path(repo_name, &is_bundle); if (path) repo = xstrdup(make_nonrelative_path(repo_name)); else if (!strchr(repo_name, ':')) repo = xstrdup(make_absolute_path(repo_name)); else repo = repo_name; if (argc == 2) dir = xstrdup(argv[1]); else dir = guess_dir_name(repo_name, is_bundle, option_bare); strip_trailing_slashes(dir); dest_exists = !stat(dir, &buf); if (dest_exists && !is_empty_dir(dir)) die("destination path '%s' already exists and is not " "an empty directory.", dir); strbuf_addf(&reflog_msg, "clone: from %s", repo); if (option_bare) work_tree = NULL; else { work_tree = getenv("GIT_WORK_TREE"); if (work_tree && !stat(work_tree, &buf)) die("working tree '%s' already exists.", work_tree); } if (option_bare || work_tree) git_dir = xstrdup(dir); else { work_tree = dir; git_dir = xstrdup(mkpath("%s/.git", dir)); } if (!option_bare) { junk_work_tree = work_tree; if (safe_create_leading_directories_const(work_tree) < 0) die_errno("could not create leading directories of '%s'", work_tree); if (!dest_exists && mkdir(work_tree, 0755)) die_errno("could not create work tree dir '%s'.", work_tree); set_git_work_tree(work_tree); } junk_git_dir = git_dir; atexit(remove_junk); sigchain_push_common(remove_junk_on_signal); setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1); if (safe_create_leading_directories_const(git_dir) < 0) die("could not create leading directories of '%s'", git_dir); set_git_dir(make_absolute_path(git_dir)); init_db(option_template, option_quiet ? INIT_DB_QUIET : 0); /* * At this point, the config exists, so we do not need the * environment variable. We actually need to unset it, too, to * re-enable parsing of the global configs. */ unsetenv(CONFIG_ENVIRONMENT); if (option_reference) setup_reference(git_dir); git_config(git_default_config, NULL); if (option_bare) { if (option_mirror) src_ref_prefix = "refs/"; strbuf_addstr(&branch_top, src_ref_prefix); git_config_set("core.bare", "true"); } else { strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin); } strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf); if (option_mirror || !option_bare) { /* Configure the remote */ strbuf_addf(&key, "remote.%s.fetch", option_origin); git_config_set_multivar(key.buf, value.buf, "^$", 0); strbuf_reset(&key); if (option_mirror) { strbuf_addf(&key, "remote.%s.mirror", option_origin); git_config_set(key.buf, "true"); strbuf_reset(&key); } strbuf_addf(&key, "remote.%s.url", option_origin); git_config_set(key.buf, repo); strbuf_reset(&key); } fetch_pattern = value.buf; refspec = parse_fetch_refspec(1, &fetch_pattern); strbuf_reset(&value); if (path && !is_bundle) { refs = clone_local(path, git_dir); mapped_refs = wanted_peer_refs(refs, refspec); } else { struct remote *remote = remote_get(argv[0]); transport = transport_get(remote, remote->url[0]); if (!transport->get_refs_list || !transport->fetch) die("Don't know how to clone %s", transport->url); transport_set_option(transport, TRANS_OPT_KEEP, "yes"); if (option_depth) transport_set_option(transport, TRANS_OPT_DEPTH, option_depth); if (option_quiet) transport->verbose = -1; else if (option_verbose) transport->verbose = 1; if (option_progress) transport->progress = 1; if (option_upload_pack) transport_set_option(transport, TRANS_OPT_UPLOADPACK, option_upload_pack); refs = transport_get_remote_refs(transport); if (refs) { mapped_refs = wanted_peer_refs(refs, refspec); transport_fetch_refs(transport, mapped_refs); } } if (refs) { clear_extra_refs(); write_remote_refs(mapped_refs); remote_head = find_ref_by_name(refs, "HEAD"); remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0); if (option_branch) { struct strbuf head = STRBUF_INIT; strbuf_addstr(&head, src_ref_prefix); strbuf_addstr(&head, option_branch); our_head_points_at = find_ref_by_name(mapped_refs, head.buf); strbuf_release(&head); if (!our_head_points_at) { warning("Remote branch %s not found in " "upstream %s, using HEAD instead", option_branch, option_origin); our_head_points_at = remote_head_points_at; } } else our_head_points_at = remote_head_points_at; } else { warning("You appear to have cloned an empty repository."); our_head_points_at = NULL; remote_head_points_at = NULL; remote_head = NULL; option_no_checkout = 1; if (!option_bare) install_branch_config(0, "master", option_origin, "refs/heads/master"); } if (remote_head_points_at && !option_bare) { struct strbuf head_ref = STRBUF_INIT; strbuf_addstr(&head_ref, branch_top.buf); strbuf_addstr(&head_ref, "HEAD"); create_symref(head_ref.buf, remote_head_points_at->peer_ref->name, reflog_msg.buf); } if (our_head_points_at) { /* Local default branch link */ create_symref("HEAD", our_head_points_at->name, NULL); if (!option_bare) { const char *head = skip_prefix(our_head_points_at->name, "refs/heads/"); update_ref(reflog_msg.buf, "HEAD", our_head_points_at->old_sha1, NULL, 0, DIE_ON_ERR); install_branch_config(0, head, option_origin, our_head_points_at->name); } } else if (remote_head) { /* Source had detached HEAD pointing somewhere. */ if (!option_bare) { update_ref(reflog_msg.buf, "HEAD", remote_head->old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); our_head_points_at = remote_head; } } else { /* Nothing to checkout out */ if (!option_no_checkout) warning("remote HEAD refers to nonexistent ref, " "unable to checkout.\n"); option_no_checkout = 1; } if (transport) { transport_unlock_pack(transport); transport_disconnect(transport); } if (!option_no_checkout) { struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); struct unpack_trees_options opts; struct tree *tree; struct tree_desc t; int fd; /* We need to be in the new work tree for the checkout */ setup_work_tree(); fd = hold_locked_index(lock_file, 1); memset(&opts, 0, sizeof opts); opts.update = 1; opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = !option_quiet; opts.src_index = &the_index; opts.dst_index = &the_index; tree = parse_tree_indirect(our_head_points_at->old_sha1); parse_tree(tree); init_tree_desc(&t, tree->buffer, tree->size); unpack_trees(1, &t, &opts); if (write_cache(fd, active_cache, active_nr) || commit_locked_index(lock_file)) die("unable to write new index file"); err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1), sha1_to_hex(our_head_points_at->old_sha1), "1", NULL); if (!err && option_recursive) err = run_command_v_opt(argv_submodule, RUN_GIT_CMD); } strbuf_release(&reflog_msg); strbuf_release(&branch_top); strbuf_release(&key); strbuf_release(&value); junk_pid = 0; return err; }
static int try_merge_strategy(const char *strategy, struct commit_list *common, const char *head_arg) { const char **args; int i = 0, ret; struct commit_list *j; struct strbuf buf = STRBUF_INIT; int index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); index_fd = hold_locked_index(lock, 1); refresh_cache(REFRESH_QUIET); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) return error("Unable to write index."); rollback_lock_file(lock); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { int clean; struct commit *result; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; struct commit_list *reversed = NULL; struct merge_options o; if (remoteheads->next) { error("Not handling anything other than two heads merge."); return 2; } init_merge_options(&o); if (!strcmp(strategy, "subtree")) o.subtree_merge = 1; o.branch1 = head_arg; o.branch2 = remoteheads->item->util; for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); index_fd = hold_locked_index(lock, 1); clean = merge_recursive(&o, lookup_commit(head), remoteheads->item, reversed, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) die ("unable to write %s", get_index_file()); rollback_lock_file(lock); return clean ? 0 : 1; } else { args = xmalloc((4 + commit_list_count(common) + commit_list_count(remoteheads)) * sizeof(char *)); strbuf_addf(&buf, "merge-%s", strategy); args[i++] = buf.buf; for (j = common; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i++] = "--"; args[i++] = head_arg; for (j = remoteheads; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i] = NULL; ret = run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&buf); i = 1; for (j = common; j; j = j->next) free((void *)args[i++]); i += 2; for (j = remoteheads; j; j = j->next) free((void *)args[i++]); free(args); discard_cache(); if (read_cache() < 0) die("failed to read the cache"); return ret; } }
static const char *unpack(void) { struct pack_header hdr; const char *hdr_err; char hdr_arg[38]; int fsck_objects = (receive_fsck_objects >= 0 ? receive_fsck_objects : transfer_fsck_objects >= 0 ? transfer_fsck_objects : 0); hdr_err = parse_pack_header(&hdr); if (hdr_err) return hdr_err; snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { int code, i = 0; const char *unpacker[4]; unpacker[i++] = "unpack-objects"; if (fsck_objects) unpacker[i++] = "--strict"; unpacker[i++] = hdr_arg; unpacker[i++] = NULL; code = run_command_v_opt(unpacker, RUN_GIT_CMD); if (!code) return NULL; return "unpack-objects abnormal exit"; } else { const char *keeper[7]; int s, status, i = 0; char keep_arg[256]; struct child_process ip; s = sprintf(keep_arg, "--keep=receive-pack %"PRIuMAX" on ", (uintmax_t) getpid()); if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); keeper[i++] = "index-pack"; keeper[i++] = "--stdin"; if (fsck_objects) keeper[i++] = "--strict"; keeper[i++] = "--fix-thin"; keeper[i++] = hdr_arg; keeper[i++] = keep_arg; keeper[i++] = NULL; memset(&ip, 0, sizeof(ip)); ip.argv = keeper; ip.out = -1; ip.git_cmd = 1; status = start_command(&ip); if (status) { return "index-pack fork failed"; } pack_lockfile = index_pack_lockfile(ip.out); close(ip.out); status = finish_command(&ip); if (!status) { reprepare_packed_git(); return NULL; } return "index-pack abnormal exit"; } }
int cmd_receive_pack(int argc, const char **argv, const char *prefix) { int advertise_refs = 0; int stateless_rpc = 0; int i; char *dir = NULL; struct command *commands; packet_trace_identity("receive-pack"); argv++; for (i = 1; i < argc; i++) { const char *arg = *argv++; if (*arg == '-') { if (!strcmp(arg, "--advertise-refs")) { advertise_refs = 1; continue; } if (!strcmp(arg, "--stateless-rpc")) { stateless_rpc = 1; continue; } usage(receive_pack_usage); } if (dir) usage(receive_pack_usage); dir = xstrdup(arg); } if (!dir) usage(receive_pack_usage); setup_path(); if (!enter_repo(dir, 0)) die("'%s' does not appear to be a git repository", dir); if (is_repository_shallow()) die("attempt to push into a shallow repository"); git_config(receive_pack_config, NULL); if (0 <= transfer_unpack_limit) unpack_limit = transfer_unpack_limit; else if (0 <= receive_unpack_limit) unpack_limit = receive_unpack_limit; if (advertise_refs || !stateless_rpc) { write_head_info(); } if (advertise_refs) return 0; if ((commands = read_head_info()) != NULL) { const char *unpack_status = NULL; if (!delete_only(commands)) unpack_status = unpack(); execute_commands(commands, unpack_status); if (pack_lockfile) unlink_or_warn(pack_lockfile); if (report_status) report(commands, unpack_status); run_receive_hook(commands, post_receive_hook, 1); run_update_post_hook(commands); if (auto_gc) { const char *argv_gc_auto[] = { "gc", "--auto", "--quiet", NULL, }; run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); } if (auto_update_server_info) update_server_info(0); } if (use_sideband) packet_flush(1); return 0; }
/* * User defined low-level merge driver support. */ static int ll_ext_merge(const struct ll_merge_driver *fn, mmbuffer_t *result, const char *path, mmfile_t *orig, const char *orig_name, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, const struct ll_merge_options *opts, int marker_size) { char temp[4][50]; struct strbuf cmd = STRBUF_INIT; struct strbuf_expand_dict_entry dict[6]; struct strbuf path_sq = STRBUF_INIT; const char *args[] = { NULL, NULL }; int status, fd, i; struct stat st; assert(opts); sq_quote_buf(&path_sq, path); dict[0].placeholder = "O"; dict[0].value = temp[0]; dict[1].placeholder = "A"; dict[1].value = temp[1]; dict[2].placeholder = "B"; dict[2].value = temp[2]; dict[3].placeholder = "L"; dict[3].value = temp[3]; dict[4].placeholder = "P"; dict[4].value = path_sq.buf; dict[5].placeholder = NULL; dict[5].value = NULL; if (fn->cmdline == NULL) die("custom merge driver %s lacks command line.", fn->name); result->ptr = NULL; result->size = 0; create_temp(orig, temp[0], sizeof(temp[0])); create_temp(src1, temp[1], sizeof(temp[1])); create_temp(src2, temp[2], sizeof(temp[2])); xsnprintf(temp[3], sizeof(temp[3]), "%d", marker_size); strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict); args[0] = cmd.buf; status = run_command_v_opt(args, RUN_USING_SHELL); fd = open(temp[1], O_RDONLY); if (fd < 0) goto bad; if (fstat(fd, &st)) goto close_bad; result->size = st.st_size; result->ptr = xmalloc(result->size + 1); if (read_in_full(fd, result->ptr, result->size) != result->size) { free(result->ptr); result->ptr = NULL; result->size = 0; } close_bad: close(fd); bad: for (i = 0; i < 3; i++) unlink_or_warn(temp[i]); strbuf_release(&cmd); strbuf_release(&path_sq); return status; }
static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, int argc, const char **argv) { char tmpdir[PATH_MAX]; struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT; struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT; struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT; struct strbuf wtdir = STRBUF_INIT; char *lbase_dir, *rbase_dir; size_t ldir_len, rdir_len, wtdir_len; const char *workdir, *tmp; int ret = 0, i; FILE *fp; struct hashmap working_tree_dups, submodules, symlinks2; struct hashmap_iter iter; struct pair_entry *entry; struct index_state wtindex; struct checkout lstate, rstate; int rc, flags = RUN_GIT_CMD, err = 0; struct child_process child = CHILD_PROCESS_INIT; const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL }; struct hashmap wt_modified, tmp_modified; int indices_loaded = 0; workdir = get_git_work_tree(); /* Setup temp directories */ tmp = getenv("TMPDIR"); xsnprintf(tmpdir, sizeof(tmpdir), "%s/git-difftool.XXXXXX", tmp ? tmp : "/tmp"); if (!mkdtemp(tmpdir)) return error("could not create '%s'", tmpdir); strbuf_addf(&ldir, "%s/left/", tmpdir); strbuf_addf(&rdir, "%s/right/", tmpdir); strbuf_addstr(&wtdir, workdir); if (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1])) strbuf_addch(&wtdir, '/'); mkdir(ldir.buf, 0700); mkdir(rdir.buf, 0700); memset(&wtindex, 0, sizeof(wtindex)); memset(&lstate, 0, sizeof(lstate)); lstate.base_dir = lbase_dir = xstrdup(ldir.buf); lstate.base_dir_len = ldir.len; lstate.force = 1; memset(&rstate, 0, sizeof(rstate)); rstate.base_dir = rbase_dir = xstrdup(rdir.buf); rstate.base_dir_len = rdir.len; rstate.force = 1; ldir_len = ldir.len; rdir_len = rdir.len; wtdir_len = wtdir.len; hashmap_init(&working_tree_dups, (hashmap_cmp_fn)working_tree_entry_cmp, NULL, 0); hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, NULL, 0); hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, NULL, 0); child.no_stdin = 1; child.git_cmd = 1; child.use_shell = 0; child.clean_on_exit = 1; child.dir = prefix; child.out = -1; argv_array_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z", NULL); for (i = 0; i < argc; i++) argv_array_push(&child.args, argv[i]); if (start_command(&child)) die("could not obtain raw diff"); fp = xfdopen(child.out, "r"); /* Build index info for left and right sides of the diff */ i = 0; while (!strbuf_getline_nul(&info, fp)) { int lmode, rmode; struct object_id loid, roid; char status; const char *src_path, *dst_path; if (starts_with(info.buf, "::")) die(N_("combined diff formats('-c' and '--cc') are " "not supported in\n" "directory diff mode('-d' and '--dir-diff').")); if (parse_index_info(info.buf, &lmode, &rmode, &loid, &roid, &status)) break; if (strbuf_getline_nul(&lpath, fp)) break; src_path = lpath.buf; i++; if (status != 'C' && status != 'R') { dst_path = src_path; } else { if (strbuf_getline_nul(&rpath, fp)) break; dst_path = rpath.buf; } if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) { strbuf_reset(&buf); strbuf_addf(&buf, "Subproject commit %s", oid_to_hex(&loid)); add_left_or_right(&submodules, src_path, buf.buf, 0); strbuf_reset(&buf); strbuf_addf(&buf, "Subproject commit %s", oid_to_hex(&roid)); if (!oidcmp(&loid, &roid)) strbuf_addstr(&buf, "-dirty"); add_left_or_right(&submodules, dst_path, buf.buf, 1); continue; } if (S_ISLNK(lmode)) { char *content = get_symlink(&loid, src_path); add_left_or_right(&symlinks2, src_path, content, 0); free(content); } if (S_ISLNK(rmode)) { char *content = get_symlink(&roid, dst_path); add_left_or_right(&symlinks2, dst_path, content, 1); free(content); } if (lmode && status != 'C') { if (checkout_path(lmode, &loid, src_path, &lstate)) { ret = error("could not write '%s'", src_path); goto finish; } } if (rmode && !S_ISLNK(rmode)) { struct working_tree_entry *entry; /* Avoid duplicate working_tree entries */ FLEX_ALLOC_STR(entry, path, dst_path); hashmap_entry_init(entry, strhash(dst_path)); if (hashmap_get(&working_tree_dups, entry, NULL)) { free(entry); continue; } hashmap_add(&working_tree_dups, entry); if (!use_wt_file(workdir, dst_path, &roid)) { if (checkout_path(rmode, &roid, dst_path, &rstate)) { ret = error("could not write '%s'", dst_path); goto finish; } } else if (!is_null_oid(&roid)) { /* * Changes in the working tree need special * treatment since they are not part of the * index. */ struct cache_entry *ce2 = make_cache_entry(rmode, roid.hash, dst_path, 0, 0); add_index_entry(&wtindex, ce2, ADD_CACHE_JUST_APPEND); add_path(&rdir, rdir_len, dst_path); if (ensure_leading_directories(rdir.buf)) { ret = error("could not create " "directory for '%s'", dst_path); goto finish; } add_path(&wtdir, wtdir_len, dst_path); if (symlinks) { if (symlink(wtdir.buf, rdir.buf)) { ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf); goto finish; } } else { struct stat st; if (stat(wtdir.buf, &st)) st.st_mode = 0644; if (copy_file(rdir.buf, wtdir.buf, st.st_mode)) { ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf); goto finish; } } } } } fclose(fp); fp = NULL; if (finish_command(&child)) { ret = error("error occurred running diff --raw"); goto finish; } if (!i) goto finish; /* * Changes to submodules require special treatment.This loop writes a * temporary file to both the left and right directories to show the * change in the recorded SHA1 for the submodule. */ hashmap_iter_init(&submodules, &iter); while ((entry = hashmap_iter_next(&iter))) { if (*entry->left) { add_path(&ldir, ldir_len, entry->path); ensure_leading_directories(ldir.buf); write_file(ldir.buf, "%s", entry->left); } if (*entry->right) { add_path(&rdir, rdir_len, entry->path); ensure_leading_directories(rdir.buf); write_file(rdir.buf, "%s", entry->right); } } /* * Symbolic links require special treatment.The standard "git diff" * shows only the link itself, not the contents of the link target. * This loop replicates that behavior. */ hashmap_iter_init(&symlinks2, &iter); while ((entry = hashmap_iter_next(&iter))) { if (*entry->left) { add_path(&ldir, ldir_len, entry->path); ensure_leading_directories(ldir.buf); write_file(ldir.buf, "%s", entry->left); } if (*entry->right) { add_path(&rdir, rdir_len, entry->path); ensure_leading_directories(rdir.buf); write_file(rdir.buf, "%s", entry->right); } } strbuf_release(&buf); strbuf_setlen(&ldir, ldir_len); helper_argv[1] = ldir.buf; strbuf_setlen(&rdir, rdir_len); helper_argv[2] = rdir.buf; if (extcmd) { helper_argv[0] = extcmd; flags = 0; } else setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1); rc = run_command_v_opt(helper_argv, flags); /* * If the diff includes working copy files and those * files were modified during the diff, then the changes * should be copied back to the working tree. * Do not copy back files when symlinks are used and the * external tool did not replace the original link with a file. * * These hashes are loaded lazily since they aren't needed * in the common case of --symlinks and the difftool updating * files through the symlink. */ hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp, NULL, wtindex.cache_nr); hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp, NULL, wtindex.cache_nr); for (i = 0; i < wtindex.cache_nr; i++) { struct hashmap_entry dummy; const char *name = wtindex.cache[i]->name; struct stat st; add_path(&rdir, rdir_len, name); if (lstat(rdir.buf, &st)) continue; if ((symlinks && S_ISLNK(st.st_mode)) || !S_ISREG(st.st_mode)) continue; if (!indices_loaded) { static struct lock_file lock; strbuf_reset(&buf); strbuf_addf(&buf, "%s/wtindex", tmpdir); if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 || write_locked_index(&wtindex, &lock, COMMIT_LOCK)) { ret = error("could not write %s", buf.buf); rollback_lock_file(&lock); goto finish; } changed_files(&wt_modified, buf.buf, workdir); strbuf_setlen(&rdir, rdir_len); changed_files(&tmp_modified, buf.buf, rdir.buf); add_path(&rdir, rdir_len, name); indices_loaded = 1; } hashmap_entry_init(&dummy, strhash(name)); if (hashmap_get(&tmp_modified, &dummy, name)) { add_path(&wtdir, wtdir_len, name); if (hashmap_get(&wt_modified, &dummy, name)) { warning(_("both files modified: '%s' and '%s'."), wtdir.buf, rdir.buf); warning(_("working tree file has been left.")); warning("%s", ""); err = 1; } else if (unlink(wtdir.buf) || copy_file(wtdir.buf, rdir.buf, st.st_mode)) warning_errno(_("could not copy '%s' to '%s'"), rdir.buf, wtdir.buf); } } if (err) { warning(_("temporary files exist in '%s'."), tmpdir); warning(_("you may want to cleanup or recover these.")); exit(1); } else exit_cleanup(tmpdir, rc); finish: if (fp) fclose(fp); free(lbase_dir); free(rbase_dir); strbuf_release(&ldir); strbuf_release(&rdir); strbuf_release(&wtdir); strbuf_release(&buf); return ret; }
static int print_tool_help(void) { const char *argv[] = { "mergetool", "--tool-help=diff", NULL }; return run_command_v_opt(argv, RUN_GIT_CMD); }
static int checkout(int submodule_progress) { unsigned char sha1[20]; char *head; struct lock_file *lock_file; struct unpack_trees_options opts; struct tree *tree; struct tree_desc t; int err = 0; if (option_no_checkout) return 0; head = resolve_refdup("HEAD", RESOLVE_REF_READING, sha1, NULL); if (!head) { warning(_("remote HEAD refers to nonexistent ref, " "unable to checkout.\n")); return 0; } if (!strcmp(head, "HEAD")) { if (advice_detached_head) detach_advice(sha1_to_hex(sha1)); } else { if (!starts_with(head, "refs/heads/")) die(_("HEAD not found below refs/heads!")); } free(head); /* We need to be in the new work tree for the checkout */ setup_work_tree(); lock_file = xcalloc(1, sizeof(struct lock_file)); hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); memset(&opts, 0, sizeof opts); opts.update = 1; opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = (option_verbosity >= 0); opts.src_index = &the_index; opts.dst_index = &the_index; tree = parse_tree_indirect(sha1); parse_tree(tree); init_tree_desc(&t, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts) < 0) die(_("unable to checkout working tree")); if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1), sha1_to_hex(sha1), "1", NULL); if (!err && option_recursive) { struct argv_array args = ARGV_ARRAY_INIT; argv_array_pushl(&args, "submodule", "update", "--init", "--recursive", NULL); if (option_shallow_submodules == 1) argv_array_push(&args, "--depth=1"); if (max_jobs != -1) argv_array_pushf(&args, "--jobs=%d", max_jobs); if (submodule_progress) argv_array_push(&args, "--progress"); err = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); } return err; }
int cmd_gc(int argc, const char **argv, const char *prefix) { int prune = 0; int aggressive = 0; int auto_gc = 0; int quiet = 0; char buf[80]; struct option builtin_gc_options[] = { OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects (deprecated)"), 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, 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); 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 your repository for optimum " "performance. You may also\n" "run \"git gc\" manually. See " "\"git help gc\" for more information.\n"); } else append_option(argv_repack, "-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]); 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; }
/** * Runs git-fetch, returning its exit status. `repo` and `refspecs` are the * repository and refspecs to fetch, or NULL if they are not provided. */ static int run_fetch(const char *repo, const char **refspecs) { struct argv_array args = ARGV_ARRAY_INIT; int ret; argv_array_pushl(&args, "fetch", "--update-head-ok", NULL); /* Shared options */ argv_push_verbosity(&args); if (opt_progress) argv_array_push(&args, opt_progress); /* Options passed to git-fetch */ if (opt_all) argv_array_push(&args, opt_all); if (opt_append) argv_array_push(&args, opt_append); if (opt_upload_pack) argv_array_push(&args, opt_upload_pack); argv_push_force(&args); if (opt_tags) argv_array_push(&args, opt_tags); if (opt_prune) argv_array_push(&args, opt_prune); if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) switch (recurse_submodules) { case RECURSE_SUBMODULES_ON: argv_array_push(&args, "--recurse-submodules=on"); break; case RECURSE_SUBMODULES_OFF: argv_array_push(&args, "--recurse-submodules=no"); break; case RECURSE_SUBMODULES_ON_DEMAND: argv_array_push(&args, "--recurse-submodules=on-demand"); break; default: BUG("submodule recursion option not understood"); } if (max_children) argv_array_push(&args, max_children); if (opt_dry_run) argv_array_push(&args, "--dry-run"); if (opt_keep) argv_array_push(&args, opt_keep); if (opt_depth) argv_array_push(&args, opt_depth); if (opt_unshallow) argv_array_push(&args, opt_unshallow); if (opt_update_shallow) argv_array_push(&args, opt_update_shallow); if (opt_refmap) argv_array_push(&args, opt_refmap); if (opt_ipv4) argv_array_push(&args, opt_ipv4); if (opt_ipv6) argv_array_push(&args, opt_ipv6); if (repo) { argv_array_push(&args, repo); argv_array_pushv(&args, refspecs); } else if (*refspecs) BUG("refspecs without repo?"); ret = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); return ret; }