commit-reach: make can_all_from_reach... linear
[gitweb.git] / builtin / repack.c
index af7340c7bafbfbbf991f782139775e18b6ac570a..6c636e159eaf2d67d617c459aceddd7423e326ab 100644 (file)
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "config.h"
 #include "dir.h"
 #include "parse-options.h"
 #include "run-command.h"
@@ -18,6 +19,12 @@ static const char *const git_repack_usage[] = {
        NULL
 };
 
+static const char incremental_bitmap_conflict_error[] = N_(
+"Incremental repacks are incompatible with bitmap indexes.  Use\n"
+"--no-write-bitmap-index or disable the pack.writebitmaps configuration."
+);
+
+
 static int repack_config(const char *var, const char *value, void *cb)
 {
        if (!strcmp(var, "repack.usedeltabaseoffset")) {
@@ -76,9 +83,11 @@ static void remove_pack_on_signal(int signo)
 
 /*
  * Adds all packs hex strings to the fname list, which do not
- * have a corresponding .keep file.
+ * have a corresponding .keep or .promisor file. These packs are not to
+ * be kept if we are going to pack everything into one file.
  */
-static void get_non_kept_pack_filenames(struct string_list *fname_list)
+static void get_non_kept_pack_filenames(struct string_list *fname_list,
+                                       const struct string_list *extra_keep)
 {
        DIR *dir;
        struct dirent *e;
@@ -89,12 +98,21 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list)
 
        while ((e = readdir(dir)) != NULL) {
                size_t len;
+               int i;
+
+               for (i = 0; i < extra_keep->nr; i++)
+                       if (!fspathcmp(e->d_name, extra_keep->items[i].string))
+                               break;
+               if (extra_keep->nr > 0 && i < extra_keep->nr)
+                       continue;
+
                if (!strip_suffix(e->d_name, ".pack", &len))
                        continue;
 
                fname = xmemdupz(e->d_name, len);
 
-               if (!file_exists(mkpath("%s/%s.keep", packdir, fname)))
+               if (!file_exists(mkpath("%s/%s.keep", packdir, fname)) &&
+                   !file_exists(mkpath("%s/%s.promisor", packdir, fname)))
                        string_list_append_nodup(fname_list, fname);
                else
                        free(fname);
@@ -139,16 +157,19 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        struct string_list rollback = STRING_LIST_INIT_NODUP;
        struct string_list existing_packs = STRING_LIST_INIT_DUP;
        struct strbuf line = STRBUF_INIT;
-       int ext, ret, failed;
+       int i, ext, ret, failed;
        FILE *out;
 
        /* variables to be filled by option parsing */
        int pack_everything = 0;
        int delete_redundant = 0;
        const char *unpack_unreachable = NULL;
+       int keep_unreachable = 0;
        const char *window = NULL, *window_memory = NULL;
        const char *depth = NULL;
+       const char *threads = NULL;
        const char *max_pack_size = NULL;
+       struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
        int no_reuse_delta = 0, no_reuse_object = 0;
        int no_update_server_info = 0;
        int quiet = 0;
@@ -175,16 +196,22 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                                N_("write bitmap index")),
                OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
                                N_("with -A, do not loosen objects older than this")),
+               OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
+                               N_("with -a, repack unreachable objects")),
                OPT_STRING(0, "window", &window, N_("n"),
                                N_("size of the window used for delta compression")),
                OPT_STRING(0, "window-memory", &window_memory, N_("bytes"),
                                N_("same as the above, but limit memory size instead of entries count")),
                OPT_STRING(0, "depth", &depth, N_("n"),
                                N_("limits the maximum delta depth")),
+               OPT_STRING(0, "threads", &threads, N_("n"),
+                               N_("limits the maximum number of threads")),
                OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"),
                                N_("maximum size of each packfile")),
                OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
                                N_("repack objects in packs marked with .keep")),
+               OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
+                               N_("do not repack this pack")),
                OPT_END()
        };
 
@@ -193,9 +220,19 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, builtin_repack_options,
                                git_repack_usage, 0);
 
+       if (delete_redundant && repository_format_precious_objects)
+               die(_("cannot delete packs in a precious-objects repo"));
+
+       if (keep_unreachable &&
+           (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
+               die(_("--keep-unreachable and -A are incompatible"));
+
        if (pack_kept_objects < 0)
                pack_kept_objects = write_bitmaps;
 
+       if (write_bitmaps && !(pack_everything & ALL_INTO_ONE))
+               die(_(incremental_bitmap_conflict_error));
+
        packdir = mkpathdup("%s/pack", get_object_directory());
        packtmp = mkpathdup("%s/.tmp-%d-pack", packdir, (int)getpid());
 
@@ -205,16 +242,23 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        argv_array_push(&cmd.args, "--keep-true-parents");
        if (!pack_kept_objects)
                argv_array_push(&cmd.args, "--honor-pack-keep");
+       for (i = 0; i < keep_pack_list.nr; i++)
+               argv_array_pushf(&cmd.args, "--keep-pack=%s",
+                                keep_pack_list.items[i].string);
        argv_array_push(&cmd.args, "--non-empty");
        argv_array_push(&cmd.args, "--all");
        argv_array_push(&cmd.args, "--reflog");
        argv_array_push(&cmd.args, "--indexed-objects");
+       if (repository_format_partial_clone)
+               argv_array_push(&cmd.args, "--exclude-promisor-objects");
        if (window)
                argv_array_pushf(&cmd.args, "--window=%s", window);
        if (window_memory)
                argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory);
        if (depth)
                argv_array_pushf(&cmd.args, "--depth=%s", depth);
+       if (threads)
+               argv_array_pushf(&cmd.args, "--threads=%s", threads);
        if (max_pack_size)
                argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size);
        if (no_reuse_delta)
@@ -225,7 +269,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                argv_array_push(&cmd.args, "--write-bitmap-index");
 
        if (pack_everything & ALL_INTO_ONE) {
-               get_non_kept_pack_filenames(&existing_packs);
+               get_non_kept_pack_filenames(&existing_packs, &keep_pack_list);
 
                if (existing_packs.nr && delete_redundant) {
                        if (unpack_unreachable) {
@@ -236,6 +280,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                        } else if (pack_everything & LOOSEN_UNREACHABLE) {
                                argv_array_push(&cmd.args,
                                                "--unpack-unreachable");
+                       } else if (keep_unreachable) {
+                               argv_array_push(&cmd.args, "--keep-unreachable");
+                               argv_array_push(&cmd.args, "--pack-loose-unreachable");
                        } else {
                                argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
                        }
@@ -263,7 +310,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                return ret;
 
        out = xfdopen(cmd.out, "r");
-       while (strbuf_getline(&line, out, '\n') != EOF) {
+       while (strbuf_getline_lf(&line, out) != EOF) {
                if (line.len != 40)
                        die("repack: Expecting 40 character sha1 lines only from pack-objects.");
                string_list_append(&names, line.buf);
@@ -285,8 +332,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        failed = 0;
        for_each_string_list_item(item, &names) {
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
-                       const char *fname_old;
-                       char *fname;
+                       char *fname, *fname_old;
                        fname = mkpathdup("%s/pack-%s%s", packdir,
                                                item->string, exts[ext].name);
                        if (!file_exists(fname)) {
@@ -294,7 +340,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                                continue;
                        }
 
-                       fname_old = mkpath("%s/old-%s%s", packdir,
+                       fname_old = mkpathdup("%s/old-%s%s", packdir,
                                                item->string, exts[ext].name);
                        if (file_exists(fname_old))
                                if (unlink(fname_old))
@@ -302,10 +348,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
                        if (!failed && rename(fname, fname_old)) {
                                free(fname);
+                               free(fname_old);
                                failed = 1;
                                break;
                        } else {
                                string_list_append(&rollback, fname);
+                               free(fname_old);
                        }
                }
                if (failed)
@@ -314,13 +362,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        if (failed) {
                struct string_list rollback_failure = STRING_LIST_INIT_DUP;
                for_each_string_list_item(item, &rollback) {
-                       const char *fname_old;
-                       char *fname;
+                       char *fname, *fname_old;
                        fname = mkpathdup("%s/%s", packdir, item->string);
-                       fname_old = mkpath("%s/old-%s", packdir, item->string);
+                       fname_old = mkpathdup("%s/old-%s", packdir, item->string);
                        if (rename(fname_old, fname))
                                string_list_append(&rollback_failure, fname);
                        free(fname);
+                       free(fname_old);
                }
 
                if (rollback_failure.nr) {
@@ -368,13 +416,14 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        /* Remove the "old-" files */
        for_each_string_list_item(item, &names) {
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
-                       const char *fname;
-                       fname = mkpath("%s/old-%s%s",
-                                       packdir,
-                                       item->string,
-                                       exts[ext].name);
+                       char *fname;
+                       fname = mkpathdup("%s/old-%s%s",
+                                         packdir,
+                                         item->string,
+                                         exts[ext].name);
                        if (remove_path(fname))
-                               warning(_("removing '%s' failed"), fname);
+                               warning(_("failed to remove '%s'"), fname);
+                       free(fname);
                }
        }