Merge branch 'ds/add-missing-tags'
The history traversal used to implement the tag-following has been optimized by introducing a new helper. * ds/add-missing-tags: remote: make add_missing_tags() linear test-reach: test get_reachable_subset commit-reach: implement get_reachable_subset
This commit is contained in:
commit
291123e69b
@ -690,3 +690,72 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
|
||||
object_array_clear(&from_objs);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
|
||||
struct commit **to, int nr_to,
|
||||
unsigned int reachable_flag)
|
||||
{
|
||||
struct commit **item;
|
||||
struct commit *current;
|
||||
struct commit_list *found_commits = NULL;
|
||||
struct commit **to_last = to + nr_to;
|
||||
struct commit **from_last = from + nr_from;
|
||||
uint32_t min_generation = GENERATION_NUMBER_INFINITY;
|
||||
int num_to_find = 0;
|
||||
|
||||
struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
|
||||
|
||||
for (item = to; item < to_last; item++) {
|
||||
struct commit *c = *item;
|
||||
|
||||
parse_commit(c);
|
||||
if (c->generation < min_generation)
|
||||
min_generation = c->generation;
|
||||
|
||||
if (!(c->object.flags & PARENT1)) {
|
||||
c->object.flags |= PARENT1;
|
||||
num_to_find++;
|
||||
}
|
||||
}
|
||||
|
||||
for (item = from; item < from_last; item++) {
|
||||
struct commit *c = *item;
|
||||
if (!(c->object.flags & PARENT2)) {
|
||||
c->object.flags |= PARENT2;
|
||||
parse_commit(c);
|
||||
|
||||
prio_queue_put(&queue, *item);
|
||||
}
|
||||
}
|
||||
|
||||
while (num_to_find && (current = prio_queue_get(&queue)) != NULL) {
|
||||
struct commit_list *parents;
|
||||
|
||||
if (current->object.flags & PARENT1) {
|
||||
current->object.flags &= ~PARENT1;
|
||||
current->object.flags |= reachable_flag;
|
||||
commit_list_insert(current, &found_commits);
|
||||
num_to_find--;
|
||||
}
|
||||
|
||||
for (parents = current->parents; parents; parents = parents->next) {
|
||||
struct commit *p = parents->item;
|
||||
|
||||
parse_commit(p);
|
||||
|
||||
if (p->generation < min_generation)
|
||||
continue;
|
||||
|
||||
if (p->object.flags & PARENT2)
|
||||
continue;
|
||||
|
||||
p->object.flags |= PARENT2;
|
||||
prio_queue_put(&queue, p);
|
||||
}
|
||||
}
|
||||
|
||||
clear_commit_marks_many(nr_to, to, PARENT1);
|
||||
clear_commit_marks_many(nr_from, from, PARENT2);
|
||||
|
||||
return found_commits;
|
||||
}
|
||||
|
@ -75,4 +75,17 @@ int can_all_from_reach_with_flag(struct object_array *from,
|
||||
int can_all_from_reach(struct commit_list *from, struct commit_list *to,
|
||||
int commit_date_cutoff);
|
||||
|
||||
|
||||
/*
|
||||
* Return a list of commits containing the commits in the 'to' array
|
||||
* that are reachable from at least one commit in the 'from' array.
|
||||
* Also add the given 'flag' to each of the commits in the returned list.
|
||||
*
|
||||
* This method uses the PARENT1 and PARENT2 flags during its operation,
|
||||
* so be sure these flags are not set before calling the method.
|
||||
*/
|
||||
struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
|
||||
struct commit **to, int nr_to,
|
||||
unsigned int reachable_flag);
|
||||
|
||||
#endif
|
||||
|
34
remote.c
34
remote.c
@ -1205,9 +1205,36 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
|
||||
* sent to the other side.
|
||||
*/
|
||||
if (sent_tips.nr) {
|
||||
const int reachable_flag = 1;
|
||||
struct commit_list *found_commits;
|
||||
struct commit **src_commits;
|
||||
int nr_src_commits = 0, alloc_src_commits = 16;
|
||||
ALLOC_ARRAY(src_commits, alloc_src_commits);
|
||||
|
||||
for_each_string_list_item(item, &src_tag) {
|
||||
struct ref *ref = item->util;
|
||||
struct commit *commit;
|
||||
|
||||
if (is_null_oid(&ref->new_oid))
|
||||
continue;
|
||||
commit = lookup_commit_reference_gently(the_repository,
|
||||
&ref->new_oid,
|
||||
1);
|
||||
if (!commit)
|
||||
/* not pushing a commit, which is not an error */
|
||||
continue;
|
||||
|
||||
ALLOC_GROW(src_commits, nr_src_commits + 1, alloc_src_commits);
|
||||
src_commits[nr_src_commits++] = commit;
|
||||
}
|
||||
|
||||
found_commits = get_reachable_subset(sent_tips.tip, sent_tips.nr,
|
||||
src_commits, nr_src_commits,
|
||||
reachable_flag);
|
||||
|
||||
for_each_string_list_item(item, &src_tag) {
|
||||
struct ref *dst_ref;
|
||||
struct ref *ref = item->util;
|
||||
struct commit *commit;
|
||||
|
||||
if (is_null_oid(&ref->new_oid))
|
||||
@ -1223,7 +1250,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
|
||||
* Is this tag, which they do not have, reachable from
|
||||
* any of the commits we are sending?
|
||||
*/
|
||||
if (!in_merge_bases_many(commit, sent_tips.nr, sent_tips.tip))
|
||||
if (!(commit->object.flags & reachable_flag))
|
||||
continue;
|
||||
|
||||
/* Add it in */
|
||||
@ -1231,7 +1258,12 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
|
||||
oidcpy(&dst_ref->new_oid, &ref->new_oid);
|
||||
dst_ref->peer_ref = copy_ref(ref);
|
||||
}
|
||||
|
||||
clear_commit_marks_many(nr_src_commits, src_commits, reachable_flag);
|
||||
free(src_commits);
|
||||
free_commit_list(found_commits);
|
||||
}
|
||||
|
||||
string_list_clear(&src_tag, 0);
|
||||
free(sent_tips.tip);
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ int cmd__reach(int ac, const char **av)
|
||||
struct commit *A, *B;
|
||||
struct commit_list *X, *Y;
|
||||
struct object_array X_obj = OBJECT_ARRAY_INIT;
|
||||
struct commit **X_array;
|
||||
int X_nr, X_alloc;
|
||||
struct commit **X_array, **Y_array;
|
||||
int X_nr, X_alloc, Y_nr, Y_alloc;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct repository *r = the_repository;
|
||||
|
||||
@ -44,9 +44,10 @@ int cmd__reach(int ac, const char **av)
|
||||
|
||||
A = B = NULL;
|
||||
X = Y = NULL;
|
||||
X_nr = 0;
|
||||
X_alloc = 16;
|
||||
X_nr = Y_nr = 0;
|
||||
X_alloc = Y_alloc = 16;
|
||||
ALLOC_ARRAY(X_array, X_alloc);
|
||||
ALLOC_ARRAY(Y_array, Y_alloc);
|
||||
|
||||
while (strbuf_getline(&buf, stdin) != EOF) {
|
||||
struct object_id oid;
|
||||
@ -92,6 +93,8 @@ int cmd__reach(int ac, const char **av)
|
||||
|
||||
case 'Y':
|
||||
commit_list_insert(c, &Y);
|
||||
ALLOC_GROW(Y_array, Y_nr + 1, Y_alloc);
|
||||
Y_array[Y_nr++] = c;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -136,6 +139,29 @@ int cmd__reach(int ac, const char **av)
|
||||
filter.with_commit_tag_algo = 0;
|
||||
|
||||
printf("%s(_,A,X,_):%d\n", av[1], commit_contains(&filter, A, X, &cache));
|
||||
} else if (!strcmp(av[1], "get_reachable_subset")) {
|
||||
const int reachable_flag = 1;
|
||||
int i, count = 0;
|
||||
struct commit_list *current;
|
||||
struct commit_list *list = get_reachable_subset(X_array, X_nr,
|
||||
Y_array, Y_nr,
|
||||
reachable_flag);
|
||||
printf("get_reachable_subset(X,Y)\n");
|
||||
for (current = list; current; current = current->next) {
|
||||
if (!(list->item->object.flags & reachable_flag))
|
||||
die(_("commit %s is not marked reachable"),
|
||||
oid_to_hex(&list->item->object.oid));
|
||||
count++;
|
||||
}
|
||||
for (i = 0; i < Y_nr; i++) {
|
||||
if (Y_array[i]->object.flags & reachable_flag)
|
||||
count--;
|
||||
}
|
||||
|
||||
if (count < 0)
|
||||
die(_("too many commits marked reachable"));
|
||||
|
||||
print_sorted_commit_ids(list);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
@ -265,4 +265,56 @@ test_expect_success 'commit_contains:miss' '
|
||||
test_three_modes commit_contains --tag
|
||||
'
|
||||
|
||||
test_expect_success 'get_reachable_subset:all' '
|
||||
cat >input <<-\EOF &&
|
||||
X:commit-9-1
|
||||
X:commit-8-3
|
||||
X:commit-7-5
|
||||
X:commit-6-6
|
||||
X:commit-1-7
|
||||
Y:commit-3-3
|
||||
Y:commit-1-7
|
||||
Y:commit-5-6
|
||||
EOF
|
||||
(
|
||||
echo "get_reachable_subset(X,Y)" &&
|
||||
git rev-parse commit-3-3 \
|
||||
commit-1-7 \
|
||||
commit-5-6 | sort
|
||||
) >expect &&
|
||||
test_three_modes get_reachable_subset
|
||||
'
|
||||
|
||||
test_expect_success 'get_reachable_subset:some' '
|
||||
cat >input <<-\EOF &&
|
||||
X:commit-9-1
|
||||
X:commit-8-3
|
||||
X:commit-7-5
|
||||
X:commit-1-7
|
||||
Y:commit-3-3
|
||||
Y:commit-1-7
|
||||
Y:commit-5-6
|
||||
EOF
|
||||
(
|
||||
echo "get_reachable_subset(X,Y)" &&
|
||||
git rev-parse commit-3-3 \
|
||||
commit-1-7 | sort
|
||||
) >expect &&
|
||||
test_three_modes get_reachable_subset
|
||||
'
|
||||
|
||||
test_expect_success 'get_reachable_subset:none' '
|
||||
cat >input <<-\EOF &&
|
||||
X:commit-9-1
|
||||
X:commit-8-3
|
||||
X:commit-7-5
|
||||
X:commit-1-7
|
||||
Y:commit-9-3
|
||||
Y:commit-7-6
|
||||
Y:commit-2-8
|
||||
EOF
|
||||
echo "get_reachable_subset(X,Y)" >expect &&
|
||||
test_three_modes get_reachable_subset
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user