290
STDIN_PACKS_MODE_NONE,
291
STDIN_PACKS_MODE_STANDARD,
292
STDIN_PACKS_MODE_FOLLOW,
293
+ STDIN_PACKS_MODE_FOLLOW_REACHABLE,
294
};
295
296
/**
3836
void *data)
3837
{
3838
enum stdin_packs_mode mode = *(enum stdin_packs_mode *)data;
3838
- if (mode == STDIN_PACKS_MODE_FOLLOW) {
3839
+ if (mode == STDIN_PACKS_MODE_FOLLOW ||
3840
+ mode == STDIN_PACKS_MODE_FOLLOW_REACHABLE) {
3841
if (object->type == OBJ_BLOB &&
3842
!odb_has_object(the_repository->objects, &object->oid, 0))
3843
return;
3868
{
3869
enum stdin_packs_mode mode = *(enum stdin_packs_mode *)data;
3870
3869
- if (mode == STDIN_PACKS_MODE_FOLLOW) {
3871
+ if (mode == STDIN_PACKS_MODE_FOLLOW ||
3872
+ mode == STDIN_PACKS_MODE_FOLLOW_REACHABLE) {
3873
show_object_pack_hint((struct object *)commit, "", data);
3874
return;
3875
}
3936
return stdin_packs_include_check_obj((struct object *)commit, data);
3937
}
3938
3939
+/*
3940
+ * Flag bit set on commits that belong to an included pack during
3941
+ * '--stdin-packs=follow-reachable'. Used by the pre-walk to
3942
+ * identify which reachable commits should be tips for the main
3943
+ * object traversal.
3944
+ */
3945
+#define IN_INCLUDED_PACK (1u<<11)
3946
+
3947
+static int mark_included_pack_tip(const struct object_id *oid,
3948
+ struct packed_git *p,
3949
+ uint32_t pos,
3950
+ void *data)
3951
+{
3952
+ struct rev_info *main_revs = data;
3953
+ off_t ofs = nth_packed_object_offset(p, pos);
3954
+ enum object_type type;
3955
+ struct object_info oi = OBJECT_INFO_INIT;
3956
+ struct object *obj;
3957
+
3958
+ oi.typep = &type;
3959
+ if (packed_object_info(p, ofs, &oi) < 0)
3960
+ return 0;
3961
+ if (type != OBJ_COMMIT && type != OBJ_TAG)
3962
+ return 0;
3963
+
3964
+ obj = parse_object(the_repository, oid);
3965
+ if (!obj)
3966
+ return 0;
3967
+
3968
+ obj->flags |= IN_INCLUDED_PACK;
3969
+
3970
+ if (type == OBJ_TAG && main_revs)
3971
+ add_pending_object(main_revs, obj, "");
3972
+ return 0;
3973
+}
3974
+
3975
+static int mark_loose_object_tip(const struct object_id *oid,
3976
+ struct object_info *oi UNUSED,
3977
+ void *data)
3978
+{
3979
+ struct rev_info *main_revs = data;
3980
+ struct object *obj;
3981
+ enum object_type type;
3982
+
3983
+ type = odb_read_object_info(the_repository->objects, oid, NULL);
3984
+ if (type != OBJ_COMMIT && type != OBJ_TAG)
3985
+ return 0;
3986
+
3987
+ obj = parse_object(the_repository, oid);
3988
+ if (!obj)
3989
+ return 0;
3990
+
3991
+ obj->flags |= IN_INCLUDED_PACK;
3992
+
3993
+ if (type == OBJ_TAG && main_revs)
3994
+ add_pending_object(main_revs, obj, "");
3995
+
3996
+ return 0;
3997
+}
3998
+
3999
+static int add_ref_to_pending(const struct reference *ref, void *cb_data)
4000
+{
4001
+ struct rev_info *revs = cb_data;
4002
+ struct object *object;
4003
+
4004
+ object = parse_object(the_repository, ref->oid);
4005
+ if (!object)
4006
+ return 0;
4007
+
4008
+ add_pending_object(revs, object, "");
4009
+ return 0;
4010
+}
4011
+
4012
+static void stdin_packs_add_reachable_pack_entries(struct string_list *keys,
4013
+ struct rev_info *revs,
4014
+ int rev_list_unpacked)
4015
+{
4016
+ struct rev_info pre_walk;
4017
+ struct commit *commit;
4018
+ struct string_list_item *item;
4019
+
4020
+ /*
4021
+ * Phase 1: mark commits in included packs, then walk from
4022
+ * ref tips to discover which of them are reachable. The walk
4023
+ * halts at excluded-closed packs (via no_kept_objects) and
4024
+ * continues through excluded-open ones.
4025
+ *
4026
+ * Also set include_check on the outer revs so that phase 2
4027
+ * (the main object traversal) halts at closed packs.
4028
+ */
4029
+ revs->include_check = stdin_packs_include_check;
4030
+ revs->include_check_obj = stdin_packs_include_check_obj;
4031
+
4032
+ for_each_string_list_item(item, keys) {
4033
+ struct stdin_pack_info *info = item->util;
4034
+ if (info->kind & STDIN_PACK_INCLUDE)
4035
+ for_each_object_in_pack(info->p,
4036
+ mark_included_pack_tip,
4037
+ revs,
4038
+ ODB_FOR_EACH_OBJECT_PACK_ORDER);
4039
+ }
4040
+
4041
+ if (rev_list_unpacked) {
4042
+ /*
4043
+ * With '--stdin-packs=follow-reachable', specifying
4044
+ * '--unpacked' instructs pack-objects to pack any loose
4045
+ * objects which are reachable.
4046
+ *
4047
+ * Pretend as if all loose objects are in an included
4048
+ * pack in order to make them eligible for packing.
4049
+ */
4050
+ struct odb_source *source = revs->repo->objects->sources;
4051
+ for (; source; source = source->next) {
4052
+ struct odb_source_files *files = odb_source_files_downcast(source);
4053
+ struct odb_for_each_object_options opts = { 0 };
4054
+ if (local)
4055
+ opts.flags |= ODB_FOR_EACH_OBJECT_LOCAL_ONLY;
4056
+
4057
+ odb_source_for_each_object(&files->loose->base, NULL,
4058
+ mark_loose_object_tip,
4059
+ revs, &opts);
4060
+ }
4061
+ }
4062
+
4063
+ repo_init_revisions(the_repository, &pre_walk, NULL);
4064
+ pre_walk.no_kept_objects = 1;
4065
+ pre_walk.keep_pack_cache_flags |= KEPT_PACK_IN_CORE;
4066
+ pre_walk.ignore_missing_links = 1;
4067
+
4068
+ refs_for_each_ref(get_main_ref_store(the_repository),
4069
+ add_ref_to_pending, &pre_walk);
4070
+
4071
+ if (prepare_revision_walk(&pre_walk))
4072
+ die(_("revision walk setup failed"));
4073
+
4074
+ /*
4075
+ * Phase 2 tips: every reachable commit that is in an
4076
+ * included pack becomes a starting point for the main
4077
+ * object traversal.
4078
+ */
4079
+ while ((commit = get_revision(&pre_walk)) != NULL) {
4080
+ if (commit->object.flags & IN_INCLUDED_PACK)
4081
+ add_pending_oid(revs, NULL,
4082
+ &commit->object.oid, 0);
4083
+ }
4084
+
4085
+ reset_revision_walk();
4086
+ release_revisions(&pre_walk);
4087
+}
4088
+
4089
static void stdin_packs_add_all_pack_entries(struct string_list *keys,
4090
struct rev_info *revs)
4091
{
4115
}
4116
4117
static void stdin_packs_add_pack_entries(struct strmap *packs,
3965
- struct rev_info *revs)
4118
+ struct rev_info *revs,
4119
+ enum stdin_packs_mode mode,
4120
+ int rev_list_unpacked)
4121
{
4122
struct string_list keys = STRING_LIST_INIT_NODUP;
4123
struct hashmap_iter iter;
4138
*/
4139
QSORT(keys.items, keys.nr, pack_mtime_cmp);
4140
3986
- stdin_packs_add_all_pack_entries(&keys, revs);
4141
+ if (mode == STDIN_PACKS_MODE_FOLLOW_REACHABLE)
4142
+ stdin_packs_add_reachable_pack_entries(&keys, revs,
4143
+ rev_list_unpacked);
4144
+ else
4145
+ stdin_packs_add_all_pack_entries(&keys, revs);
4146
4147
string_list_clear(&keys, 0);
4148
}
4149
4150
static void stdin_packs_read_input(struct rev_info *revs,
3992
- enum stdin_packs_mode mode)
4151
+ enum stdin_packs_mode mode,
4152
+ int rev_list_unpacked)
4153
{
4154
struct strbuf buf = STRBUF_INIT;
4155
struct strmap packs = STRMAP_INIT;
4164
continue;
4165
else if (*key == '^')
4166
kind = STDIN_PACK_EXCLUDE_CLOSED;
4007
- else if (*key == '!' && mode == STDIN_PACKS_MODE_FOLLOW)
4167
+ else if (*key == '!' &&
4168
+ (mode == STDIN_PACKS_MODE_FOLLOW ||
4169
+ mode == STDIN_PACKS_MODE_FOLLOW_REACHABLE))
4170
kind = STDIN_PACK_EXCLUDE_OPEN;
4171
4172
if (kind != STDIN_PACK_INCLUDE)
4231
info->p = p;
4232
}
4233
4072
- stdin_packs_add_pack_entries(&packs, revs);
4234
+ stdin_packs_add_pack_entries(&packs, revs, mode, rev_list_unpacked);
4235
4236
strbuf_release(&buf);
4237
strmap_clear(&packs, 1);
4271
4272
/* avoids adding objects in excluded packs */
4273
ignore_packed_keep_in_core = 1;
4112
- if (mode == STDIN_PACKS_MODE_FOLLOW) {
4274
+ if (mode == STDIN_PACKS_MODE_FOLLOW ||
4275
+ mode == STDIN_PACKS_MODE_FOLLOW_REACHABLE) {
4276
/*
4277
* In '--stdin-packs=follow' mode, additionally ignore
4278
* objects in excluded-open packs to prevent them from
4280
*/
4281
ignore_packed_keep_in_core_open = 1;
4282
}
4120
- stdin_packs_read_input(&revs, mode);
4121
- if (rev_list_unpacked)
4283
+ stdin_packs_read_input(&revs, mode, rev_list_unpacked);
4284
+ if (rev_list_unpacked && mode != STDIN_PACKS_MODE_FOLLOW_REACHABLE)
4285
add_unreachable_loose_objects(&revs);
4286
4287
if (prepare_revision_walk(&revs))
5190
*mode = STDIN_PACKS_MODE_STANDARD;
5191
else if (!strcmp(arg, "follow"))
5192
*mode = STDIN_PACKS_MODE_FOLLOW;
5193
+ else if (!strcmp(arg, "follow-reachable"))
5194
+ *mode = STDIN_PACKS_MODE_FOLLOW_REACHABLE;
5195
else
5196
die(_("invalid value for '%s': '%s'"), opt->long_name, arg);
5197