summaryrefslogtreecommitdiff
path: root/builtin/gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/gc.c')
-rw-r--r--builtin/gc.c219
1 files changed, 148 insertions, 71 deletions
diff --git a/builtin/gc.c b/builtin/gc.c
index ceff31ea00..f3942188a6 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -11,6 +11,10 @@
*/
#include "builtin.h"
+#include "abspath.h"
+#include "date.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "tempfile.h"
@@ -22,6 +26,7 @@
#include "commit.h"
#include "commit-graph.h"
#include "packfile.h"
+#include "object-file.h"
#include "object-store.h"
#include "pack.h"
#include "pack-objects.h"
@@ -31,7 +36,11 @@
#include "refs.h"
#include "remote.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "hook.h"
+#include "setup.h"
+#include "trace2.h"
+#include "wrapper.h"
#define FAILED_RUN "failed to run %s"
@@ -42,7 +51,7 @@ static const char * const builtin_gc_usage[] = {
static int pack_refs = 1;
static int prune_reflogs = 1;
-static int cruft_packs = 0;
+static int cruft_packs = 1;
static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
@@ -167,9 +176,11 @@ static void gc_config(void)
struct maintenance_run_opts;
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
{
- const char *argv[] = { "pack-refs", "--all", "--prune", NULL };
+ struct child_process cmd = CHILD_PROCESS_INIT;
- return run_command_v_opt(argv, RUN_GIT_CMD);
+ cmd.git_cmd = 1;
+ strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
+ return run_command(&cmd);
}
static int too_many_loose_objects(void)
@@ -211,7 +222,7 @@ static struct packed_git *find_base_packs(struct string_list *packs,
struct packed_git *p, *base = NULL;
for (p = get_all_packs(the_repository); p; p = p->next) {
- if (!p->pack_local)
+ if (!p->pack_local || p->is_cruft)
continue;
if (limit) {
if (p->pack_size >= limit)
@@ -282,7 +293,7 @@ static uint64_t total_ram(void)
static uint64_t estimate_repack_memory(struct packed_git *pack)
{
- unsigned long nr_objects = approximate_object_count();
+ unsigned long nr_objects = repo_approximate_object_count(the_repository);
size_t os_cache, heap;
if (!pack || !nr_objects)
@@ -322,7 +333,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack)
return os_cache + heap;
}
-static int keep_one_pack(struct string_list_item *item, void *data)
+static int keep_one_pack(struct string_list_item *item, void *data UNUSED)
{
strvec_pushf(&repack, "--keep-pack=%s", basename(item->string));
return 0;
@@ -535,8 +546,14 @@ static void gc_before_repack(void)
if (pack_refs && maintenance_task_pack_refs(NULL))
die(FAILED_RUN, "pack-refs");
- if (prune_reflogs && run_command_v_opt(reflog.v, RUN_GIT_CMD))
- die(FAILED_RUN, reflog.v[0]);
+ if (prune_reflogs) {
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ cmd.git_cmd = 1;
+ strvec_pushv(&cmd.args, reflog.v);
+ if (run_command(&cmd))
+ die(FAILED_RUN, reflog.v[0]);
+ }
}
int cmd_gc(int argc, const char **argv, const char *prefix)
@@ -550,6 +567,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int daemonized = 0;
int keep_largest_pack = -1;
timestamp_t dummy;
+ struct child_process rerere_cmd = CHILD_PROCESS_INIT;
struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")),
@@ -671,30 +689,44 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
gc_before_repack();
if (!repository_format_precious_objects) {
- if (run_command_v_opt(repack.v,
- RUN_GIT_CMD | RUN_CLOSE_OBJECT_STORE))
+ struct child_process repack_cmd = CHILD_PROCESS_INIT;
+
+ repack_cmd.git_cmd = 1;
+ repack_cmd.close_object_store = 1;
+ strvec_pushv(&repack_cmd.args, repack.v);
+ if (run_command(&repack_cmd))
die(FAILED_RUN, repack.v[0]);
if (prune_expire) {
+ struct child_process prune_cmd = CHILD_PROCESS_INIT;
+
/* run `git prune` even if using cruft packs */
strvec_push(&prune, prune_expire);
if (quiet)
strvec_push(&prune, "--no-progress");
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
strvec_push(&prune,
"--exclude-promisor-objects");
- if (run_command_v_opt(prune.v, RUN_GIT_CMD))
+ prune_cmd.git_cmd = 1;
+ strvec_pushv(&prune_cmd.args, prune.v);
+ if (run_command(&prune_cmd))
die(FAILED_RUN, prune.v[0]);
}
}
if (prune_worktrees_expire) {
+ struct child_process prune_worktrees_cmd = CHILD_PROCESS_INIT;
+
strvec_push(&prune_worktrees, prune_worktrees_expire);
- if (run_command_v_opt(prune_worktrees.v, RUN_GIT_CMD))
+ prune_worktrees_cmd.git_cmd = 1;
+ strvec_pushv(&prune_worktrees_cmd.args, prune_worktrees.v);
+ if (run_command(&prune_worktrees_cmd))
die(FAILED_RUN, prune_worktrees.v[0]);
}
- if (run_command_v_opt(rerere.v, RUN_GIT_CMD))
+ rerere_cmd.git_cmd = 1;
+ strvec_pushv(&rerere_cmd.args, rerere.v);
+ if (run_command(&rerere_cmd))
die(FAILED_RUN, rerere.v[0]);
report_garbage = report_pack_garbage;
@@ -704,7 +736,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
clean_pack_garbage();
}
- prepare_repo_settings(the_repository);
if (the_repository->settings.gc_write_commit_graph == 1)
write_commit_graph_reachable(the_repository->objects->odb,
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
@@ -794,7 +825,7 @@ static int dfs_on_ref(const char *refname UNUSED,
commit = lookup_commit(the_repository, oid);
if (!commit)
return 0;
- if (parse_commit(commit) ||
+ if (repo_parse_commit(the_repository, commit) ||
commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
return 0;
@@ -811,7 +842,7 @@ static int dfs_on_ref(const char *refname UNUSED,
commit = pop_commit(&stack);
for (parent = commit->parents; parent; parent = parent->next) {
- if (parse_commit(parent->item) ||
+ if (repo_parse_commit(the_repository, parent->item) ||
commit_graph_position(parent->item) != COMMIT_NOT_FROM_GRAPH ||
parent->item->object.flags & SEEN)
continue;
@@ -950,9 +981,9 @@ struct write_loose_object_data {
static int loose_object_auto_limit = 100;
-static int loose_object_count(const struct object_id *oid,
- const char *path,
- void *data)
+static int loose_object_count(const struct object_id *oid UNUSED,
+ const char *path UNUSED,
+ void *data)
{
int *count = (int*)data;
if (++(*count) >= loose_object_auto_limit)
@@ -977,15 +1008,15 @@ static int loose_object_auto_condition(void)
NULL, NULL, &count);
}
-static int bail_on_loose(const struct object_id *oid,
- const char *path,
- void *data)
+static int bail_on_loose(const struct object_id *oid UNUSED,
+ const char *path UNUSED,
+ void *data UNUSED)
{
return 1;
}
static int write_loose_object_to_stdin(const struct object_id *oid,
- const char *path,
+ const char *path UNUSED,
void *data)
{
struct write_loose_object_data *d = (struct write_loose_object_data *)data;
@@ -1454,20 +1485,22 @@ static char *get_maintpath(void)
}
static char const * const builtin_maintenance_register_usage[] = {
- "git maintenance register",
+ "git maintenance register [--config-file <path>]",
NULL
};
static int maintenance_register(int argc, const char **argv, const char *prefix)
{
+ char *config_file = NULL;
struct option options[] = {
+ OPT_STRING(0, "config-file", &config_file, N_("file"), N_("use given config file")),
OPT_END(),
};
- int rc;
- char *config_value;
- struct child_process config_set = CHILD_PROCESS_INIT;
- struct child_process config_get = CHILD_PROCESS_INIT;
+ int found = 0;
+ const char *key = "maintenance.repo";
char *maintpath = get_maintpath();
+ struct string_list_item *item;
+ const struct string_list *list;
argc = parse_options(argc, argv, prefix, options,
builtin_maintenance_register_usage, 0);
@@ -1479,51 +1512,65 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
git_config_set("maintenance.auto", "false");
/* Set maintenance strategy, if unset */
- if (!git_config_get_string("maintenance.strategy", &config_value))
- free(config_value);
- else
+ if (git_config_get("maintenance.strategy"))
git_config_set("maintenance.strategy", "incremental");
- config_get.git_cmd = 1;
- strvec_pushl(&config_get.args, "config", "--global", "--get",
- "--fixed-value", "maintenance.repo", maintpath, NULL);
- config_get.out = -1;
-
- if (start_command(&config_get)) {
- rc = error(_("failed to run 'git config'"));
- goto done;
- }
-
- /* We already have this value in our config! */
- if (!finish_command(&config_get)) {
- rc = 0;
- goto done;
+ if (!git_config_get_string_multi(key, &list)) {
+ for_each_string_list_item(item, list) {
+ if (!strcmp(maintpath, item->string)) {
+ found = 1;
+ break;
+ }
+ }
}
- config_set.git_cmd = 1;
- strvec_pushl(&config_set.args, "config", "--add", "--global", "maintenance.repo",
- maintpath, NULL);
+ if (!found) {
+ int rc;
+ char *user_config = NULL, *xdg_config = NULL;
- rc = run_command(&config_set);
+ if (!config_file) {
+ git_global_config(&user_config, &xdg_config);
+ config_file = user_config;
+ if (!user_config)
+ die(_("$HOME not set"));
+ }
+ rc = git_config_set_multivar_in_file_gently(
+ config_file, "maintenance.repo", maintpath,
+ CONFIG_REGEX_NONE, 0);
+ free(user_config);
+ free(xdg_config);
+
+ if (rc)
+ die(_("unable to add '%s' value of '%s'"),
+ key, maintpath);
+ }
-done:
free(maintpath);
- return rc;
+ return 0;
}
static char const * const builtin_maintenance_unregister_usage[] = {
- "git maintenance unregister",
+ "git maintenance unregister [--config-file <path>] [--force]",
NULL
};
static int maintenance_unregister(int argc, const char **argv, const char *prefix)
{
+ int force = 0;
+ char *config_file = NULL;
struct option options[] = {
+ OPT_STRING(0, "config-file", &config_file, N_("file"), N_("use given config file")),
+ OPT__FORCE(&force,
+ N_("return success even if repository was not registered"),
+ PARSE_OPT_NOCOMPLETE),
OPT_END(),
};
- int rc;
- struct child_process config_unset = CHILD_PROCESS_INIT;
+ const char *key = "maintenance.repo";
char *maintpath = get_maintpath();
+ int found = 0;
+ struct string_list_item *item;
+ const struct string_list *list;
+ struct config_set cs = { { 0 } };
argc = parse_options(argc, argv, prefix, options,
builtin_maintenance_unregister_usage, 0);
@@ -1531,13 +1578,47 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
usage_with_options(builtin_maintenance_unregister_usage,
options);
- config_unset.git_cmd = 1;
- strvec_pushl(&config_unset.args, "config", "--global", "--unset",
- "--fixed-value", "maintenance.repo", maintpath, NULL);
+ if (config_file) {
+ git_configset_init(&cs);
+ git_configset_add_file(&cs, config_file);
+ }
+ if (!(config_file
+ ? git_configset_get_string_multi(&cs, key, &list)
+ : git_config_get_string_multi(key, &list))) {
+ for_each_string_list_item(item, list) {
+ if (!strcmp(maintpath, item->string)) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ int rc;
+ char *user_config = NULL, *xdg_config = NULL;
+ if (!config_file) {
+ git_global_config(&user_config, &xdg_config);
+ config_file = user_config;
+ if (!user_config)
+ die(_("$HOME not set"));
+ }
+ rc = git_config_set_multivar_in_file_gently(
+ config_file, key, NULL, maintpath,
+ CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
+ free(user_config);
+ free(xdg_config);
+
+ if (rc &&
+ (!force || rc == CONFIG_NOTHING_SET))
+ die(_("unable to unset '%s' value of '%s'"),
+ key, maintpath);
+ } else if (!force) {
+ die(_("repository '%s' is not registered"), maintpath);
+ }
- rc = run_command(&config_unset);
+ git_configset_clear(&cs);
free(maintpath);
- return rc;
+ return 0;
}
static const char *get_frequency(enum schedule_priority schedule)
@@ -1605,11 +1686,11 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
if (is_available)
*is_available = 0;
- string_list_split_in_place(&list, testing, ',', -1);
+ string_list_split_in_place(&list, testing, ",", -1);
for_each_string_list_item(item, &list) {
struct string_list pair = STRING_LIST_INIT_NODUP;
- if (string_list_split_in_place(&pair, item->string, ':', 2) != 2)
+ if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
continue;
if (!strcmp(*cmd, pair.items[0].string)) {
@@ -1874,20 +1955,16 @@ static char *schtasks_task_name(const char *frequency)
static int schtasks_remove_task(enum schedule_priority schedule)
{
const char *cmd = "schtasks";
- int result;
- struct strvec args = STRVEC_INIT;
+ struct child_process child = CHILD_PROCESS_INIT;
const char *frequency = get_frequency(schedule);
char *name = schtasks_task_name(frequency);
get_schedule_cmd(&cmd, NULL);
- strvec_split(&args, cmd);
- strvec_pushl(&args, "/delete", "/tn", name, "/f", NULL);
-
- result = run_command_v_opt(args.v, 0);
-
- strvec_clear(&args);
+ strvec_split(&child.args, cmd);
+ strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL);
free(name);
- return result;
+
+ return run_command(&child);
}
static int schtasks_remove_tasks(void)