Git fork

Merge branch 'ds/path-walk-repack-fix' into maint-2.51

"git repack --path-walk" lost objects in some corner cases, which
has been corrected.
cf. <CABPp-BHFxxGrqKc0m==TjQNjDGdO=H5Rf6EFsf2nfE1=TuraOQ@mail.gmail.com>

* ds/path-walk-repack-fix:
path-walk: create initializer for path lists
path-walk: fix setup of pending objects

+88 -30
+25 -30
path-walk.c
··· 105 prio_queue_put(&ctx->path_stack, xstrdup(path)); 106 } 107 108 static int add_tree_entries(struct path_walk_context *ctx, 109 const char *base_path, 110 struct object_id *oid) ··· 129 130 init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); 131 while (tree_entry(&desc, &entry)) { 132 - struct type_and_oid_list *list; 133 struct object *o; 134 /* Not actually true, but we will ignore submodules later. */ 135 enum object_type type = S_ISDIR(entry.mode) ? OBJ_TREE : OBJ_BLOB; ··· 190 continue; 191 } 192 193 - if (!(list = strmap_get(&ctx->paths_to_lists, path.buf))) { 194 - CALLOC_ARRAY(list, 1); 195 - list->type = type; 196 - strmap_put(&ctx->paths_to_lists, path.buf, list); 197 - } 198 push_to_stack(ctx, path.buf); 199 - 200 - if (!(o->flags & UNINTERESTING)) 201 - list->maybe_interesting = 1; 202 - 203 - oid_array_append(&list->oids, &entry.oid); 204 } 205 206 free_tree_buffer(tree); ··· 377 if (!info->trees) 378 continue; 379 if (pending->path) { 380 - struct type_and_oid_list *list; 381 char *path = *pending->path ? xstrfmt("%s/", pending->path) 382 : xstrdup(""); 383 - if (!(list = strmap_get(&ctx->paths_to_lists, path))) { 384 - CALLOC_ARRAY(list, 1); 385 - list->type = OBJ_TREE; 386 - strmap_put(&ctx->paths_to_lists, path, list); 387 - } 388 - oid_array_append(&list->oids, &obj->oid); 389 free(path); 390 } else { 391 /* assume a root tree, such as a lightweight tag. */ ··· 396 case OBJ_BLOB: 397 if (!info->blobs) 398 continue; 399 - if (pending->path) { 400 - struct type_and_oid_list *list; 401 - char *path = pending->path; 402 - if (!(list = strmap_get(&ctx->paths_to_lists, path))) { 403 - CALLOC_ARRAY(list, 1); 404 - list->type = OBJ_BLOB; 405 - strmap_put(&ctx->paths_to_lists, path, list); 406 - } 407 - oid_array_append(&list->oids, &obj->oid); 408 - } else { 409 - /* assume a root tree, such as a lightweight tag. */ 410 oid_array_append(&tagged_blobs->oids, &obj->oid); 411 - } 412 break; 413 414 case OBJ_COMMIT:
··· 105 prio_queue_put(&ctx->path_stack, xstrdup(path)); 106 } 107 108 + static void add_path_to_list(struct path_walk_context *ctx, 109 + const char *path, 110 + enum object_type type, 111 + struct object_id *oid, 112 + int interesting) 113 + { 114 + struct type_and_oid_list *list = strmap_get(&ctx->paths_to_lists, path); 115 + 116 + if (!list) { 117 + CALLOC_ARRAY(list, 1); 118 + list->type = type; 119 + strmap_put(&ctx->paths_to_lists, path, list); 120 + } 121 + 122 + list->maybe_interesting |= interesting; 123 + oid_array_append(&list->oids, oid); 124 + } 125 + 126 static int add_tree_entries(struct path_walk_context *ctx, 127 const char *base_path, 128 struct object_id *oid) ··· 147 148 init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); 149 while (tree_entry(&desc, &entry)) { 150 struct object *o; 151 /* Not actually true, but we will ignore submodules later. */ 152 enum object_type type = S_ISDIR(entry.mode) ? OBJ_TREE : OBJ_BLOB; ··· 207 continue; 208 } 209 210 + add_path_to_list(ctx, path.buf, type, &entry.oid, 211 + !(o->flags & UNINTERESTING)); 212 + 213 push_to_stack(ctx, path.buf); 214 } 215 216 free_tree_buffer(tree); ··· 387 if (!info->trees) 388 continue; 389 if (pending->path) { 390 char *path = *pending->path ? xstrfmt("%s/", pending->path) 391 : xstrdup(""); 392 + add_path_to_list(ctx, path, OBJ_TREE, &obj->oid, 1); 393 free(path); 394 } else { 395 /* assume a root tree, such as a lightweight tag. */ ··· 400 case OBJ_BLOB: 401 if (!info->blobs) 402 continue; 403 + if (pending->path) 404 + add_path_to_list(ctx, pending->path, OBJ_BLOB, &obj->oid, 1); 405 + else 406 oid_array_append(&tagged_blobs->oids, &obj->oid); 407 break; 408 409 case OBJ_COMMIT:
+63
t/t7700-repack.sh
··· 838 test_server_info_missing 839 ' 840 841 test_done
··· 838 test_server_info_missing 839 ' 840 841 + test_expect_success 'pending objects are repacked appropriately' ' 842 + test_when_finished rm -rf pending && 843 + git init pending && 844 + 845 + ( 846 + cd pending && 847 + 848 + # Commit file, a/b/c and never change them. 849 + mkdir -p a/b && 850 + echo singleton >file && 851 + echo stuff >a/b/c && 852 + echo more >a/d && 853 + git add file a && 854 + git commit -m "single blobs" && 855 + 856 + # Files a/d and a/e will not be singletons. 857 + echo d >a/d && 858 + echo e >a/e && 859 + git add a && 860 + git commit -m "more blobs" && 861 + 862 + # This use of a sparse index helps to force 863 + # test that the cache-tree is walked, too. 864 + git sparse-checkout set --sparse-index a x && 865 + 866 + # Create staged changes: 867 + # * a/e now has multiple versions. 868 + # * a/i now has only one version. 869 + echo f >a/d && 870 + echo h >a/e && 871 + echo i >a/i && 872 + git add a && 873 + 874 + # Stage and unstage a change to make use of 875 + # resolve-undo cache and how that impacts fsck. 876 + mkdir x && 877 + echo y >x/y && 878 + git add x && 879 + xy=$(git rev-parse :x/y) && 880 + git rm --cached x/y && 881 + 882 + # The blob for x/y must persist through repacks, 883 + # but fsck currently ignores the REUC extension 884 + # for finding links to the blob. 885 + cat >expect <<-EOF && 886 + dangling blob $xy 887 + EOF 888 + 889 + # Bring the loose objects into a packfile to avoid 890 + # leftovers in next test. Without this, the loose 891 + # objects persist and the test succeeds for other 892 + # reasons. 893 + git repack -adf && 894 + git fsck >out && 895 + test_cmp expect out && 896 + 897 + # Test path walk version with pack.useSparse. 898 + git -c pack.useSparse=true repack -adf --path-walk && 899 + git fsck >out && 900 + test_cmp expect out 901 + ) 902 + ' 903 + 904 test_done