Merge branch 'aw/doc-smtp-ssl-cert-path'
[gitweb.git] / builtin / pack-objects.c
index 3eb86e0693b3f9adb6680645151f842dffa7a4f9..d8165878e1d466e49719038b1badc524d5627270 100644 (file)
@@ -20,6 +20,9 @@
 #include "streaming.h"
 #include "thread-utils.h"
 #include "pack-bitmap.h"
+#include "reachable.h"
+#include "sha1-array.h"
+#include "argv-array.h"
 
 static const char *pack_usage[] = {
        N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
@@ -89,8 +92,7 @@ static void index_commit_for_bitmap(struct commit *commit)
 {
        if (indexed_commits_nr >= indexed_commits_alloc) {
                indexed_commits_alloc = (indexed_commits_alloc + 32) * 2;
-               indexed_commits = xrealloc(indexed_commits,
-                       indexed_commits_alloc * sizeof(struct commit *));
+               REALLOC_ARRAY(indexed_commits, indexed_commits_alloc);
        }
 
        indexed_commits[indexed_commits_nr++] = commit;
@@ -1974,8 +1976,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
 
        init_threaded_search();
 
-       if (!delta_search_threads)      /* --threads=0 means autodetect */
-               delta_search_threads = online_cpus();
        if (delta_search_threads <= 1) {
                find_deltas(list, &list_size, window, depth, processed);
                cleanup_threaded_search();
@@ -2409,6 +2409,27 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
        return 0;
 }
 
+/*
+ * Store a list of sha1s that are should not be discarded
+ * because they are either written too recently, or are
+ * reachable from another object that was.
+ *
+ * This is filled by get_object_list.
+ */
+static struct sha1_array recent_objects;
+
+static int loosened_object_can_be_discarded(const unsigned char *sha1,
+                                           unsigned long mtime)
+{
+       if (!unpack_unreachable_expiration)
+               return 0;
+       if (mtime > unpack_unreachable_expiration)
+               return 0;
+       if (sha1_array_lookup(&recent_objects, sha1) >= 0)
+               return 0;
+       return 1;
+}
+
 static void loosen_unused_packed_objects(struct rev_info *revs)
 {
        struct packed_git *p;
@@ -2419,17 +2440,14 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
                if (!p->pack_local || p->pack_keep)
                        continue;
 
-               if (unpack_unreachable_expiration &&
-                   p->mtime < unpack_unreachable_expiration)
-                       continue;
-
                if (open_pack_index(p))
                        die("cannot open pack index");
 
                for (i = 0; i < p->num_objects; i++) {
                        sha1 = nth_packed_object_sha1(p, i);
                        if (!packlist_find(&to_pack, sha1, NULL) &&
-                               !has_sha1_pack_kept_or_nonlocal(sha1))
+                           !has_sha1_pack_kept_or_nonlocal(sha1) &&
+                           !loosened_object_can_be_discarded(sha1, p->mtime))
                                if (force_object_loose(sha1, p->mtime))
                                        die("unable to force loose object");
                }
@@ -2465,6 +2483,19 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
        return 0;
 }
 
+static void record_recent_object(struct object *obj,
+                                const struct name_path *path,
+                                const char *last,
+                                void *data)
+{
+       sha1_array_append(&recent_objects, obj->sha1);
+}
+
+static void record_recent_commit(struct commit *commit, void *data)
+{
+       sha1_array_append(&recent_objects, commit->object.sha1);
+}
+
 static void get_object_list(int ac, const char **av)
 {
        struct rev_info revs;
@@ -2512,10 +2543,23 @@ static void get_object_list(int ac, const char **av)
        mark_edges_uninteresting(&revs, show_edge);
        traverse_commit_list(&revs, show_commit, show_object, NULL);
 
+       if (unpack_unreachable_expiration) {
+               revs.ignore_missing_links = 1;
+               if (add_unseen_recent_objects_to_traversal(&revs,
+                               unpack_unreachable_expiration))
+                       die("unable to add recent objects");
+               if (prepare_revision_walk(&revs))
+                       die("revision walk setup failed");
+               traverse_commit_list(&revs, record_recent_commit,
+                                    record_recent_object, NULL);
+       }
+
        if (keep_unreachable)
                add_objects_in_unpacked_packs(&revs);
        if (unpack_unreachable)
                loosen_unused_packed_objects(&revs);
+
+       sha1_array_clear(&recent_objects);
 }
 
 static int option_parse_index_version(const struct option *opt,
@@ -2569,10 +2613,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 {
        int use_internal_rev_list = 0;
        int thin = 0;
+       int shallow = 0;
        int all_progress_implied = 0;
-       const char *rp_av[6];
-       int rp_ac = 0;
+       struct argv_array rp = ARGV_ARRAY_INIT;
        int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
+       int rev_list_index = 0;
        struct option pack_objects_options[] = {
                OPT_SET_INT('q', "quiet", &progress,
                            N_("do not show progress meter"), 0),
@@ -2619,6 +2664,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                { OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
                  N_("include objects referred by reflog entries"),
                  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+               { OPTION_SET_INT, 0, "indexed-objects", &rev_list_index, NULL,
+                 N_("include objects referred to by the index"),
+                 PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
                OPT_BOOL(0, "stdout", &pack_to_stdout,
                         N_("output pack to stdout")),
                OPT_BOOL(0, "include-tag", &include_tag,
@@ -2630,6 +2678,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                  PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
                OPT_BOOL(0, "thin", &thin,
                         N_("create thin packs")),
+               OPT_BOOL(0, "shallow", &shallow,
+                        N_("create packs suitable for shallow fetches")),
                OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
                         N_("ignore packs that have companion .keep file")),
                OPT_INTEGER(0, "compression", &pack_compression_level,
@@ -2661,24 +2711,30 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (pack_to_stdout != !base_name || argc)
                usage_with_options(pack_usage, pack_objects_options);
 
-       rp_av[rp_ac++] = "pack-objects";
+       argv_array_push(&rp, "pack-objects");
        if (thin) {
                use_internal_rev_list = 1;
-               rp_av[rp_ac++] = "--objects-edge";
+               argv_array_push(&rp, shallow
+                               ? "--objects-edge-aggressive"
+                               : "--objects-edge");
        } else
-               rp_av[rp_ac++] = "--objects";
+               argv_array_push(&rp, "--objects");
 
        if (rev_list_all) {
                use_internal_rev_list = 1;
-               rp_av[rp_ac++] = "--all";
+               argv_array_push(&rp, "--all");
        }
        if (rev_list_reflog) {
                use_internal_rev_list = 1;
-               rp_av[rp_ac++] = "--reflog";
+               argv_array_push(&rp, "--reflog");
+       }
+       if (rev_list_index) {
+               use_internal_rev_list = 1;
+               argv_array_push(&rp, "--indexed-objects");
        }
        if (rev_list_unpacked) {
                use_internal_rev_list = 1;
-               rp_av[rp_ac++] = "--unpacked";
+               argv_array_push(&rp, "--unpacked");
        }
 
        if (!reuse_object)
@@ -2687,6 +2743,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                pack_compression_level = Z_DEFAULT_COMPRESSION;
        else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)
                die("bad pack compression level %d", pack_compression_level);
+
+       if (!delta_search_threads)      /* --threads=0 means autodetect */
+               delta_search_threads = online_cpus();
+
 #ifdef NO_PTHREADS
        if (delta_search_threads != 1)
                warning("no threads support, ignoring --threads");
@@ -2705,6 +2765,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 
        if (keep_unreachable && unpack_unreachable)
                die("--keep-unreachable and --unpack-unreachable are incompatible.");
+       if (!rev_list_all || !rev_list_reflog || !rev_list_index)
+               unpack_unreachable_expiration = 0;
 
        if (!use_internal_rev_list || !pack_to_stdout || is_repository_shallow())
                use_bitmap_index = 0;
@@ -2722,8 +2784,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (!use_internal_rev_list)
                read_object_list_from_stdin();
        else {
-               rp_av[rp_ac] = NULL;
-               get_object_list(rp_ac, rp_av);
+               get_object_list(rp.argc, rp.argv);
+               argv_array_clear(&rp);
        }
        cleanup_preferred_base();
        if (include_tag && nr_result)