static void finish(struct commit *head_commit, struct commit_list *remoteheads, const unsigned char *new_head, const char *msg) { struct strbuf reflog_message = STRBUF_INIT; const unsigned char *head = head_commit->object.oid.hash; if (!msg) strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION")); else { if (verbosity >= 0) printf("%s\n", msg); strbuf_addf(&reflog_message, "%s: %s", getenv("GIT_REFLOG_ACTION"), msg); } if (squash) { squash_message(head_commit, remoteheads); } else { if (verbosity >= 0 && !merge_msg.len) printf(_("No merge message -- not updating HEAD\n")); else { const char *argv_gc_auto[] = { "gc", "--auto", NULL }; update_ref(reflog_message.buf, "HEAD", new_head, head, 0, UPDATE_REFS_DIE_ON_ERR); /* * We ignore errors in 'gc --auto', since the * user should see them. */ close_all_packs(); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); } } if (new_head && show_diffstat) { struct diff_options opts; diff_setup(&opts); opts.stat_width = -1; /* use full terminal width */ opts.stat_graph_width = -1; /* respect statGraphWidth config */ opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; diff_setup_done(&opts); diff_tree_sha1(head, new_head, "", &opts); diffcore_std(&opts); diff_flush(&opts); } /* Run a post-merge hook */ run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL); strbuf_release(&reflog_message); }
void raw_object_store_clear(struct raw_object_store *o) { FREE_AND_NULL(o->objectdir); FREE_AND_NULL(o->alternate_db); oidmap_free(o->replace_map, 1); FREE_AND_NULL(o->replace_map); free_alt_odbs(o); o->alt_odb_tail = NULL; INIT_LIST_HEAD(&o->packed_git_mru); close_all_packs(o); o->packed_git = NULL; }
int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0, is_local; 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; const struct ref *ref; struct strbuf key = STRBUF_INIT, value = STRBUF_INIT; struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT; struct transport *transport = NULL; const char *src_ref_prefix = "refs/heads/"; struct remote *remote; int err = 0, complete_refs_before_fetch = 1; int submodule_progress; struct refspec *refspec; const char *fetch_pattern; packet_trace_identity("clone"); 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_depth || option_since || option_not.nr) deepen = 1; if (option_single_branch == -1) option_single_branch = deepen ? 1 : 0; if (option_mirror) option_bare = 1; if (option_bare) { if (option_origin) die(_("--bare and --origin %s options are incompatible."), option_origin); if (real_git_dir) die(_("--bare and --separate-git-dir are incompatible.")); 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(absolute_path(repo_name)); else if (!strchr(repo_name, ':')) die(_("repository '%s' does not exist"), repo_name); else repo = repo_name; /* no need to be strict, transport_set_option() will validate it again */ if (option_depth && atoi(option_depth) < 1) die(_("depth %s is not a positive number"), option_depth); 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 = mkpathdup("%s/.git", dir); } atexit(remove_junk); sigchain_push_common(remove_junk_on_signal); if (!option_bare) { 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, 0777)) die_errno(_("could not create work tree dir '%s'"), work_tree); junk_work_tree = work_tree; set_git_work_tree(work_tree); } junk_git_dir = real_git_dir ? real_git_dir : git_dir; if (safe_create_leading_directories_const(git_dir) < 0) die(_("could not create leading directories of '%s'"), git_dir); if (0 <= option_verbosity) { if (option_bare) fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir); else fprintf(stderr, _("Cloning into '%s'...\n"), dir); } if (option_recursive) { if (option_required_reference.nr && option_optional_reference.nr) die(_("clone --recursive is not compatible with " "both --reference and --reference-if-able")); else if (option_required_reference.nr) { string_list_append(&option_config, "submodule.alternateLocation=superproject"); string_list_append(&option_config, "submodule.alternateErrorStrategy=die"); } else if (option_optional_reference.nr) { string_list_append(&option_config, "submodule.alternateLocation=superproject"); string_list_append(&option_config, "submodule.alternateErrorStrategy=info"); } } init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET); if (real_git_dir) git_dir = real_git_dir; write_config(&option_config); 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); strbuf_addf(&key, "remote.%s.url", option_origin); git_config_set(key.buf, repo); strbuf_reset(&key); if (option_required_reference.nr || option_optional_reference.nr) setup_reference(); fetch_pattern = value.buf; refspec = parse_fetch_refspec(1, &fetch_pattern); strbuf_reset(&value); remote = remote_get(option_origin); transport = transport_get(remote, remote->url[0]); transport_set_verbosity(transport, option_verbosity, option_progress); transport->family = family; path = get_repo_path(remote->url[0], &is_bundle); is_local = option_local != 0 && path && !is_bundle; if (is_local) { if (option_depth) warning(_("--depth is ignored in local clones; use file:// instead.")); if (option_since) warning(_("--shallow-since is ignored in local clones; use file:// instead.")); if (option_not.nr) warning(_("--shallow-exclude is ignored in local clones; use file:// instead.")); if (!access(mkpath("%s/shallow", path), F_OK)) { if (option_local > 0) warning(_("source repository is shallow, ignoring --local")); is_local = 0; } } if (option_local > 0 && !is_local) warning(_("--local is ignored")); transport->cloning = 1; if (!transport->get_refs_list || (!is_local && !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_since) transport_set_option(transport, TRANS_OPT_DEEPEN_SINCE, option_since); if (option_not.nr) transport_set_option(transport, TRANS_OPT_DEEPEN_NOT, (const char *)&option_not); if (option_single_branch) transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1"); if (option_upload_pack) transport_set_option(transport, TRANS_OPT_UPLOADPACK, option_upload_pack); if (transport->smart_options && !deepen) transport->smart_options->check_self_contained_and_connected = 1; refs = transport_get_remote_refs(transport); if (refs) { mapped_refs = wanted_peer_refs(refs, refspec); /* * transport_get_remote_refs() may return refs with null sha-1 * in mapped_refs (see struct transport->get_refs_list * comment). In that case we need fetch it early because * remote_head code below relies on it. * * for normal clones, transport_get_remote_refs() should * return reliable ref set, we can delay cloning until after * remote HEAD check. */ for (ref = refs; ref; ref = ref->next) if (is_null_oid(&ref->old_oid)) { complete_refs_before_fetch = 0; break; } if (!is_local && !complete_refs_before_fetch) transport_fetch_refs(transport, 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) { our_head_points_at = find_remote_branch(mapped_refs, option_branch); if (!our_head_points_at) die(_("Remote branch %s not found in upstream %s"), option_branch, option_origin); } else our_head_points_at = remote_head_points_at; } else { if (option_branch) die(_("Remote branch %s not found in upstream %s"), option_branch, option_origin); warning(_("You appear to have cloned an empty repository.")); mapped_refs = NULL; 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"); } write_refspec_config(src_ref_prefix, our_head_points_at, remote_head_points_at, &branch_top); if (is_local) clone_local(path, git_dir); else if (refs && complete_refs_before_fetch) transport_fetch_refs(transport, mapped_refs); update_remote_refs(refs, mapped_refs, remote_head_points_at, branch_top.buf, reflog_msg.buf, transport, !is_local); update_head(our_head_points_at, remote_head, reflog_msg.buf); /* * We want to show progress for recursive submodule clones iff * we did so for the main clone. But only the transport knows * the final decision for this flag, so we need to rescue the value * before we free the transport. */ submodule_progress = transport->progress; transport_unlock_pack(transport); transport_disconnect(transport); if (option_dissociate) { close_all_packs(); dissociate_from_references(); } junk_mode = JUNK_LEAVE_REPO; err = checkout(submodule_progress); strbuf_release(&reflog_msg); strbuf_release(&branch_top); strbuf_release(&key); strbuf_release(&value); junk_mode = JUNK_LEAVE_ALL; free(refspec); return err; }
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_receive_pack(int argc, const char **argv, const char *prefix) { int advertise_refs = 0; struct command *commands; struct sha1_array shallow = SHA1_ARRAY_INIT; struct sha1_array ref = SHA1_ARRAY_INIT; struct shallow_info si; struct option options[] = { OPT__QUIET(&quiet, N_("quiet")), OPT_HIDDEN_BOOL(0, "stateless-rpc", &stateless_rpc, NULL), OPT_HIDDEN_BOOL(0, "advertise-refs", &advertise_refs, NULL), OPT_HIDDEN_BOOL(0, "reject-thin-pack-for-testing", &reject_thin, NULL), OPT_END() }; packet_trace_identity("receive-pack"); argc = parse_options(argc, argv, prefix, options, receive_pack_usage, 0); if (argc > 1) usage_msg_opt(_("Too many arguments."), receive_pack_usage, options); if (argc == 0) usage_msg_opt(_("You must specify a directory."), receive_pack_usage, options); service_dir = argv[0]; setup_path(); if (!enter_repo(service_dir, 0)) die("'%s' does not appear to be a git repository", service_dir); git_config(receive_pack_config, NULL); if (cert_nonce_seed) push_cert_nonce = prepare_push_cert_nonce(service_dir, time(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(&shallow)) != NULL) { const char *unpack_status = NULL; struct string_list push_options = STRING_LIST_INIT_DUP; if (use_push_options) read_push_options(&push_options); prepare_shallow_info(&si, &shallow); if (!si.nr_ours && !si.nr_theirs) shallow_update = 0; if (!delete_only(commands)) { unpack_status = unpack_with_sideband(&si); update_shallow_info(commands, &si, &ref); } use_keepalive = KEEPALIVE_ALWAYS; execute_commands(commands, unpack_status, &si, &push_options); if (pack_lockfile) unlink_or_warn(pack_lockfile); if (report_status) report(commands, unpack_status); run_receive_hook(commands, "post-receive", 1, &push_options); run_update_post_hook(commands); if (push_options.nr) string_list_clear(&push_options, 0); if (auto_gc) { const char *argv_gc_auto[] = { "gc", "--auto", "--quiet", NULL, }; struct child_process proc = CHILD_PROCESS_INIT; proc.no_stdin = 1; proc.stdout_to_stderr = 1; proc.err = use_sideband ? -1 : 0; proc.git_cmd = 1; proc.argv = argv_gc_auto; close_all_packs(); if (!start_command(&proc)) { if (use_sideband) copy_to_sideband(proc.err, -1, NULL); finish_command(&proc); } } if (auto_update_server_info) update_server_info(0); clear_shallow_info(&si); } if (use_sideband) packet_flush(1); sha1_array_clear(&shallow); sha1_array_clear(&ref); free((void *)push_cert_nonce); 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) { close_all_packs(); 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; }