struct ref *fetch_pack(struct fetch_pack_args *args, int fd[], struct child_process *conn, const struct ref *ref, const char *dest, struct ref **sought, int nr_sought, char **pack_lockfile) { struct ref *ref_cpy; fetch_pack_setup(); if (nr_sought) nr_sought = remove_duplicates_in_refs(sought, nr_sought); if (!ref) { packet_flush(fd[1]); die("no matching remote head"); } ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile); if (args->depth > 0 && alternate_shallow_file) { if (*alternate_shallow_file == '\0') { /* --unshallow */ unlink_or_warn(git_path("shallow")); rollback_lock_file(&shallow_lock); } else commit_lock_file(&shallow_lock); } reprepare_packed_git(); return ref_cpy; }
struct ref *fetch_pack(struct fetch_pack_args *my_args, int fd[], struct child_process *conn, const struct ref *ref, const char *dest, int nr_heads, char **heads, char **pack_lockfile) { struct stat st; struct ref *ref_cpy; fetch_pack_setup(); if (&args != my_args) memcpy(&args, my_args, sizeof(args)); if (args.depth > 0) { if (stat(git_path("shallow"), &st)) st.st_mtime = 0; } if (heads && nr_heads) nr_heads = remove_duplicates(nr_heads, heads); if (!ref) { packet_flush(fd[1]); die("no matching remote head"); } ref_cpy = do_fetch_pack(fd, ref, nr_heads, heads, pack_lockfile); if (args.depth > 0) { struct cache_time mtime; struct strbuf sb = STRBUF_INIT; char *shallow = git_path("shallow"); int fd; mtime.sec = st.st_mtime; mtime.nsec = ST_MTIME_NSEC(st); if (stat(shallow, &st)) { if (mtime.sec) die("shallow file was removed during fetch"); } else if (st.st_mtime != mtime.sec #ifdef USE_NSEC || ST_MTIME_NSEC(st) != mtime.nsec #endif ) die("shallow file was changed during fetch"); fd = hold_lock_file_for_update(&lock, shallow, LOCK_DIE_ON_ERROR); if (!write_shallow_commits(&sb, 0) || write_in_full(fd, sb.buf, sb.len) != sb.len) { unlink_or_warn(shallow); rollback_lock_file(&lock); } else { commit_lock_file(&lock); } strbuf_release(&sb); } reprepare_packed_git(); return ref_cpy; }
struct ref *fetch_pack(struct fetch_pack_args *args, int fd[], struct child_process *conn, const struct ref *ref, const char *dest, struct ref **sought, int nr_sought, struct sha1_array *shallow, char **pack_lockfile) { struct ref *ref_cpy; struct shallow_info si; fetch_pack_setup(); if (nr_sought) nr_sought = remove_duplicates_in_refs(sought, nr_sought); if (!ref) { packet_flush(fd[1]); die("no matching remote head"); } prepare_shallow_info(&si, shallow); ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, &si, pack_lockfile); reprepare_packed_git(); update_shallow(args, sought, nr_sought, &si); clear_shallow_info(&si); return ref_cpy; }
struct ref *fetch_pack(struct fetch_pack_args *my_args, int fd[], struct child_process *conn, const struct ref *ref, const char *dest, int nr_heads, char **heads, char **pack_lockfile) { struct stat st; struct ref *ref_cpy; fetch_pack_setup(); memcpy(&args, my_args, sizeof(args)); if (args.depth > 0) { if (stat(git_path("shallow"), &st)) st.st_mtime = 0; } if (heads && nr_heads) nr_heads = remove_duplicates(nr_heads, heads); if (!ref) { packet_flush(fd[1]); die("no matching remote head"); } ref_cpy = do_fetch_pack(fd, ref, nr_heads, heads, pack_lockfile); if (args.depth > 0) { struct cache_time mtime; char *shallow = git_path("shallow"); int fd; mtime.sec = st.st_mtime; #ifdef USE_NSEC mtime.usec = st.st_mtim.usec; #endif if (stat(shallow, &st)) { if (mtime.sec) die("shallow file was removed during fetch"); } else if (st.st_mtime != mtime.sec #ifdef USE_NSEC || st.st_mtim.usec != mtime.usec #endif ) die("shallow file was changed during fetch"); fd = hold_lock_file_for_update(&lock, shallow, 1); if (!write_shallow_commits(fd, 0)) { unlink(shallow); rollback_lock_file(&lock); } else { commit_lock_file(&lock); } } reprepare_packed_git(); return ref_cpy; }
struct ref *fetch_pack(struct fetch_pack_args *args, int fd[], struct child_process *conn, const struct ref *ref, const char *dest, struct ref **sought, int nr_sought, struct oid_array *shallow, char **pack_lockfile, enum protocol_version version) { struct ref *ref_cpy; struct shallow_info si; fetch_pack_setup(); if (nr_sought) nr_sought = remove_duplicates_in_refs(sought, nr_sought); if (!ref) { packet_flush(fd[1]); die(_("no matching remote head")); } prepare_shallow_info(&si, shallow); if (version == protocol_v2) ref_cpy = do_fetch_pack_v2(args, fd, ref, sought, nr_sought, pack_lockfile); else ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, &si, pack_lockfile); reprepare_packed_git(the_repository); if (!args->cloning && args->deepen) { struct check_connected_options opt = CHECK_CONNECTED_INIT; struct ref *iterator = ref_cpy; opt.shallow_file = alternate_shallow_file; if (args->deepen) opt.is_deepening_fetch = 1; if (check_connected(iterate_ref_map, &iterator, &opt)) { error(_("remote did not send all necessary objects")); free_refs(ref_cpy); ref_cpy = NULL; rollback_lock_file(&shallow_lock); goto cleanup; } args->connectivity_checked = 1; } update_shallow(args, sought, nr_sought, &si); cleanup: clear_shallow_info(&si); return ref_cpy; }
int git_read_tree(GIT_HASH hash,read_tree_fn_t fn, void *context) { struct tree * root; int ret; reprepare_packed_git(); root = parse_tree_indirect(hash); if (!root) { free_all_pack(); return -1; } ret = read_tree_recursive(root, NULL, 0, 0, NULL, fn, context); free_all_pack(); return ret; }
static void git_end_pack (char *pack_file, char *pack_dir) { char *command; char *pack_name; char *src_pack_pack, *src_pack_idx; char *dst_pack_pack, *dst_pack_idx; if (fclose (packf) == EOF) return; command = git_format_command ("git pack-objects -q --non-empty .tmp-pack < '%s'", pack_file); if (!command) { unlink (pack_file); return; } pack_name = git_system_to_string (command); unlink (pack_file); free (command); if (!pack_name) return; fprintf (STATUS, "Pack pack-%s created\n", pack_name); fflush (STATUS); src_pack_pack = git_format_command (".tmp-pack-%s.pack", pack_name); src_pack_idx = git_format_command (".tmp-pack-%s.idx", pack_name); dst_pack_pack = git_format_command ("%s/pack-%s.pack", pack_dir, pack_name); dst_pack_idx = git_format_command ("%s/pack-%s.idx", pack_dir, pack_name); if (!src_pack_pack || !src_pack_idx || !dst_pack_pack || !dst_pack_idx) { if (src_pack_pack) free (src_pack_pack); if (src_pack_idx) free (src_pack_idx); if (dst_pack_pack) free (dst_pack_pack); if (dst_pack_idx) free (dst_pack_idx); return; } if (rename (src_pack_pack, dst_pack_pack) == -1 || rename (src_pack_idx, dst_pack_idx) == -1) return; free (src_pack_pack); free (src_pack_idx); free (dst_pack_pack); free (dst_pack_idx); (void) git_system ("git prune-packed"); reprepare_packed_git (); }
int git_checkout_file(const char *ref, const char *path, const char *outputpath) { struct cache_entry *ce; int ret; GIT_HASH sha1; struct tree * root; struct checkout state; struct pathspec pathspec; const char *match[2]; ret = get_sha1(ref, sha1); if(ret) return ret; reprepare_packed_git(); root = parse_tree_indirect(sha1); if(!root) { free_all_pack(); return -1; } ce = xcalloc(1, cache_entry_size(strlen(path))); match[0] = path; match[1] = NULL; init_pathspec(&pathspec, match); pathspec.items[0].use_wildcard = 0; ret = read_tree_recursive(root, "", 0, 0, &pathspec, update_some, ce); free_pathspec(&pathspec); if(ret) { free_all_pack(); free(ce); return ret; } memset(&state, 0, sizeof(state)); state.force = 1; state.refresh_cache = 0; ret = write_entry(ce, outputpath, &state, 0); free_all_pack(); free(ce); return ret; }
int git_checkout_file(const char* ref, const char* path, char* outputpath) { struct cache_entry *ce; int ret; struct object_id oid; struct tree * root; struct checkout state; struct pathspec pathspec; const char *matchbuf[1]; ret = get_oid(ref, &oid); if(ret) return ret; reprepare_packed_git(the_repository); root = parse_tree_indirect(&oid); if(!root) { free_all_pack(); return -1; } ce = xcalloc(1, cache_entry_size(strlen(path))); matchbuf[0] = NULL; parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC, PATHSPEC_PREFER_CWD, path, matchbuf); pathspec.items[0].nowildcard_len = pathspec.items[0].len; ret = read_tree_recursive(root, "", 0, 0, &pathspec, update_some, ce); clear_pathspec(&pathspec); if(ret) { free_all_pack(); free(ce); return ret; } memset(&state, 0, sizeof(state)); state.force = 1; state.refresh_cache = 0; ret = write_entry(ce, outputpath, &state, 0); free_all_pack(); free(ce); return ret; }
static void finish_bulk_checkin(struct bulk_checkin_state *state) { struct object_id oid; struct strbuf packname = STRBUF_INIT; int i; if (!state->f) return; if (state->nr_written == 0) { close(state->f->fd); unlink(state->pack_tmp_name); goto clear_exit; } else if (state->nr_written == 1) { sha1close(state->f, oid.hash, CSUM_FSYNC); } else { int fd = sha1close(state->f, oid.hash, 0); fixup_pack_header_footer(fd, oid.hash, state->pack_tmp_name, state->nr_written, oid.hash, state->offset); close(fd); } strbuf_addf(&packname, "%s/pack/pack-", get_object_directory()); finish_tmp_packfile(&packname, state->pack_tmp_name, state->written, state->nr_written, &state->pack_idx_opts, oid.hash); for (i = 0; i < state->nr_written; i++) free(state->written[i]); clear_exit: free(state->written); memset(state, 0, sizeof(*state)); strbuf_release(&packname); /* Make objects we just wrote available to ourselves */ reprepare_packed_git(); }
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 const char *unpack(int err_fd, struct shallow_info *si) { struct pack_header hdr; struct argv_array av = ARGV_ARRAY_INIT; const char *hdr_err; int status; char hdr_arg[38]; struct child_process child; 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) { if (err_fd > 0) close(err_fd); return hdr_err; } snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (si->nr_ours || si->nr_theirs) { alt_shallow_file = setup_temporary_shallow(si->shallow); argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL); } memset(&child, 0, sizeof(child)); if (ntohl(hdr.hdr_entries) < unpack_limit) { argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL); if (quiet) argv_array_push(&av, "-q"); if (fsck_objects) argv_array_push(&av, "--strict"); child.argv = av.argv; child.no_stdout = 1; child.err = err_fd; child.git_cmd = 1; status = run_command(&child); if (status) return "unpack-objects abnormal exit"; } else { int s; char keep_arg[256]; 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"); argv_array_pushl(&av, "index-pack", "--stdin", hdr_arg, keep_arg, NULL); if (fsck_objects) argv_array_push(&av, "--strict"); if (fix_thin) argv_array_push(&av, "--fix-thin"); child.argv = av.argv; child.out = -1; child.err = err_fd; child.git_cmd = 1; status = start_command(&child); if (status) return "index-pack fork failed"; pack_lockfile = index_pack_lockfile(child.out); close(child.out); status = finish_command(&child); if (status) return "index-pack abnormal exit"; reprepare_packed_git(); } return NULL; }
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"; } }
struct ref *fetch_pack(struct fetch_pack_args *args, int fd[], struct child_process *conn, const struct ref *ref, const char *dest, struct ref **sought, int nr_sought, struct oid_array *shallow, char **pack_lockfile, enum protocol_version version) { struct ref *ref_cpy; struct shallow_info si; fetch_pack_setup(); if (nr_sought) nr_sought = remove_duplicates_in_refs(sought, nr_sought); if (args->no_dependents && !args->filter_options.choice) { /* * The protocol does not support requesting that only the * wanted objects be sent, so approximate this by setting a * "blob:none" filter if no filter is already set. This works * for all object types: note that wanted blobs will still be * sent because they are directly specified as a "want". * * NEEDSWORK: Add an option in the protocol to request that * only the wanted objects be sent, and implement it. */ parse_list_objects_filter(&args->filter_options, "blob:none"); } if (version != protocol_v2 && !ref) { packet_flush(fd[1]); die(_("no matching remote head")); } prepare_shallow_info(&si, shallow); if (version == protocol_v2) ref_cpy = do_fetch_pack_v2(args, fd, ref, sought, nr_sought, pack_lockfile); else ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, &si, pack_lockfile); reprepare_packed_git(the_repository); if (!args->cloning && args->deepen) { struct check_connected_options opt = CHECK_CONNECTED_INIT; struct ref *iterator = ref_cpy; opt.shallow_file = alternate_shallow_file; if (args->deepen) opt.is_deepening_fetch = 1; if (check_connected(iterate_ref_map, &iterator, &opt)) { error(_("remote did not send all necessary objects")); free_refs(ref_cpy); ref_cpy = NULL; rollback_lock_file(&shallow_lock); goto cleanup; } args->connectivity_checked = 1; } update_shallow(args, sought, nr_sought, &si); cleanup: clear_shallow_info(&si); return ref_cpy; }
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; }
static const char *unpack(int err_fd, struct shallow_info *si) { struct pack_header hdr; const char *hdr_err; int status; char hdr_arg[38]; struct child_process child = CHILD_PROCESS_INIT; 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) { if (err_fd > 0) close(err_fd); return hdr_err; } snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (si->nr_ours || si->nr_theirs) { alt_shallow_file = setup_temporary_shallow(si->shallow); argv_array_push(&child.args, "--shallow-file"); argv_array_push(&child.args, alt_shallow_file); } if (ntohl(hdr.hdr_entries) < unpack_limit) { argv_array_pushl(&child.args, "unpack-objects", hdr_arg, NULL); if (quiet) argv_array_push(&child.args, "-q"); if (fsck_objects) argv_array_pushf(&child.args, "--strict%s", fsck_msg_types.buf); child.no_stdout = 1; child.err = err_fd; child.git_cmd = 1; status = run_command(&child); if (status) return "unpack-objects abnormal exit"; } else { char hostname[256]; argv_array_pushl(&child.args, "index-pack", "--stdin", hdr_arg, NULL); if (gethostname(hostname, sizeof(hostname))) xsnprintf(hostname, sizeof(hostname), "localhost"); argv_array_pushf(&child.args, "--keep=receive-pack %"PRIuMAX" on %s", (uintmax_t)getpid(), hostname); if (!quiet && err_fd) argv_array_push(&child.args, "--show-resolving-progress"); if (use_sideband) argv_array_push(&child.args, "--report-end-of-input"); if (fsck_objects) argv_array_pushf(&child.args, "--strict%s", fsck_msg_types.buf); if (!reject_thin) argv_array_push(&child.args, "--fix-thin"); child.out = -1; child.err = err_fd; child.git_cmd = 1; status = start_command(&child); if (status) return "index-pack fork failed"; pack_lockfile = index_pack_lockfile(child.out); close(child.out); status = finish_command(&child); if (status) return "index-pack abnormal exit"; reprepare_packed_git(); } return NULL; }
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; }