Skip to content

Commit 76d1cd8

Browse files
committed
Merge branch 'cc/rev-list-allow-missing-tips'
"git rev-list --missing=print" has learned to optionally take "--allow-missing-tips", which allows the objects at the starting points to be missing. * cc/rev-list-allow-missing-tips: revision: fix --missing=[print|allow*] for annotated tags rev-list: allow missing tips with --missing=[print|allow*] t6022: fix 'test' style and 'even though' typo oidset: refactor oidset_insert_from_set() revision: clarify a 'return NULL' in get_reference()
2 parents 2c206fc + a4324ba commit 76d1cd8

File tree

7 files changed

+129
-19
lines changed

7 files changed

+129
-19
lines changed

Documentation/rev-list-options.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,10 @@ Unexpected missing objects will raise an error.
10191019
+
10201020
The form '--missing=print' is like 'allow-any', but will also print a
10211021
list of the missing objects. Object IDs are prefixed with a ``?'' character.
1022+
+
1023+
If some tips passed to the traversal are missing, they will be
1024+
considered as missing too, and the traversal will ignore them. In case
1025+
we cannot get their Object ID though, an error will be raised.
10221026

10231027
--exclude-promisor-objects::
10241028
(For internal use only.) Prefilter object traversal at

builtin/rev-list.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,18 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
545545
*
546546
* Let "--missing" to conditionally set fetch_if_missing.
547547
*/
548+
/*
549+
* NEEDSWORK: These loops that attempt to find presence of
550+
* options without understanding that the options they are
551+
* skipping are broken (e.g., it would not know "--grep
552+
* --exclude-promisor-objects" is not triggering
553+
* "--exclude-promisor-objects" option). We really need
554+
* setup_revisions() to have a mechanism to allow and disallow
555+
* some sets of options for different commands (like rev-list,
556+
* replay, etc). Such a mechanism should do an early parsing
557+
* of options and be able to manage the `--missing=...` and
558+
* `--exclude-promisor-objects` options below.
559+
*/
548560
for (i = 1; i < argc; i++) {
549561
const char *arg = argv[i];
550562
if (!strcmp(arg, "--exclude-promisor-objects")) {
@@ -753,8 +765,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
753765

754766
if (arg_print_omitted)
755767
oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
756-
if (arg_missing_action == MA_PRINT)
768+
if (arg_missing_action == MA_PRINT) {
757769
oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
770+
/* Add missing tips */
771+
oidset_insert_from_set(&missing_objects, &revs.missing_commits);
772+
oidset_clear(&revs.missing_commits);
773+
}
758774

759775
traverse_commit_list_filtered(
760776
&revs, show_commit, show_object, &info,

list-objects-filter.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -711,15 +711,6 @@ static void filter_combine__free(void *filter_data)
711711
free(d);
712712
}
713713

714-
static void add_all(struct oidset *dest, struct oidset *src) {
715-
struct oidset_iter iter;
716-
struct object_id *src_oid;
717-
718-
oidset_iter_init(src, &iter);
719-
while ((src_oid = oidset_iter_next(&iter)) != NULL)
720-
oidset_insert(dest, src_oid);
721-
}
722-
723714
static void filter_combine__finalize_omits(
724715
struct oidset *omits,
725716
void *filter_data)
@@ -728,7 +719,7 @@ static void filter_combine__finalize_omits(
728719
size_t sub;
729720

730721
for (sub = 0; sub < d->nr; sub++) {
731-
add_all(omits, &d->sub[sub].omits);
722+
oidset_insert_from_set(omits, &d->sub[sub].omits);
732723
oidset_clear(&d->sub[sub].omits);
733724
}
734725
}

oidset.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ int oidset_insert(struct oidset *set, const struct object_id *oid)
2323
return !added;
2424
}
2525

26+
void oidset_insert_from_set(struct oidset *dest, struct oidset *src)
27+
{
28+
struct oidset_iter iter;
29+
struct object_id *src_oid;
30+
31+
oidset_iter_init(src, &iter);
32+
while ((src_oid = oidset_iter_next(&iter)))
33+
oidset_insert(dest, src_oid);
34+
}
35+
2636
int oidset_remove(struct oidset *set, const struct object_id *oid)
2737
{
2838
khiter_t pos = kh_get_oid_set(&set->set, *oid);

oidset.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ int oidset_contains(const struct oidset *set, const struct object_id *oid);
4747
*/
4848
int oidset_insert(struct oidset *set, const struct object_id *oid);
4949

50+
/**
51+
* Insert all the oids that are in set 'src' into set 'dest'; a copy
52+
* is made of each oid inserted into set 'dest'.
53+
*/
54+
void oidset_insert_from_set(struct oidset *dest, struct oidset *src);
55+
5056
/**
5157
* Remove the oid from the set.
5258
*

revision.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,13 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
385385

386386
if (!object) {
387387
if (revs->ignore_missing)
388-
return object;
388+
return NULL;
389389
if (revs->exclude_promisor_objects && is_promisor_object(oid))
390390
return NULL;
391+
if (revs->do_not_die_on_missing_objects) {
392+
oidset_insert(&revs->missing_commits, oid);
393+
return NULL;
394+
}
391395
die("bad object %s", name);
392396
}
393397
object->flags |= flags;
@@ -415,15 +419,21 @@ static struct commit *handle_commit(struct rev_info *revs,
415419
*/
416420
while (object->type == OBJ_TAG) {
417421
struct tag *tag = (struct tag *) object;
422+
struct object_id *oid;
418423
if (revs->tag_objects && !(flags & UNINTERESTING))
419424
add_pending_object(revs, object, tag->tag);
420-
object = parse_object(revs->repo, get_tagged_oid(tag));
425+
oid = get_tagged_oid(tag);
426+
object = parse_object(revs->repo, oid);
421427
if (!object) {
422428
if (revs->ignore_missing_links || (flags & UNINTERESTING))
423429
return NULL;
424430
if (revs->exclude_promisor_objects &&
425431
is_promisor_object(&tag->tagged->oid))
426432
return NULL;
433+
if (revs->do_not_die_on_missing_objects && oid) {
434+
oidset_insert(&revs->missing_commits, oid);
435+
return NULL;
436+
}
427437
die("bad object %s", oid_to_hex(&tag->tagged->oid));
428438
}
429439
object->flags |= flags;
@@ -1945,6 +1955,7 @@ void repo_init_revisions(struct repository *r,
19451955
init_display_notes(&revs->notes_opt);
19461956
list_objects_filter_init(&revs->filter);
19471957
init_ref_exclusions(&revs->ref_excludes);
1958+
oidset_init(&revs->missing_commits, 0);
19481959
}
19491960

19501961
static void add_pending_commit_list(struct rev_info *revs,
@@ -2176,13 +2187,18 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
21762187
if (revarg_opt & REVARG_COMMITTISH)
21772188
get_sha1_flags |= GET_OID_COMMITTISH;
21782189

2190+
/*
2191+
* Even if revs->do_not_die_on_missing_objects is set, we
2192+
* should error out if we can't even get an oid, as
2193+
* `--missing=print` should be able to report missing oids.
2194+
*/
21792195
if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc))
21802196
return revs->ignore_missing ? 0 : -1;
21812197
if (!cant_be_filename)
21822198
verify_non_filename(revs->prefix, arg);
21832199
object = get_reference(revs, arg, &oid, flags ^ local_flags);
21842200
if (!object)
2185-
return revs->ignore_missing ? 0 : -1;
2201+
return (revs->ignore_missing || revs->do_not_die_on_missing_objects) ? 0 : -1;
21862202
add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
21872203
add_pending_object_with_path(revs, object, arg, oc.mode, oc.path);
21882204
free(oc.path);
@@ -3828,8 +3844,6 @@ int prepare_revision_walk(struct rev_info *revs)
38283844
FOR_EACH_OBJECT_PROMISOR_ONLY);
38293845
}
38303846

3831-
oidset_init(&revs->missing_commits, 0);
3832-
38333847
if (!revs->reflog_info)
38343848
prepare_to_use_bloom_filter(revs);
38353849
if (!revs->unsorted_input)

t/t6022-rev-list-missing.sh

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ TEST_PASSES_SANITIZE_LEAK=true
1010
test_expect_success 'create repository and alternate directory' '
1111
test_commit 1 &&
1212
test_commit 2 &&
13-
test_commit 3
13+
test_commit 3 &&
14+
git tag -m "tag message" annot_tag HEAD~1 &&
15+
git tag regul_tag HEAD~1 &&
16+
git branch a_branch HEAD~1
1417
'
1518

1619
# We manually corrupt the repository, which means that the commit-graph may
@@ -46,9 +49,10 @@ do
4649
git rev-list --objects --no-object-names \
4750
HEAD ^$obj >expect.raw &&
4851
49-
# Blobs are shared by all commits, so evethough a commit/tree
52+
# Blobs are shared by all commits, so even though a commit/tree
5053
# might be skipped, its blob must be accounted for.
51-
if [ $obj != "HEAD:1.t" ]; then
54+
if test $obj != "HEAD:1.t"
55+
then
5256
echo $(git rev-parse HEAD:1.t) >>expect.raw &&
5357
echo $(git rev-parse HEAD:2.t) >>expect.raw
5458
fi &&
@@ -77,4 +81,69 @@ do
7781
done
7882
done
7983

84+
for missing_tip in "annot_tag" "regul_tag" "a_branch" "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
85+
do
86+
# We want to check that things work when both
87+
# - all the tips passed are missing (case existing_tip = ""), and
88+
# - there is one missing tip and one existing tip (case existing_tip = "HEAD")
89+
for existing_tip in "" "HEAD"
90+
do
91+
for action in "allow-any" "print"
92+
do
93+
test_expect_success "--missing=$action with tip '$missing_tip' missing and tip '$existing_tip'" '
94+
# Before the object is made missing, we use rev-list to
95+
# get the expected oids.
96+
if test "$existing_tip" = "HEAD"
97+
then
98+
git rev-list --objects --no-object-names \
99+
HEAD ^$missing_tip >expect.raw
100+
else
101+
>expect.raw
102+
fi &&
103+
104+
# Blobs are shared by all commits, so even though a commit/tree
105+
# might be skipped, its blob must be accounted for.
106+
if test "$existing_tip" = "HEAD" && test $missing_tip != "HEAD:1.t"
107+
then
108+
echo $(git rev-parse HEAD:1.t) >>expect.raw &&
109+
echo $(git rev-parse HEAD:2.t) >>expect.raw
110+
fi &&
111+
112+
missing_oid="$(git rev-parse $missing_tip)" &&
113+
114+
if test "$missing_tip" = "annot_tag"
115+
then
116+
oid="$(git rev-parse $missing_tip^{commit})" &&
117+
echo "$missing_oid" >>expect.raw
118+
else
119+
oid="$missing_oid"
120+
fi &&
121+
122+
path=".git/objects/$(test_oid_to_path $oid)" &&
123+
124+
mv "$path" "$path.hidden" &&
125+
test_when_finished "mv $path.hidden $path" &&
126+
127+
git rev-list --missing=$action --objects --no-object-names \
128+
$missing_oid $existing_tip >actual.raw &&
129+
130+
# When the action is to print, we should also add the missing
131+
# oid to the expect list.
132+
case $action in
133+
allow-any)
134+
;;
135+
print)
136+
grep ?$oid actual.raw &&
137+
echo ?$oid >>expect.raw
138+
;;
139+
esac &&
140+
141+
sort actual.raw >actual &&
142+
sort expect.raw >expect &&
143+
test_cmp expect actual
144+
'
145+
done
146+
done
147+
done
148+
80149
test_done

0 commit comments

Comments
 (0)