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()maint
commit
76d1cd8e5e
|
@ -1019,6 +1019,10 @@ Unexpected missing objects will raise an error.
|
|||
+
|
||||
The form '--missing=print' is like 'allow-any', but will also print a
|
||||
list of the missing objects. Object IDs are prefixed with a ``?'' character.
|
||||
+
|
||||
If some tips passed to the traversal are missing, they will be
|
||||
considered as missing too, and the traversal will ignore them. In case
|
||||
we cannot get their Object ID though, an error will be raised.
|
||||
|
||||
--exclude-promisor-objects::
|
||||
(For internal use only.) Prefilter object traversal at
|
||||
|
|
|
@ -545,6 +545,18 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
|||
*
|
||||
* Let "--missing" to conditionally set fetch_if_missing.
|
||||
*/
|
||||
/*
|
||||
* NEEDSWORK: These loops that attempt to find presence of
|
||||
* options without understanding that the options they are
|
||||
* skipping are broken (e.g., it would not know "--grep
|
||||
* --exclude-promisor-objects" is not triggering
|
||||
* "--exclude-promisor-objects" option). We really need
|
||||
* setup_revisions() to have a mechanism to allow and disallow
|
||||
* some sets of options for different commands (like rev-list,
|
||||
* replay, etc). Such a mechanism should do an early parsing
|
||||
* of options and be able to manage the `--missing=...` and
|
||||
* `--exclude-promisor-objects` options below.
|
||||
*/
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "--exclude-promisor-objects")) {
|
||||
|
@ -753,8 +765,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
|||
|
||||
if (arg_print_omitted)
|
||||
oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
|
||||
if (arg_missing_action == MA_PRINT)
|
||||
if (arg_missing_action == MA_PRINT) {
|
||||
oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
|
||||
/* Add missing tips */
|
||||
oidset_insert_from_set(&missing_objects, &revs.missing_commits);
|
||||
oidset_clear(&revs.missing_commits);
|
||||
}
|
||||
|
||||
traverse_commit_list_filtered(
|
||||
&revs, show_commit, show_object, &info,
|
||||
|
|
|
@ -711,15 +711,6 @@ static void filter_combine__free(void *filter_data)
|
|||
free(d);
|
||||
}
|
||||
|
||||
static void add_all(struct oidset *dest, struct oidset *src) {
|
||||
struct oidset_iter iter;
|
||||
struct object_id *src_oid;
|
||||
|
||||
oidset_iter_init(src, &iter);
|
||||
while ((src_oid = oidset_iter_next(&iter)) != NULL)
|
||||
oidset_insert(dest, src_oid);
|
||||
}
|
||||
|
||||
static void filter_combine__finalize_omits(
|
||||
struct oidset *omits,
|
||||
void *filter_data)
|
||||
|
@ -728,7 +719,7 @@ static void filter_combine__finalize_omits(
|
|||
size_t sub;
|
||||
|
||||
for (sub = 0; sub < d->nr; sub++) {
|
||||
add_all(omits, &d->sub[sub].omits);
|
||||
oidset_insert_from_set(omits, &d->sub[sub].omits);
|
||||
oidset_clear(&d->sub[sub].omits);
|
||||
}
|
||||
}
|
||||
|
|
10
oidset.c
10
oidset.c
|
@ -23,6 +23,16 @@ int oidset_insert(struct oidset *set, const struct object_id *oid)
|
|||
return !added;
|
||||
}
|
||||
|
||||
void oidset_insert_from_set(struct oidset *dest, struct oidset *src)
|
||||
{
|
||||
struct oidset_iter iter;
|
||||
struct object_id *src_oid;
|
||||
|
||||
oidset_iter_init(src, &iter);
|
||||
while ((src_oid = oidset_iter_next(&iter)))
|
||||
oidset_insert(dest, src_oid);
|
||||
}
|
||||
|
||||
int oidset_remove(struct oidset *set, const struct object_id *oid)
|
||||
{
|
||||
khiter_t pos = kh_get_oid_set(&set->set, *oid);
|
||||
|
|
6
oidset.h
6
oidset.h
|
@ -47,6 +47,12 @@ int oidset_contains(const struct oidset *set, const struct object_id *oid);
|
|||
*/
|
||||
int oidset_insert(struct oidset *set, const struct object_id *oid);
|
||||
|
||||
/**
|
||||
* Insert all the oids that are in set 'src' into set 'dest'; a copy
|
||||
* is made of each oid inserted into set 'dest'.
|
||||
*/
|
||||
void oidset_insert_from_set(struct oidset *dest, struct oidset *src);
|
||||
|
||||
/**
|
||||
* Remove the oid from the set.
|
||||
*
|
||||
|
|
24
revision.c
24
revision.c
|
@ -385,9 +385,13 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
|
|||
|
||||
if (!object) {
|
||||
if (revs->ignore_missing)
|
||||
return object;
|
||||
return NULL;
|
||||
if (revs->exclude_promisor_objects && is_promisor_object(oid))
|
||||
return NULL;
|
||||
if (revs->do_not_die_on_missing_objects) {
|
||||
oidset_insert(&revs->missing_commits, oid);
|
||||
return NULL;
|
||||
}
|
||||
die("bad object %s", name);
|
||||
}
|
||||
object->flags |= flags;
|
||||
|
@ -415,15 +419,21 @@ static struct commit *handle_commit(struct rev_info *revs,
|
|||
*/
|
||||
while (object->type == OBJ_TAG) {
|
||||
struct tag *tag = (struct tag *) object;
|
||||
struct object_id *oid;
|
||||
if (revs->tag_objects && !(flags & UNINTERESTING))
|
||||
add_pending_object(revs, object, tag->tag);
|
||||
object = parse_object(revs->repo, get_tagged_oid(tag));
|
||||
oid = get_tagged_oid(tag);
|
||||
object = parse_object(revs->repo, oid);
|
||||
if (!object) {
|
||||
if (revs->ignore_missing_links || (flags & UNINTERESTING))
|
||||
return NULL;
|
||||
if (revs->exclude_promisor_objects &&
|
||||
is_promisor_object(&tag->tagged->oid))
|
||||
return NULL;
|
||||
if (revs->do_not_die_on_missing_objects && oid) {
|
||||
oidset_insert(&revs->missing_commits, oid);
|
||||
return NULL;
|
||||
}
|
||||
die("bad object %s", oid_to_hex(&tag->tagged->oid));
|
||||
}
|
||||
object->flags |= flags;
|
||||
|
@ -1945,6 +1955,7 @@ void repo_init_revisions(struct repository *r,
|
|||
init_display_notes(&revs->notes_opt);
|
||||
list_objects_filter_init(&revs->filter);
|
||||
init_ref_exclusions(&revs->ref_excludes);
|
||||
oidset_init(&revs->missing_commits, 0);
|
||||
}
|
||||
|
||||
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
|
|||
if (revarg_opt & REVARG_COMMITTISH)
|
||||
get_sha1_flags |= GET_OID_COMMITTISH;
|
||||
|
||||
/*
|
||||
* Even if revs->do_not_die_on_missing_objects is set, we
|
||||
* should error out if we can't even get an oid, as
|
||||
* `--missing=print` should be able to report missing oids.
|
||||
*/
|
||||
if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc))
|
||||
return revs->ignore_missing ? 0 : -1;
|
||||
if (!cant_be_filename)
|
||||
verify_non_filename(revs->prefix, arg);
|
||||
object = get_reference(revs, arg, &oid, flags ^ local_flags);
|
||||
if (!object)
|
||||
return revs->ignore_missing ? 0 : -1;
|
||||
return (revs->ignore_missing || revs->do_not_die_on_missing_objects) ? 0 : -1;
|
||||
add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
|
||||
add_pending_object_with_path(revs, object, arg, oc.mode, oc.path);
|
||||
free(oc.path);
|
||||
|
@ -3828,8 +3844,6 @@ int prepare_revision_walk(struct rev_info *revs)
|
|||
FOR_EACH_OBJECT_PROMISOR_ONLY);
|
||||
}
|
||||
|
||||
oidset_init(&revs->missing_commits, 0);
|
||||
|
||||
if (!revs->reflog_info)
|
||||
prepare_to_use_bloom_filter(revs);
|
||||
if (!revs->unsorted_input)
|
||||
|
|
|
@ -10,7 +10,10 @@ TEST_PASSES_SANITIZE_LEAK=true
|
|||
test_expect_success 'create repository and alternate directory' '
|
||||
test_commit 1 &&
|
||||
test_commit 2 &&
|
||||
test_commit 3
|
||||
test_commit 3 &&
|
||||
git tag -m "tag message" annot_tag HEAD~1 &&
|
||||
git tag regul_tag HEAD~1 &&
|
||||
git branch a_branch HEAD~1
|
||||
'
|
||||
|
||||
# We manually corrupt the repository, which means that the commit-graph may
|
||||
|
@ -46,9 +49,10 @@ do
|
|||
git rev-list --objects --no-object-names \
|
||||
HEAD ^$obj >expect.raw &&
|
||||
|
||||
# Blobs are shared by all commits, so evethough a commit/tree
|
||||
# Blobs are shared by all commits, so even though a commit/tree
|
||||
# might be skipped, its blob must be accounted for.
|
||||
if [ $obj != "HEAD:1.t" ]; then
|
||||
if test $obj != "HEAD:1.t"
|
||||
then
|
||||
echo $(git rev-parse HEAD:1.t) >>expect.raw &&
|
||||
echo $(git rev-parse HEAD:2.t) >>expect.raw
|
||||
fi &&
|
||||
|
@ -77,4 +81,69 @@ do
|
|||
done
|
||||
done
|
||||
|
||||
for missing_tip in "annot_tag" "regul_tag" "a_branch" "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
|
||||
do
|
||||
# We want to check that things work when both
|
||||
# - all the tips passed are missing (case existing_tip = ""), and
|
||||
# - there is one missing tip and one existing tip (case existing_tip = "HEAD")
|
||||
for existing_tip in "" "HEAD"
|
||||
do
|
||||
for action in "allow-any" "print"
|
||||
do
|
||||
test_expect_success "--missing=$action with tip '$missing_tip' missing and tip '$existing_tip'" '
|
||||
# Before the object is made missing, we use rev-list to
|
||||
# get the expected oids.
|
||||
if test "$existing_tip" = "HEAD"
|
||||
then
|
||||
git rev-list --objects --no-object-names \
|
||||
HEAD ^$missing_tip >expect.raw
|
||||
else
|
||||
>expect.raw
|
||||
fi &&
|
||||
|
||||
# Blobs are shared by all commits, so even though a commit/tree
|
||||
# might be skipped, its blob must be accounted for.
|
||||
if test "$existing_tip" = "HEAD" && test $missing_tip != "HEAD:1.t"
|
||||
then
|
||||
echo $(git rev-parse HEAD:1.t) >>expect.raw &&
|
||||
echo $(git rev-parse HEAD:2.t) >>expect.raw
|
||||
fi &&
|
||||
|
||||
missing_oid="$(git rev-parse $missing_tip)" &&
|
||||
|
||||
if test "$missing_tip" = "annot_tag"
|
||||
then
|
||||
oid="$(git rev-parse $missing_tip^{commit})" &&
|
||||
echo "$missing_oid" >>expect.raw
|
||||
else
|
||||
oid="$missing_oid"
|
||||
fi &&
|
||||
|
||||
path=".git/objects/$(test_oid_to_path $oid)" &&
|
||||
|
||||
mv "$path" "$path.hidden" &&
|
||||
test_when_finished "mv $path.hidden $path" &&
|
||||
|
||||
git rev-list --missing=$action --objects --no-object-names \
|
||||
$missing_oid $existing_tip >actual.raw &&
|
||||
|
||||
# When the action is to print, we should also add the missing
|
||||
# oid to the expect list.
|
||||
case $action in
|
||||
allow-any)
|
||||
;;
|
||||
print)
|
||||
grep ?$oid actual.raw &&
|
||||
echo ?$oid >>expect.raw
|
||||
;;
|
||||
esac &&
|
||||
|
||||
sort actual.raw >actual &&
|
||||
sort expect.raw >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
test_done
|
||||
|
|
Loading…
Reference in New Issue