static int pack_refs = 1;
static int aggressive_window = -1;
static int gc_auto_threshold = 6700;
+static int gc_auto_pack_limit = 20;
#define MAX_ADD 10
static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
-static const char *argv_repack[MAX_ADD] = {"repack", "-a", "-d", "-l", NULL};
+static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
static const char *argv_prune[] = {"prune", NULL};
static const char *argv_rerere[] = {"rerere", "gc", NULL};
gc_auto_threshold = git_config_int(var, value);
return 0;
}
+ if (!strcmp(var, "gc.autopacklimit")) {
+ gc_auto_pack_limit = git_config_int(var, value);
+ return 0;
+ }
return git_default_config(var, value);
}
int num_loose = 0;
int needed = 0;
+ if (gc_auto_threshold <= 0)
+ return 0;
+
if (sizeof(path) <= snprintf(path, sizeof(path), "%s/17", objdir)) {
warning("insanely long object directory %.*s", 50, objdir);
return 0;
return needed;
}
-static int need_to_gc(void)
+static int too_many_packs(void)
{
- int ac = 0;
+ struct packed_git *p;
+ int cnt;
+ if (gc_auto_pack_limit <= 0)
+ return 0;
+
+ prepare_packed_git();
+ for (cnt = 0, p = packed_git; p; p = p->next) {
+ char path[PATH_MAX];
+ size_t len;
+ int keep;
+
+ if (!p->pack_local)
+ continue;
+ len = strlen(p->pack_name);
+ if (PATH_MAX <= len + 1)
+ continue; /* oops, give up */
+ memcpy(path, p->pack_name, len-5);
+ memcpy(path + len - 5, ".keep", 6);
+ keep = access(p->pack_name, F_OK) && (errno == ENOENT);
+ if (keep)
+ continue;
+ /*
+ * Perhaps check the size of the pack and count only
+ * very small ones here?
+ */
+ cnt++;
+ }
+ return gc_auto_pack_limit <= cnt;
+}
+
+static int need_to_gc(void)
+{
/*
- * Setting gc.auto to 0 or negative can disable the
- * automatic gc
+ * Setting gc.auto and gc.autopacklimit to 0 or negative can
+ * disable the automatic gc.
*/
- if (gc_auto_threshold <= 0)
+ if (gc_auto_threshold <= 0 && gc_auto_pack_limit <= 0)
return 0;
- if (!too_many_loose_objects())
+ /*
+ * If there are too many loose objects, but not too many
+ * packs, we run "repack -d -l". If there are too many packs,
+ * we run "repack -A -d -l". Otherwise we tell the caller
+ * there is no need.
+ */
+ if (too_many_packs())
+ append_option(argv_repack, "-A", MAX_ADD);
+ else if (!too_many_loose_objects())
return 0;
-
- argv_repack[ac++] = "repack";
- argv_repack[ac++] = "-d";
- argv_repack[ac++] = "-l";
- argv_repack[ac++] = NULL;
return 1;
}
prune = 0;
if (!need_to_gc())
return 0;
+ fprintf(stderr, "Packing your repository for optimum "
+ "performance. You may also\n"
+ "run \"git gc\" manually. See "
+ "\"git help gc\" for more information.\n");
+ } else {
+ /*
+ * Use safer (for shared repos) "-A" option to
+ * repack when not pruning. Auto-gc makes its
+ * own decision.
+ */
+ if (prune)
+ append_option(argv_repack, "-a", MAX_ADD);
+ else
+ append_option(argv_repack, "-A", MAX_ADD);
}
if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))