The sixteenth batch
[git/gitster.git] / shallow.c
blobef3adb635fdb9ca625ed10bd30a760962f140471
1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
4 #include "hex.h"
5 #include "repository.h"
6 #include "tempfile.h"
7 #include "lockfile.h"
8 #include "odb.h"
9 #include "commit.h"
10 #include "tag.h"
11 #include "pkt-line.h"
12 #include "refs.h"
13 #include "oid-array.h"
14 #include "path.h"
15 #include "diff.h"
16 #include "revision.h"
17 #include "commit-slab.h"
18 #include "list-objects.h"
19 #include "commit-reach.h"
20 #include "shallow.h"
21 #include "statinfo.h"
22 #include "trace.h"
24 void set_alternate_shallow_file(struct repository *r, const char *path, int override)
26 if (r->parsed_objects->is_shallow != -1)
27 BUG("is_repository_shallow must not be called before set_alternate_shallow_file");
28 if (r->parsed_objects->alternate_shallow_file && !override)
29 return;
30 free(r->parsed_objects->alternate_shallow_file);
31 r->parsed_objects->alternate_shallow_file = xstrdup_or_null(path);
34 int register_shallow(struct repository *r, const struct object_id *oid)
36 struct commit_graft *graft =
37 xmalloc(sizeof(struct commit_graft));
38 struct commit *commit = lookup_commit(r, oid);
40 oidcpy(&graft->oid, oid);
41 graft->nr_parent = -1;
42 if (commit && commit->object.parsed) {
43 free_commit_list(commit->parents);
44 commit->parents = NULL;
46 return register_commit_graft(r, graft, 0);
49 int unregister_shallow(const struct object_id *oid)
51 int pos = commit_graft_pos(the_repository, oid);
52 if (pos < 0)
53 return -1;
54 free(the_repository->parsed_objects->grafts[pos]);
55 if (pos + 1 < the_repository->parsed_objects->grafts_nr)
56 MOVE_ARRAY(the_repository->parsed_objects->grafts + pos,
57 the_repository->parsed_objects->grafts + pos + 1,
58 the_repository->parsed_objects->grafts_nr - pos - 1);
59 the_repository->parsed_objects->grafts_nr--;
60 return 0;
63 int is_repository_shallow(struct repository *r)
65 FILE *fp;
66 char buf[1024];
67 const char *path = r->parsed_objects->alternate_shallow_file;
69 if (r->parsed_objects->is_shallow >= 0)
70 return r->parsed_objects->is_shallow;
72 if (!path)
73 path = git_path_shallow(r);
75 * fetch-pack sets '--shallow-file ""' as an indicator that no
76 * shallow file should be used. We could just open it and it
77 * will likely fail. But let's do an explicit check instead.
79 if (!*path || (fp = fopen(path, "r")) == NULL) {
80 stat_validity_clear(r->parsed_objects->shallow_stat);
81 r->parsed_objects->is_shallow = 0;
82 return r->parsed_objects->is_shallow;
84 stat_validity_update(r->parsed_objects->shallow_stat, fileno(fp));
85 r->parsed_objects->is_shallow = 1;
87 while (fgets(buf, sizeof(buf), fp)) {
88 struct object_id oid;
89 if (get_oid_hex(buf, &oid))
90 die("bad shallow line: %s", buf);
91 register_shallow(r, &oid);
93 fclose(fp);
94 return r->parsed_objects->is_shallow;
97 static void reset_repository_shallow(struct repository *r)
99 r->parsed_objects->is_shallow = -1;
100 stat_validity_clear(r->parsed_objects->shallow_stat);
101 parsed_object_pool_reset_commit_grafts(r->parsed_objects);
104 int commit_shallow_file(struct repository *r, struct shallow_lock *lk)
106 int res = commit_lock_file(&lk->lock);
107 reset_repository_shallow(r);
110 * Update in-memory data structures with the new shallow information,
111 * including unparsing all commits that now have grafts.
113 is_repository_shallow(r);
115 return res;
118 void rollback_shallow_file(struct repository *r, struct shallow_lock *lk)
120 rollback_lock_file(&lk->lock);
121 reset_repository_shallow(r);
125 * TODO: use "int" elemtype instead of "int *" when/if commit-slab
126 * supports a "valid" flag.
128 define_commit_slab(commit_depth, int *);
129 static void free_depth_in_slab(int **ptr)
131 FREE_AND_NULL(*ptr);
133 struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
134 int shallow_flag, int not_shallow_flag)
136 size_t i = 0;
137 int cur_depth = 0;
138 struct commit_list *result = NULL;
139 struct object_array stack = OBJECT_ARRAY_INIT;
140 struct commit *commit = NULL;
141 struct commit_graft *graft;
142 struct commit_depth depths;
144 init_commit_depth(&depths);
145 while (commit || i < heads->nr || stack.nr) {
146 struct commit_list *p;
147 if (!commit) {
148 if (i < heads->nr) {
149 int **depth_slot;
150 commit = (struct commit *)
151 deref_tag(the_repository,
152 heads->objects[i++].item,
153 NULL, 0);
154 if (!commit || commit->object.type != OBJ_COMMIT) {
155 commit = NULL;
156 continue;
158 depth_slot = commit_depth_at(&depths, commit);
159 if (!*depth_slot)
160 *depth_slot = xmalloc(sizeof(int));
161 **depth_slot = 0;
162 cur_depth = 0;
163 } else {
164 commit = (struct commit *)
165 object_array_pop(&stack);
166 cur_depth = **commit_depth_at(&depths, commit);
169 parse_commit_or_die(commit);
170 cur_depth++;
171 if ((depth != INFINITE_DEPTH && cur_depth >= depth) ||
172 (is_repository_shallow(the_repository) && !commit->parents &&
173 (graft = lookup_commit_graft(the_repository, &commit->object.oid)) != NULL &&
174 graft->nr_parent < 0)) {
175 commit_list_insert(commit, &result);
176 commit->object.flags |= shallow_flag;
177 commit = NULL;
178 continue;
180 commit->object.flags |= not_shallow_flag;
181 for (p = commit->parents, commit = NULL; p; p = p->next) {
182 int **depth_slot = commit_depth_at(&depths, p->item);
183 if (!*depth_slot) {
184 *depth_slot = xmalloc(sizeof(int));
185 **depth_slot = cur_depth;
186 } else {
187 if (cur_depth >= **depth_slot)
188 continue;
189 **depth_slot = cur_depth;
191 if (p->next)
192 add_object_array(&p->item->object,
193 NULL, &stack);
194 else {
195 commit = p->item;
196 cur_depth = **commit_depth_at(&depths, commit);
200 deep_clear_commit_depth(&depths, free_depth_in_slab);
202 return result;
205 static void show_commit(struct commit *commit, void *data)
207 commit_list_insert(commit, data);
211 * Given rev-list arguments, run rev-list. All reachable commits
212 * except border ones are marked with not_shallow_flag. Border commits
213 * are marked with shallow_flag. The list of border/shallow commits
214 * are also returned.
216 struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av,
217 int shallow_flag,
218 int not_shallow_flag)
220 struct commit_list *result = NULL, *p;
221 struct commit_list *not_shallow_list = NULL;
222 struct rev_info revs;
223 int both_flags = shallow_flag | not_shallow_flag;
226 * SHALLOW (excluded) and NOT_SHALLOW (included) should not be
227 * set at this point. But better be safe than sorry.
229 clear_object_flags(the_repository, both_flags);
231 is_repository_shallow(the_repository); /* make sure shallows are read */
233 repo_init_revisions(the_repository, &revs, NULL);
234 save_commit_buffer = 0;
235 setup_revisions(ac, av, &revs, NULL);
237 if (prepare_revision_walk(&revs))
238 die("revision walk setup failed");
239 traverse_commit_list(&revs, show_commit, NULL, &not_shallow_list);
241 if (!not_shallow_list)
242 die("no commits selected for shallow requests");
244 /* Mark all reachable commits as NOT_SHALLOW */
245 for (p = not_shallow_list; p; p = p->next)
246 p->item->object.flags |= not_shallow_flag;
249 * mark border commits SHALLOW + NOT_SHALLOW.
250 * We cannot clear NOT_SHALLOW right now. Imagine border
251 * commit A is processed first, then commit B, whose parent is
252 * A, later. If NOT_SHALLOW on A is cleared at step 1, B
253 * itself is considered border at step 2, which is incorrect.
255 for (p = not_shallow_list; p; p = p->next) {
256 struct commit *c = p->item;
257 struct commit_list *parent;
259 if (repo_parse_commit(the_repository, c))
260 die("unable to parse commit %s",
261 oid_to_hex(&c->object.oid));
263 for (parent = c->parents; parent; parent = parent->next)
264 if (!(parent->item->object.flags & not_shallow_flag)) {
265 c->object.flags |= shallow_flag;
266 commit_list_insert(c, &result);
267 break;
270 free_commit_list(not_shallow_list);
273 * Now we can clean up NOT_SHALLOW on border commits. Having
274 * both flags set can confuse the caller.
276 for (p = result; p; p = p->next) {
277 struct object *o = &p->item->object;
278 if ((o->flags & both_flags) == both_flags)
279 o->flags &= ~not_shallow_flag;
281 release_revisions(&revs);
282 return result;
285 static void check_shallow_file_for_update(struct repository *r)
287 if (r->parsed_objects->is_shallow == -1)
288 BUG("shallow must be initialized by now");
290 if (!stat_validity_check(r->parsed_objects->shallow_stat,
291 git_path_shallow(r)))
292 die("shallow file has changed since we read it");
295 #define SEEN_ONLY 1
296 #define VERBOSE 2
297 #define QUICK 4
299 struct write_shallow_data {
300 struct strbuf *out;
301 int use_pack_protocol;
302 int count;
303 unsigned flags;
306 static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
308 struct write_shallow_data *data = cb_data;
309 const char *hex = oid_to_hex(&graft->oid);
310 if (graft->nr_parent != -1)
311 return 0;
312 if (data->flags & QUICK) {
313 if (!odb_has_object(the_repository->objects, &graft->oid,
314 HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
315 return 0;
316 } else if (data->flags & SEEN_ONLY) {
317 struct commit *c = lookup_commit(the_repository, &graft->oid);
318 if (!c || !(c->object.flags & SEEN)) {
319 if (data->flags & VERBOSE)
320 printf("Removing %s from .git/shallow\n",
321 oid_to_hex(&c->object.oid));
322 return 0;
325 data->count++;
326 if (data->use_pack_protocol)
327 packet_buf_write(data->out, "shallow %s", hex);
328 else {
329 strbuf_addstr(data->out, hex);
330 strbuf_addch(data->out, '\n');
332 return 0;
335 static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol,
336 const struct oid_array *extra,
337 unsigned flags)
339 struct write_shallow_data data = {
340 .out = out,
341 .use_pack_protocol = use_pack_protocol,
342 .flags = flags,
345 for_each_commit_graft(write_one_shallow, &data);
346 if (!extra)
347 return data.count;
348 for (size_t i = 0; i < extra->nr; i++) {
349 strbuf_addstr(out, oid_to_hex(extra->oid + i));
350 strbuf_addch(out, '\n');
351 data.count++;
353 return data.count;
356 int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
357 const struct oid_array *extra)
359 return write_shallow_commits_1(out, use_pack_protocol, extra, 0);
362 const char *setup_temporary_shallow(const struct oid_array *extra)
364 struct tempfile *temp;
365 struct strbuf sb = STRBUF_INIT;
367 if (write_shallow_commits(&sb, 0, extra)) {
368 char *path = repo_git_path(the_repository, "shallow_XXXXXX");
369 temp = xmks_tempfile(path);
370 free(path);
372 if (write_in_full(temp->fd, sb.buf, sb.len) < 0 ||
373 close_tempfile_gently(temp) < 0)
374 die_errno("failed to write to %s",
375 get_tempfile_path(temp));
376 strbuf_release(&sb);
377 return get_tempfile_path(temp);
380 * is_repository_shallow() sees empty string as "no shallow
381 * file".
383 return "";
386 void setup_alternate_shallow(struct shallow_lock *shallow_lock,
387 const char **alternate_shallow_file,
388 const struct oid_array *extra)
390 struct strbuf sb = STRBUF_INIT;
391 int fd;
393 fd = hold_lock_file_for_update(&shallow_lock->lock,
394 git_path_shallow(the_repository),
395 LOCK_DIE_ON_ERROR);
396 check_shallow_file_for_update(the_repository);
397 if (write_shallow_commits(&sb, 0, extra)) {
398 if (write_in_full(fd, sb.buf, sb.len) < 0)
399 die_errno("failed to write to %s",
400 get_lock_file_path(&shallow_lock->lock));
401 *alternate_shallow_file = get_lock_file_path(&shallow_lock->lock);
402 } else
404 * is_repository_shallow() sees empty string as "no
405 * shallow file".
407 *alternate_shallow_file = "";
408 strbuf_release(&sb);
411 static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *cb)
413 int fd = *(int *)cb;
414 if (graft->nr_parent == -1)
415 packet_write_fmt(fd, "shallow %s\n", oid_to_hex(&graft->oid));
416 return 0;
419 void advertise_shallow_grafts(int fd)
421 if (!is_repository_shallow(the_repository))
422 return;
423 for_each_commit_graft(advertise_shallow_grafts_cb, &fd);
427 * mark_reachable_objects() should have been run prior to this and all
428 * reachable commits marked as "SEEN", except when quick_prune is non-zero,
429 * in which case lines are excised from the shallow file if they refer to
430 * commits that do not exist (any longer).
432 void prune_shallow(unsigned options)
434 struct shallow_lock shallow_lock = SHALLOW_LOCK_INIT;
435 struct strbuf sb = STRBUF_INIT;
436 unsigned flags = SEEN_ONLY;
437 int fd;
439 if (options & PRUNE_QUICK)
440 flags |= QUICK;
442 if (options & PRUNE_SHOW_ONLY) {
443 flags |= VERBOSE;
444 write_shallow_commits_1(&sb, 0, NULL, flags);
445 strbuf_release(&sb);
446 return;
448 fd = hold_lock_file_for_update(&shallow_lock.lock,
449 git_path_shallow(the_repository),
450 LOCK_DIE_ON_ERROR);
451 check_shallow_file_for_update(the_repository);
452 if (write_shallow_commits_1(&sb, 0, NULL, flags)) {
453 if (write_in_full(fd, sb.buf, sb.len) < 0)
454 die_errno("failed to write to %s",
455 get_lock_file_path(&shallow_lock.lock));
456 commit_shallow_file(the_repository, &shallow_lock);
457 } else {
458 unlink(git_path_shallow(the_repository));
459 rollback_shallow_file(the_repository, &shallow_lock);
461 strbuf_release(&sb);
464 struct trace_key trace_shallow = TRACE_KEY_INIT(SHALLOW);
467 * Step 1, split sender shallow commits into "ours" and "theirs"
468 * Step 2, clean "ours" based on .git/shallow
470 void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
472 trace_printf_key(&trace_shallow, "shallow: prepare_shallow_info\n");
473 memset(info, 0, sizeof(*info));
474 info->shallow = sa;
475 if (!sa)
476 return;
477 ALLOC_ARRAY(info->ours, sa->nr);
478 ALLOC_ARRAY(info->theirs, sa->nr);
479 for (size_t i = 0; i < sa->nr; i++) {
480 if (odb_has_object(the_repository->objects, sa->oid + i,
481 HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) {
482 struct commit_graft *graft;
483 graft = lookup_commit_graft(the_repository,
484 &sa->oid[i]);
485 if (graft && graft->nr_parent < 0)
486 continue;
487 info->ours[info->nr_ours++] = i;
488 } else
489 info->theirs[info->nr_theirs++] = i;
493 void clear_shallow_info(struct shallow_info *info)
495 if (info->used_shallow) {
496 for (size_t i = 0; i < info->shallow->nr; i++)
497 free(info->used_shallow[i]);
498 free(info->used_shallow);
501 free(info->need_reachability_test);
502 free(info->reachable);
503 free(info->shallow_ref);
504 free(info->ours);
505 free(info->theirs);
508 /* Step 4, remove non-existent ones in "theirs" after getting the pack */
510 void remove_nonexistent_theirs_shallow(struct shallow_info *info)
512 struct object_id *oid = info->shallow->oid;
513 size_t i, dst;
514 trace_printf_key(&trace_shallow, "shallow: remove_nonexistent_theirs_shallow\n");
515 for (i = dst = 0; i < info->nr_theirs; i++) {
516 if (i != dst)
517 info->theirs[dst] = info->theirs[i];
518 if (odb_has_object(the_repository->objects, oid + info->theirs[i],
519 HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
520 dst++;
522 info->nr_theirs = dst;
525 define_commit_slab(ref_bitmap, uint32_t *);
527 #define POOL_SIZE (512 * 1024)
529 struct paint_info {
530 struct ref_bitmap ref_bitmap;
531 unsigned nr_bits;
532 char **pools;
533 char *free, *end;
534 unsigned pool_count;
537 static uint32_t *paint_alloc(struct paint_info *info)
539 unsigned nr = DIV_ROUND_UP(info->nr_bits, 32);
540 unsigned size = nr * sizeof(uint32_t);
541 void *p;
542 if (!info->pool_count || info->end < info->free + size) {
543 if (size > POOL_SIZE)
544 BUG("pool size too small for %d in paint_alloc()",
545 size);
546 info->pool_count++;
547 REALLOC_ARRAY(info->pools, info->pool_count);
548 info->free = xmalloc(POOL_SIZE);
549 info->pools[info->pool_count - 1] = info->free;
550 info->end = info->free + POOL_SIZE;
552 p = info->free;
553 info->free += size;
554 return p;
558 * Given a commit SHA-1, walk down to parents until either SEEN,
559 * UNINTERESTING or BOTTOM is hit. Set the id-th bit in ref_bitmap for
560 * all walked commits.
562 static void paint_down(struct paint_info *info, const struct object_id *oid,
563 unsigned int id)
565 unsigned int i, nr;
566 struct commit_list *head = NULL;
567 size_t bitmap_nr = DIV_ROUND_UP(info->nr_bits, 32);
568 size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr);
569 struct commit *c = lookup_commit_reference_gently(the_repository, oid,
571 uint32_t *tmp; /* to be freed before return */
572 uint32_t *bitmap;
574 if (!c)
575 return;
577 tmp = xmalloc(bitmap_size);
578 bitmap = paint_alloc(info);
579 memset(bitmap, 0, bitmap_size);
580 bitmap[id / 32] |= (1U << (id % 32));
581 commit_list_insert(c, &head);
582 while (head) {
583 struct commit_list *p;
584 struct commit *c = pop_commit(&head);
585 uint32_t **refs = ref_bitmap_at(&info->ref_bitmap, c);
587 /* XXX check "UNINTERESTING" from pack bitmaps if available */
588 if (c->object.flags & (SEEN | UNINTERESTING))
589 continue;
590 else
591 c->object.flags |= SEEN;
593 if (!*refs)
594 *refs = bitmap;
595 else {
596 memcpy(tmp, *refs, bitmap_size);
597 for (i = 0; i < bitmap_nr; i++)
598 tmp[i] |= bitmap[i];
599 if (memcmp(tmp, *refs, bitmap_size)) {
600 *refs = paint_alloc(info);
601 memcpy(*refs, tmp, bitmap_size);
605 if (c->object.flags & BOTTOM)
606 continue;
608 if (repo_parse_commit(the_repository, c))
609 die("unable to parse commit %s",
610 oid_to_hex(&c->object.oid));
612 for (p = c->parents; p; p = p->next) {
613 if (p->item->object.flags & SEEN)
614 continue;
615 commit_list_insert(p->item, &head);
619 nr = get_max_object_index(the_repository);
620 for (i = 0; i < nr; i++) {
621 struct object *o = get_indexed_object(the_repository, i);
622 if (o && o->type == OBJ_COMMIT)
623 o->flags &= ~SEEN;
626 free(tmp);
629 static int mark_uninteresting(const char *refname UNUSED,
630 const char *referent UNUSED,
631 const struct object_id *oid,
632 int flags UNUSED,
633 void *cb_data UNUSED)
635 struct commit *commit = lookup_commit_reference_gently(the_repository,
636 oid, 1);
637 if (!commit)
638 return 0;
639 commit->object.flags |= UNINTERESTING;
640 mark_parents_uninteresting(NULL, commit);
641 return 0;
644 static void post_assign_shallow(struct shallow_info *info,
645 struct ref_bitmap *ref_bitmap,
646 int *ref_status);
648 * Step 6(+7), associate shallow commits with new refs
650 * info->ref must be initialized before calling this function.
652 * If used is not NULL, it's an array of info->shallow->nr
653 * bitmaps. The n-th bit set in the m-th bitmap if ref[n] needs the
654 * m-th shallow commit from info->shallow.
656 * If used is NULL, "ours" and "theirs" are updated. And if ref_status
657 * is not NULL it's an array of ref->nr ints. ref_status[i] is true if
658 * the ref needs some shallow commits from either info->ours or
659 * info->theirs.
661 void assign_shallow_commits_to_refs(struct shallow_info *info,
662 uint32_t **used, int *ref_status)
664 struct object_id *oid = info->shallow->oid;
665 struct oid_array *ref = info->ref;
666 unsigned int i, nr;
667 size_t *shallow, nr_shallow = 0;
668 struct paint_info pi;
670 trace_printf_key(&trace_shallow, "shallow: assign_shallow_commits_to_refs\n");
671 ALLOC_ARRAY(shallow, info->nr_ours + info->nr_theirs);
672 for (i = 0; i < info->nr_ours; i++)
673 shallow[nr_shallow++] = info->ours[i];
674 for (i = 0; i < info->nr_theirs; i++)
675 shallow[nr_shallow++] = info->theirs[i];
678 * Prepare the commit graph to track what refs can reach what
679 * (new) shallow commits.
681 nr = get_max_object_index(the_repository);
682 for (i = 0; i < nr; i++) {
683 struct object *o = get_indexed_object(the_repository, i);
684 if (!o || o->type != OBJ_COMMIT)
685 continue;
687 o->flags &= ~(UNINTERESTING | BOTTOM | SEEN);
690 memset(&pi, 0, sizeof(pi));
691 init_ref_bitmap(&pi.ref_bitmap);
692 pi.nr_bits = ref->nr;
695 * "--not --all" to cut short the traversal if new refs
696 * connect to old refs. If not (e.g. force ref updates) it'll
697 * have to go down to the current shallow commits.
699 refs_head_ref(get_main_ref_store(the_repository), mark_uninteresting,
700 NULL);
701 refs_for_each_ref(get_main_ref_store(the_repository),
702 mark_uninteresting, NULL);
704 /* Mark potential bottoms so we won't go out of bound */
705 for (i = 0; i < nr_shallow; i++) {
706 struct commit *c = lookup_commit(the_repository,
707 &oid[shallow[i]]);
708 c->object.flags |= BOTTOM;
711 for (i = 0; i < ref->nr; i++)
712 paint_down(&pi, ref->oid + i, i);
714 if (used) {
715 int bitmap_size = DIV_ROUND_UP(pi.nr_bits, 32) * sizeof(uint32_t);
716 memset(used, 0, sizeof(*used) * info->shallow->nr);
717 for (i = 0; i < nr_shallow; i++) {
718 const struct commit *c = lookup_commit(the_repository,
719 &oid[shallow[i]]);
720 uint32_t **map = ref_bitmap_at(&pi.ref_bitmap, c);
721 if (*map)
722 used[shallow[i]] = xmemdupz(*map, bitmap_size);
725 * unreachable shallow commits are not removed from
726 * "ours" and "theirs". The user is supposed to run
727 * step 7 on every ref separately and not trust "ours"
728 * and "theirs" any more.
730 } else
731 post_assign_shallow(info, &pi.ref_bitmap, ref_status);
733 clear_ref_bitmap(&pi.ref_bitmap);
734 for (i = 0; i < pi.pool_count; i++)
735 free(pi.pools[i]);
736 free(pi.pools);
737 free(shallow);
740 struct commit_array {
741 struct commit **commits;
742 size_t nr, alloc;
745 static int add_ref(const char *refname UNUSED,
746 const char *referent UNUSED,
747 const struct object_id *oid,
748 int flags UNUSED,
749 void *cb_data)
751 struct commit_array *ca = cb_data;
752 ALLOC_GROW(ca->commits, ca->nr + 1, ca->alloc);
753 ca->commits[ca->nr] = lookup_commit_reference_gently(the_repository,
754 oid, 1);
755 if (ca->commits[ca->nr])
756 ca->nr++;
757 return 0;
760 static void update_refstatus(int *ref_status, size_t nr, uint32_t *bitmap)
762 if (!ref_status)
763 return;
764 for (size_t i = 0; i < nr; i++)
765 if (bitmap[i / 32] & (1U << (i % 32)))
766 ref_status[i]++;
770 * Step 7, reachability test on "ours" at commit level
772 static void post_assign_shallow(struct shallow_info *info,
773 struct ref_bitmap *ref_bitmap,
774 int *ref_status)
776 struct object_id *oid = info->shallow->oid;
777 struct commit *c;
778 uint32_t **bitmap;
779 size_t dst, i, j;
780 size_t bitmap_nr = DIV_ROUND_UP(info->ref->nr, 32);
781 struct commit_array ca;
783 trace_printf_key(&trace_shallow, "shallow: post_assign_shallow\n");
784 if (ref_status)
785 memset(ref_status, 0, sizeof(*ref_status) * info->ref->nr);
787 /* Remove unreachable shallow commits from "theirs" */
788 for (i = dst = 0; i < info->nr_theirs; i++) {
789 if (i != dst)
790 info->theirs[dst] = info->theirs[i];
791 c = lookup_commit(the_repository, &oid[info->theirs[i]]);
792 bitmap = ref_bitmap_at(ref_bitmap, c);
793 if (!*bitmap)
794 continue;
795 for (j = 0; j < bitmap_nr; j++)
796 if (bitmap[0][j]) {
797 update_refstatus(ref_status, info->ref->nr, *bitmap);
798 dst++;
799 break;
802 info->nr_theirs = dst;
804 memset(&ca, 0, sizeof(ca));
805 refs_head_ref(get_main_ref_store(the_repository), add_ref, &ca);
806 refs_for_each_ref(get_main_ref_store(the_repository), add_ref, &ca);
808 /* Remove unreachable shallow commits from "ours" */
809 for (i = dst = 0; i < info->nr_ours; i++) {
810 if (i != dst)
811 info->ours[dst] = info->ours[i];
812 c = lookup_commit(the_repository, &oid[info->ours[i]]);
813 bitmap = ref_bitmap_at(ref_bitmap, c);
814 if (!*bitmap)
815 continue;
816 for (j = 0; j < bitmap_nr; j++)
817 if (bitmap[0][j]) {
818 /* Step 7, reachability test at commit level */
819 int ret = repo_in_merge_bases_many(the_repository, c, ca.nr, ca.commits, 1);
820 if (ret < 0)
821 exit(128);
822 if (!ret) {
823 update_refstatus(ref_status, info->ref->nr, *bitmap);
824 dst++;
825 break;
829 info->nr_ours = dst;
831 free(ca.commits);
834 /* (Delayed) step 7, reachability test at commit level */
835 int delayed_reachability_test(struct shallow_info *si, int c)
837 if (si->need_reachability_test[c]) {
838 struct commit *commit = lookup_commit(the_repository,
839 &si->shallow->oid[c]);
841 if (!si->commits) {
842 struct commit_array ca;
844 memset(&ca, 0, sizeof(ca));
845 refs_head_ref(get_main_ref_store(the_repository),
846 add_ref, &ca);
847 refs_for_each_ref(get_main_ref_store(the_repository),
848 add_ref, &ca);
849 si->commits = ca.commits;
850 si->nr_commits = ca.nr;
853 si->reachable[c] = repo_in_merge_bases_many(the_repository,
854 commit,
855 si->nr_commits,
856 si->commits,
858 if (si->reachable[c] < 0)
859 exit(128);
860 si->need_reachability_test[c] = 0;
862 return si->reachable[c];