Signed-off-by: Mark Thomas <mar...@efaref.net>
---
 builtin/pack-objects.c | 26 ++++++++++++++++++++++++--
 list-objects.c         | 12 +++++++-----
 list-objects.h         | 13 ++++++++++++-
 object.h               |  1 +
 on_demand.c            | 26 ++++++++++++++++++++++++++
 on_demand.h            |  4 ++++
 upload-pack.c          |  8 +++++++-
 7 files changed, 81 insertions(+), 9 deletions(-)

diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index f294dcf..c8b2503 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -24,6 +24,7 @@
 #include "sha1-array.h"
 #include "argv-array.h"
 #include "mru.h"
+#include "on_demand.h"
 
 static const char *pack_usage[] = {
        N_("git pack-objects --stdout [<options>...] [< <ref-list> | < 
<object-list>]"),
@@ -77,6 +78,8 @@ static unsigned long cache_max_small_delta_size = 1000;
 
 static unsigned long window_memory_limit = 0;
 
+static int send_all_commits;
+
 /*
  * stats
  */
@@ -2750,12 +2753,15 @@ static void record_recent_commit(struct commit *commit, 
void *data)
 static void get_object_list(int ac, const char **av)
 {
        struct rev_info revs;
+       struct rev_info revs2;
        char line[1000];
        int flags = 0;
 
        init_revisions(&revs, NULL);
+       init_revisions(&revs2, NULL);
        save_commit_buffer = 0;
        setup_revisions(ac, av, &revs, NULL);
+       setup_revisions(ac, av, &revs2, NULL);
 
        /* make sure shallows are read */
        is_repository_shallow();
@@ -2776,7 +2782,10 @@ static void get_object_list(int ac, const char **av)
                                unsigned char sha1[20];
                                if (get_sha1_hex(line + 10, sha1))
                                        die("not an SHA-1 '%s'", line + 10);
-                               register_shallow(sha1);
+                               if (send_all_commits)
+                                       register_on_demand_cutoff(sha1);
+                               else
+                                       register_shallow(sha1);
                                use_bitmap_index = 0;
                                continue;
                        }
@@ -2784,6 +2793,8 @@ static void get_object_list(int ac, const char **av)
                }
                if (handle_revision_arg(line, &revs, flags, 
REVARG_CANNOT_BE_FILENAME))
                        die("bad revision '%s'", line);
+               if (handle_revision_arg(line, &revs2, flags, 
REVARG_CANNOT_BE_FILENAME))
+                       die("bad revision '%s'", line);
        }
 
        if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
@@ -2792,7 +2803,16 @@ static void get_object_list(int ac, const char **av)
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
        mark_edges_uninteresting(&revs, show_edge);
-       traverse_commit_list(&revs, show_commit, show_object, NULL);
+
+       if (send_all_commits) {
+               revs2.include_check = on_demand_include_check;
+               traverse_commit_list(&revs2, on_demand_show_commit_tree, NULL,
+                                    NULL);
+               reset_revision_walk();
+       }
+
+       traverse_commit_list_extended(&revs, show_commit, show_object,
+                                     on_demand_show_tree_check, NULL);
 
        if (unpack_unreachable_expiration) {
                revs.ignore_missing_links = 1;
@@ -2928,6 +2948,8 @@ int cmd_pack_objects(int argc, const char **argv, const 
char *prefix)
                         N_("use a bitmap index if available to speed up 
counting objects")),
                OPT_BOOL(0, "write-bitmap-index", &write_bitmap_index,
                         N_("write a bitmap index together with the pack 
index")),
+               OPT_BOOL(0, "send-all-commits", &send_all_commits,
+                        N_("send all commits for on-demand shallow fetches")),
                OPT_END(),
        };
 
diff --git a/list-objects.c b/list-objects.c
index f3ca6aa..2607549 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -183,10 +183,11 @@ static void add_pending_tree(struct rev_info *revs, 
struct tree *tree)
        add_pending_object(revs, &tree->object, "");
 }
 
-void traverse_commit_list(struct rev_info *revs,
-                         show_commit_fn show_commit,
-                         show_object_fn show_object,
-                         void *data)
+void traverse_commit_list_extended(struct rev_info *revs,
+                                  show_commit_fn show_commit,
+                                  show_object_fn show_object,
+                                  show_tree_check_fn show_tree_check,
+                                  void *data)
 {
        int i;
        struct commit *commit;
@@ -198,7 +199,8 @@ void traverse_commit_list(struct rev_info *revs,
                 * an uninteresting boundary commit may not have its tree
                 * parsed yet, but we are not going to show them anyway
                 */
-               if (commit->tree)
+               if (show_object && commit->tree &&
+                   (!show_tree_check || show_tree_check(commit, data)))
                        add_pending_tree(revs, commit->tree);
                show_commit(commit, data);
        }
diff --git a/list-objects.h b/list-objects.h
index 0cebf85..e80dc8c 100644
--- a/list-objects.h
+++ b/list-objects.h
@@ -3,7 +3,18 @@
 
 typedef void (*show_commit_fn)(struct commit *, void *);
 typedef void (*show_object_fn)(struct object *, const char *, void *);
-void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, 
void *);
+typedef int (*show_tree_check_fn)(struct commit *, void *);
+void traverse_commit_list_extended(struct rev_info *, show_commit_fn,
+                                  show_object_fn, show_tree_check_fn, void *);
+
+inline void traverse_commit_list(struct rev_info *revs,
+                                show_commit_fn show_commit,
+                                show_object_fn show_object,
+                                void *data)
+{
+       traverse_commit_list_extended(revs, show_commit, show_object, NULL,
+                                     data);
+}
 
 typedef void (*show_edge_fn)(struct commit *);
 void mark_edges_uninteresting(struct rev_info *, show_edge_fn);
diff --git a/object.h b/object.h
index f52957d..25177fd 100644
--- a/object.h
+++ b/object.h
@@ -38,6 +38,7 @@ struct object_array {
  * http-push.c:                            16-----19
  * commit.c:                               16-----19
  * sha1_name.c:                                     20
+ * on_demand.c:                                       21-22
  */
 #define FLAG_BITS  27
 
diff --git a/on_demand.c b/on_demand.c
index a0aaf18..c72d7a5 100644
--- a/on_demand.c
+++ b/on_demand.c
@@ -155,3 +155,29 @@ int object_info_on_demand(const unsigned char *sha1, 
struct object_info *oi)
        die("git on-demand: protocol error, "
            "unexpected response: '%s'", line);
 }
+
+#define ON_DEMAND_CUTOFF       (1u << 21)
+#define ON_DEMAND_SHOW_TREE    (1u << 22)
+
+void register_on_demand_cutoff(const unsigned char *sha1)
+{
+       struct commit *commit = lookup_commit(sha1);
+       if (commit)
+               commit->object.flags |= ON_DEMAND_CUTOFF;
+}
+
+int on_demand_include_check(struct commit *commit, void *data)
+{
+       return !(commit->object.flags & ON_DEMAND_CUTOFF);
+}
+
+void on_demand_show_commit_tree(struct commit *commit, void *data)
+{
+       commit->object.flags |= ON_DEMAND_SHOW_TREE;
+}
+
+int on_demand_show_tree_check(struct commit *commit, void *data)
+{
+       return !!(commit->object.flags &
+                 (ON_DEMAND_SHOW_TREE|ON_DEMAND_CUTOFF));
+}
diff --git a/on_demand.h b/on_demand.h
index 09a8072..7bbb523 100644
--- a/on_demand.h
+++ b/on_demand.h
@@ -4,5 +4,9 @@
 void *read_remote_on_demand(const unsigned char *sha1, enum object_type *type,
                            unsigned long *size);
 int object_info_on_demand(const unsigned char *sha1, struct object_info *oi);
+void register_on_demand_cutoff(const unsigned char *sha1);
+int on_demand_include_check(struct commit *commit, void *data);
+void on_demand_show_commit_tree(struct commit *commit, void *data);
+int on_demand_show_tree_check(struct commit *commit, void *data);
 
 #endif
diff --git a/upload-pack.c b/upload-pack.c
index 7597ba3..1b552b4 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -42,6 +42,7 @@ static int multi_ack;
 static int no_done;
 static int use_thin_pack, use_ofs_delta, use_include_tag;
 static int no_progress, daemon_mode;
+static int send_all_commits;
 /* Allow specifying sha1 if it is a ref tip. */
 #define ALLOW_TIP_SHA1 01
 /* Allow request of a sha1 if it is reachable from a ref (possibly hidden 
ref). */
@@ -130,6 +131,8 @@ static void create_pack_file(void)
                argv_array_push(&pack_objects.args, "--delta-base-offset");
        if (use_include_tag)
                argv_array_push(&pack_objects.args, "--include-tag");
+       if (send_all_commits)
+               argv_array_push(&pack_objects.args, "--send-all-commits");
 
        pack_objects.in = -1;
        pack_objects.out = -1;
@@ -820,6 +823,8 @@ static void receive_needs(void)
                        no_progress = 1;
                if (parse_feature_request(features, "include-tag"))
                        use_include_tag = 1;
+               if (parse_feature_request(features, "on-demand"))
+                       send_all_commits = 1;
 
                o = parse_object(sha1_buf);
                if (!o)
@@ -924,7 +929,8 @@ static int send_ref(const char *refname, const struct 
object_id *oid,
 {
        static const char *capabilities = "multi_ack thin-pack side-band"
                " side-band-64k ofs-delta shallow deepen-since deepen-not"
-               " deepen-relative no-progress include-tag multi_ack_detailed";
+               " deepen-relative no-progress include-tag multi_ack_detailed"
+               " on-demand";
        const char *refname_nons = strip_namespace(refname);
        struct object_id peeled;
 
-- 
2.7.4

Reply via email to