Skip to content

Commit 7722b99

Browse files
committed
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
2 parents 345aaf3 + 3295c35 commit 7722b99

File tree

3 files changed

+161
-17
lines changed

3 files changed

+161
-17
lines changed

Documentation/rev-list-options.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,25 @@ Unexpected missing objects will raise an error.
10241024
The form '--missing=print' is like 'allow-any', but will also print a
10251025
list of the missing objects. Object IDs are prefixed with a ``?'' character.
10261026
+
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+
+
10271046
If some tips passed to the traversal are missing, they will be
10281047
considered as missing too, and the traversal will ignore them. In case
10291048
we cannot get their Object ID though, an error will be raised.

builtin/rev-list.c

Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
#include "progress.h"
2323
#include "reflog-walk.h"
2424
#include "oidset.h"
25+
#include "oidmap.h"
2526
#include "packfile.h"
27+
#include "quote.h"
28+
#include "strbuf.h"
2629

2730
static const char rev_list_usage[] =
2831
"git rev-list [<options>] <commit>... [--] [<path>...]\n"
@@ -73,11 +76,17 @@ static unsigned progress_counter;
7376
static struct oidset omitted_objects;
7477
static int arg_print_omitted; /* print objects omitted by filter */
7578

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;
7785
enum missing_action {
7886
MA_ERROR = 0, /* fail if any missing objects are encountered */
7987
MA_ALLOW_ANY, /* silently allow ALL missing objects */
8088
MA_PRINT, /* print ALL missing objects in special section */
89+
MA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */
8190
MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
8291
};
8392
static enum missing_action arg_missing_action;
@@ -101,7 +110,49 @@ static off_t get_object_disk_usage(struct object *obj)
101110
return size;
102111
}
103112

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)
105156
{
106157
/*
107158
* Whether or not we try to dynamically fetch missing objects
@@ -119,7 +170,8 @@ static inline void finish_object__ma(struct object *obj)
119170
return;
120171

121172
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);
123175
return;
124176

125177
case MA_ALLOW_PROMISOR:
@@ -152,7 +204,7 @@ static void show_commit(struct commit *commit, void *data)
152204

153205
if (revs->do_not_die_on_missing_objects &&
154206
oidset_contains(&revs->missing_commits, &commit->object.oid)) {
155-
finish_object__ma(&commit->object);
207+
finish_object__ma(&commit->object, NULL);
156208
return;
157209
}
158210

@@ -268,12 +320,11 @@ static void show_commit(struct commit *commit, void *data)
268320
finish_commit(commit);
269321
}
270322

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)
273324
{
274325
struct rev_list_info *info = cb_data;
275326
if (oid_object_info_extended(the_repository, &obj->oid, NULL, 0) < 0) {
276-
finish_object__ma(obj);
327+
finish_object__ma(obj, name);
277328
return 1;
278329
}
279330
if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
@@ -414,6 +465,12 @@ static inline int parse_missing_action_value(const char *value)
414465
return 1;
415466
}
416467

468+
if (!strcmp(value, "print-info")) {
469+
arg_missing_action = MA_PRINT_INFO;
470+
fetch_if_missing = 0;
471+
return 1;
472+
}
473+
417474
if (!strcmp(value, "allow-promisor")) {
418475
arg_missing_action = MA_ALLOW_PROMISOR;
419476
fetch_if_missing = 0;
@@ -781,10 +838,18 @@ int cmd_rev_list(int argc,
781838

782839
if (arg_print_omitted)
783840
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+
786849
/* 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+
788853
oidset_clear(&revs.missing_commits);
789854
}
790855

@@ -800,13 +865,20 @@ int cmd_rev_list(int argc,
800865
printf("~%s\n", oid_to_hex(oid));
801866
oidset_clear(&omitted_objects);
802867
}
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);
810882
}
811883

812884
stop_progress(&progress);

t/t6022-rev-list-missing.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,57 @@ do
145145
done
146146
done
147147

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+
148201
test_done

0 commit comments

Comments
 (0)