2  * git gc builtin command
 
   4  * Cleanup unreachable files and optimize the repository.
 
   6  * Copyright (c) 2007 James Bowes
 
   8  * Based on git-gc.sh, which is
 
  10  * Copyright (c) 2006 Shawn O. Pearce
 
  15 #include "parse-options.h"
 
  16 #include "run-command.h"
 
  18 #define FAILED_RUN "failed to run %s"
 
  20 static const char * const builtin_gc_usage[] = {
 
  25 static int pack_refs = 1;
 
  26 static int aggressive_window = 250;
 
  27 static int gc_auto_threshold = 6700;
 
  28 static int gc_auto_pack_limit = 50;
 
  29 static const char *prune_expire = "2.weeks.ago";
 
  32 static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
 
  33 static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
 
  34 static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
 
  35 static const char *argv_prune[] = {"prune", "--expire", NULL, NULL};
 
  36 static const char *argv_rerere[] = {"rerere", "gc", NULL};
 
  38 static int gc_config(const char *var, const char *value, void *cb)
 
  40         if (!strcmp(var, "gc.packrefs")) {
 
  41                 if (value && !strcmp(value, "notbare"))
 
  44                         pack_refs = git_config_bool(var, value);
 
  47         if (!strcmp(var, "gc.aggressivewindow")) {
 
  48                 aggressive_window = git_config_int(var, value);
 
  51         if (!strcmp(var, "gc.auto")) {
 
  52                 gc_auto_threshold = git_config_int(var, value);
 
  55         if (!strcmp(var, "gc.autopacklimit")) {
 
  56                 gc_auto_pack_limit = git_config_int(var, value);
 
  59         if (!strcmp(var, "gc.pruneexpire")) {
 
  60                 if (value && strcmp(value, "now")) {
 
  61                         unsigned long now = approxidate("now");
 
  62                         if (approxidate(value) >= now)
 
  63                                 return error(_("Invalid %s: '%s'"), var, value);
 
  65                 return git_config_string(&prune_expire, var, value);
 
  67         return git_default_config(var, value, cb);
 
  70 static void append_option(const char **cmd, const char *opt, int max_length)
 
  74         for (i = 0; cmd[i]; i++)
 
  77         if (i + 2 >= max_length)
 
  78                 die(_("Too many options specified"));
 
  83 static int too_many_loose_objects(void)
 
  86          * Quickly check if a "gc" is needed, by estimating how
 
  87          * many loose objects there are.  Because SHA-1 is evenly
 
  88          * distributed, we can check only one and get a reasonable
 
  92         const char *objdir = get_object_directory();
 
  99         if (gc_auto_threshold <= 0)
 
 102         if (sizeof(path) <= snprintf(path, sizeof(path), "%s/17", objdir)) {
 
 103                 warning(_("insanely long object directory %.*s"), 50, objdir);
 
 110         auto_threshold = (gc_auto_threshold + 255) / 256;
 
 111         while ((ent = readdir(dir)) != NULL) {
 
 112                 if (strspn(ent->d_name, "0123456789abcdef") != 38 ||
 
 113                     ent->d_name[38] != '\0')
 
 115                 if (++num_loose > auto_threshold) {
 
 124 static int too_many_packs(void)
 
 126         struct packed_git *p;
 
 129         if (gc_auto_pack_limit <= 0)
 
 132         prepare_packed_git();
 
 133         for (cnt = 0, p = packed_git; p; p = p->next) {
 
 139                  * Perhaps check the size of the pack and count only
 
 140                  * very small ones here?
 
 144         return gc_auto_pack_limit <= cnt;
 
 147 static int need_to_gc(void)
 
 150          * Setting gc.auto to 0 or negative can disable the
 
 153         if (gc_auto_threshold <= 0)
 
 157          * If there are too many loose objects, but not too many
 
 158          * packs, we run "repack -d -l".  If there are too many packs,
 
 159          * we run "repack -A -d -l".  Otherwise we tell the caller
 
 162         if (too_many_packs())
 
 163                 append_option(argv_repack,
 
 164                               prune_expire && !strcmp(prune_expire, "now") ?
 
 167         else if (!too_many_loose_objects())
 
 170         if (run_hook(NULL, "pre-auto-gc", NULL))
 
 175 int cmd_gc(int argc, const char **argv, const char *prefix)
 
 182         struct option builtin_gc_options[] = {
 
 183                 OPT__QUIET(&quiet, "suppress progress reporting"),
 
 184                 { OPTION_STRING, 0, "prune", &prune_expire, "date",
 
 185                         "prune unreferenced objects",
 
 186                         PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
 
 187                 OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
 
 188                 OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
 
 192         if (argc == 2 && !strcmp(argv[1], "-h"))
 
 193                 usage_with_options(builtin_gc_usage, builtin_gc_options);
 
 195         git_config(gc_config, NULL);
 
 198                 pack_refs = !is_bare_repository();
 
 200         argc = parse_options(argc, argv, prefix, builtin_gc_options,
 
 201                              builtin_gc_usage, 0);
 
 203                 usage_with_options(builtin_gc_usage, builtin_gc_options);
 
 206                 append_option(argv_repack, "-f", MAX_ADD);
 
 207                 append_option(argv_repack, "--depth=250", MAX_ADD);
 
 208                 if (aggressive_window > 0) {
 
 209                         sprintf(buf, "--window=%d", aggressive_window);
 
 210                         append_option(argv_repack, buf, MAX_ADD);
 
 214                 append_option(argv_repack, "-q", MAX_ADD);
 
 218                  * Auto-gc should be least intrusive as possible.
 
 223                         fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
 
 226                                         _("Auto packing the repository for optimum performance. You may also\n"
 
 227                                         "run \"git gc\" manually. See "
 
 228                                         "\"git help gc\" for more information.\n"));
 
 230                 append_option(argv_repack,
 
 231                               prune_expire && !strcmp(prune_expire, "now")
 
 235         if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
 
 236                 return error(FAILED_RUN, argv_pack_refs[0]);
 
 238         if (run_command_v_opt(argv_reflog, RUN_GIT_CMD))
 
 239                 return error(FAILED_RUN, argv_reflog[0]);
 
 241         if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
 
 242                 return error(FAILED_RUN, argv_repack[0]);
 
 245                 argv_prune[2] = prune_expire;
 
 246                 if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
 
 247                         return error(FAILED_RUN, argv_prune[0]);
 
 250         if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
 
 251                 return error(FAILED_RUN, argv_rerere[0]);
 
 253         if (auto_gc && too_many_loose_objects())
 
 254                 warning(_("There are too many unreachable loose objects; "
 
 255                         "run 'git prune' to remove them."));