Git fork

Merge branch 'jt/rev-list-missing-print-info'

"git rev-list --missing=" learned to accept "print-info" that gives
known details expected of the missing objects, like path and type.

* jt/rev-list-missing-print-info:
rev-list: extend print-info to print missing object type
rev-list: add print-info action to print missing object path

+161 -17
+19
Documentation/rev-list-options.adoc
··· 1024 1024 The form '--missing=print' is like 'allow-any', but will also print a 1025 1025 list of the missing objects. Object IDs are prefixed with a ``?'' character. 1026 1026 + 1027 + The form '--missing=print-info' is like 'print', but will also print additional 1028 + information about the missing object inferred from its containing object. The 1029 + information is all printed on the same line with the missing object ID in the 1030 + form: `?<oid> [<token>=<value>]...`. The `<token>=<value>` pairs containing 1031 + additional information are separated from each other by a SP. The value is 1032 + encoded in a token specific fashion, but SP or LF contained in value are always 1033 + expected to be represented in such a way that the resulting encoded value does 1034 + not have either of these two problematic bytes. Each `<token>=<value>` may be 1035 + one of the following: 1036 + + 1037 + -- 1038 + * The `path=<path>` shows the path of the missing object inferred from a 1039 + containing object. A path containing SP or special characters is enclosed in 1040 + double-quotes in the C style as needed. 1041 + + 1042 + * The `type=<type>` shows the type of the missing object inferred from a 1043 + containing object. 1044 + -- 1045 + + 1027 1046 If some tips passed to the traversal are missing, they will be 1028 1047 considered as missing too, and the traversal will ignore them. In case 1029 1048 we cannot get their Object ID though, an error will be raised.
+89 -17
builtin/rev-list.c
··· 22 22 #include "progress.h" 23 23 #include "reflog-walk.h" 24 24 #include "oidset.h" 25 + #include "oidmap.h" 25 26 #include "packfile.h" 27 + #include "quote.h" 28 + #include "strbuf.h" 26 29 27 30 static const char rev_list_usage[] = 28 31 "git rev-list [<options>] <commit>... [--] [<path>...]\n" ··· 73 76 static struct oidset omitted_objects; 74 77 static int arg_print_omitted; /* print objects omitted by filter */ 75 78 76 - static struct oidset missing_objects; 79 + struct missing_objects_map_entry { 80 + struct oidmap_entry entry; 81 + const char *path; 82 + unsigned type; 83 + }; 84 + static struct oidmap missing_objects; 77 85 enum missing_action { 78 86 MA_ERROR = 0, /* fail if any missing objects are encountered */ 79 87 MA_ALLOW_ANY, /* silently allow ALL missing objects */ 80 88 MA_PRINT, /* print ALL missing objects in special section */ 89 + MA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */ 81 90 MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */ 82 91 }; 83 92 static enum missing_action arg_missing_action; ··· 101 110 return size; 102 111 } 103 112 104 - static inline void finish_object__ma(struct object *obj) 113 + static void add_missing_object_entry(struct object_id *oid, const char *path, 114 + unsigned type) 115 + { 116 + struct missing_objects_map_entry *entry; 117 + 118 + if (oidmap_get(&missing_objects, oid)) 119 + return; 120 + 121 + CALLOC_ARRAY(entry, 1); 122 + entry->entry.oid = *oid; 123 + entry->type = type; 124 + if (path) 125 + entry->path = xstrdup(path); 126 + oidmap_put(&missing_objects, entry); 127 + } 128 + 129 + static void print_missing_object(struct missing_objects_map_entry *entry, 130 + int print_missing_info) 131 + { 132 + struct strbuf sb = STRBUF_INIT; 133 + 134 + if (!print_missing_info) { 135 + printf("?%s\n", oid_to_hex(&entry->entry.oid)); 136 + return; 137 + } 138 + 139 + if (entry->path && *entry->path) { 140 + struct strbuf path = STRBUF_INIT; 141 + 142 + strbuf_addstr(&sb, " path="); 143 + quote_path(entry->path, NULL, &path, QUOTE_PATH_QUOTE_SP); 144 + strbuf_addbuf(&sb, &path); 145 + 146 + strbuf_release(&path); 147 + } 148 + if (entry->type) 149 + strbuf_addf(&sb, " type=%s", type_name(entry->type)); 150 + 151 + printf("?%s%s\n", oid_to_hex(&entry->entry.oid), sb.buf); 152 + strbuf_release(&sb); 153 + } 154 + 155 + static inline void finish_object__ma(struct object *obj, const char *name) 105 156 { 106 157 /* 107 158 * Whether or not we try to dynamically fetch missing objects ··· 119 170 return; 120 171 121 172 case MA_PRINT: 122 - oidset_insert(&missing_objects, &obj->oid); 173 + case MA_PRINT_INFO: 174 + add_missing_object_entry(&obj->oid, name, obj->type); 123 175 return; 124 176 125 177 case MA_ALLOW_PROMISOR: ··· 152 204 153 205 if (revs->do_not_die_on_missing_objects && 154 206 oidset_contains(&revs->missing_commits, &commit->object.oid)) { 155 - finish_object__ma(&commit->object); 207 + finish_object__ma(&commit->object, NULL); 156 208 return; 157 209 } 158 210 ··· 268 320 finish_commit(commit); 269 321 } 270 322 271 - static int finish_object(struct object *obj, const char *name UNUSED, 272 - void *cb_data) 323 + static int finish_object(struct object *obj, const char *name, void *cb_data) 273 324 { 274 325 struct rev_list_info *info = cb_data; 275 326 if (oid_object_info_extended(the_repository, &obj->oid, NULL, 0) < 0) { 276 - finish_object__ma(obj); 327 + finish_object__ma(obj, name); 277 328 return 1; 278 329 } 279 330 if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT) ··· 410 461 411 462 if (!strcmp(value, "print")) { 412 463 arg_missing_action = MA_PRINT; 464 + fetch_if_missing = 0; 465 + return 1; 466 + } 467 + 468 + if (!strcmp(value, "print-info")) { 469 + arg_missing_action = MA_PRINT_INFO; 413 470 fetch_if_missing = 0; 414 471 return 1; 415 472 } ··· 781 838 782 839 if (arg_print_omitted) 783 840 oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE); 784 - if (arg_missing_action == MA_PRINT) { 785 - oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE); 841 + if (arg_missing_action == MA_PRINT || 842 + arg_missing_action == MA_PRINT_INFO) { 843 + struct oidset_iter iter; 844 + struct object_id *oid; 845 + 846 + oidmap_init(&missing_objects, DEFAULT_OIDSET_SIZE); 847 + oidset_iter_init(&revs.missing_commits, &iter); 848 + 786 849 /* Add missing tips */ 787 - oidset_insert_from_set(&missing_objects, &revs.missing_commits); 850 + while ((oid = oidset_iter_next(&iter))) 851 + add_missing_object_entry(oid, NULL, 0); 852 + 788 853 oidset_clear(&revs.missing_commits); 789 854 } 790 855 ··· 800 865 printf("~%s\n", oid_to_hex(oid)); 801 866 oidset_clear(&omitted_objects); 802 867 } 803 - if (arg_missing_action == MA_PRINT) { 804 - struct oidset_iter iter; 805 - struct object_id *oid; 806 - oidset_iter_init(&missing_objects, &iter); 807 - while ((oid = oidset_iter_next(&iter))) 808 - printf("?%s\n", oid_to_hex(oid)); 809 - oidset_clear(&missing_objects); 868 + if (arg_missing_action == MA_PRINT || 869 + arg_missing_action == MA_PRINT_INFO) { 870 + struct missing_objects_map_entry *entry; 871 + struct oidmap_iter iter; 872 + 873 + oidmap_iter_init(&missing_objects, &iter); 874 + 875 + while ((entry = oidmap_iter_next(&iter))) { 876 + print_missing_object(entry, arg_missing_action == 877 + MA_PRINT_INFO); 878 + free((void *)entry->path); 879 + } 880 + 881 + oidmap_free(&missing_objects, true); 810 882 } 811 883 812 884 stop_progress(&progress);
+53
t/t6022-rev-list-missing.sh
··· 145 145 done 146 146 done 147 147 148 + for obj in "HEAD~1" "HEAD^{tree}" "HEAD:foo" "HEAD:foo/bar" "HEAD:baz baz" 149 + do 150 + test_expect_success "--missing=print-info with missing '$obj'" ' 151 + test_when_finished rm -rf missing-info && 152 + 153 + git init missing-info && 154 + ( 155 + cd missing-info && 156 + git commit --allow-empty -m first && 157 + 158 + mkdir foo && 159 + echo bar >foo/bar && 160 + echo baz >"baz baz" && 161 + echo bat >bat\" && 162 + git add -A && 163 + git commit -m second && 164 + 165 + oid="$(git rev-parse "$obj")" && 166 + path=".git/objects/$(test_oid_to_path $oid)" && 167 + type_info=" type=$(git cat-file -t $oid)" && 168 + 169 + case $obj in 170 + HEAD:foo) 171 + path_info=" path=foo" 172 + ;; 173 + HEAD:foo/bar) 174 + path_info=" path=foo/bar" 175 + ;; 176 + "HEAD:baz baz") 177 + path_info=" path=\"baz baz\"" 178 + ;; 179 + "HEAD:bat\"") 180 + path_info=" path=\"bat\\\"\"" 181 + ;; 182 + esac && 183 + 184 + # Before the object is made missing, we use rev-list to 185 + # get the expected oids. 186 + git rev-list --objects --no-object-names \ 187 + HEAD ^"$obj" >expect.raw && 188 + echo "?$oid$path_info$type_info" >>expect.raw && 189 + 190 + mv "$path" "$path.hidden" && 191 + git rev-list --objects --no-object-names \ 192 + --missing=print-info HEAD >actual.raw && 193 + 194 + sort actual.raw >actual && 195 + sort expect.raw >expect && 196 + test_cmp expect actual 197 + ) 198 + ' 199 + done 200 + 148 201 test_done