|
17 | 17 |
|
18 | 18 | static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
|
19 | 19 |
|
| 20 | +static int compare_commits_by_gen(const void *_a, const void *_b) |
| 21 | +{ |
| 22 | + const struct commit *a = *(const struct commit * const *)_a; |
| 23 | + const struct commit *b = *(const struct commit * const *)_b; |
| 24 | + |
| 25 | + timestamp_t generation_a = commit_graph_generation(a); |
| 26 | + timestamp_t generation_b = commit_graph_generation(b); |
| 27 | + |
| 28 | + if (generation_a < generation_b) |
| 29 | + return -1; |
| 30 | + if (generation_a > generation_b) |
| 31 | + return 1; |
| 32 | + if (a->date < b->date) |
| 33 | + return -1; |
| 34 | + if (a->date > b->date) |
| 35 | + return 1; |
| 36 | + return 0; |
| 37 | +} |
| 38 | + |
20 | 39 | static int queue_has_nonstale(struct prio_queue *queue)
|
21 | 40 | {
|
22 | 41 | int i;
|
@@ -156,14 +175,9 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
|
156 | 175 | return ret;
|
157 | 176 | }
|
158 | 177 |
|
159 |
| -static int remove_redundant(struct repository *r, struct commit **array, int cnt) |
| 178 | +static int remove_redundant_no_gen(struct repository *r, |
| 179 | + struct commit **array, int cnt) |
160 | 180 | {
|
161 |
| - /* |
162 |
| - * Some commit in the array may be an ancestor of |
163 |
| - * another commit. Move such commit to the end of |
164 |
| - * the array, and return the number of commits that |
165 |
| - * are independent from each other. |
166 |
| - */ |
167 | 181 | struct commit **work;
|
168 | 182 | unsigned char *redundant;
|
169 | 183 | int *filled_index;
|
@@ -209,15 +223,156 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
|
209 | 223 | for (i = filled = 0; i < cnt; i++)
|
210 | 224 | if (!redundant[i])
|
211 | 225 | array[filled++] = work[i];
|
212 |
| - for (j = filled, i = 0; i < cnt; i++) |
213 |
| - if (redundant[i]) |
214 |
| - array[j++] = work[i]; |
215 | 226 | free(work);
|
216 | 227 | free(redundant);
|
217 | 228 | free(filled_index);
|
218 | 229 | return filled;
|
219 | 230 | }
|
220 | 231 |
|
| 232 | +static int remove_redundant_with_gen(struct repository *r, |
| 233 | + struct commit **array, int cnt) |
| 234 | +{ |
| 235 | + int i, count_non_stale = 0, count_still_independent = cnt; |
| 236 | + timestamp_t min_generation = GENERATION_NUMBER_INFINITY; |
| 237 | + struct commit **walk_start, **sorted; |
| 238 | + size_t walk_start_nr = 0, walk_start_alloc = cnt; |
| 239 | + int min_gen_pos = 0; |
| 240 | + |
| 241 | + /* |
| 242 | + * Sort the input by generation number, ascending. This allows |
| 243 | + * us to increase the "min_generation" limit when we discover |
| 244 | + * the commit with lowest generation is STALE. The index |
| 245 | + * min_gen_pos points to the current position within 'array' |
| 246 | + * that is not yet known to be STALE. |
| 247 | + */ |
| 248 | + ALLOC_ARRAY(sorted, cnt); |
| 249 | + COPY_ARRAY(sorted, array, cnt); |
| 250 | + QSORT(sorted, cnt, compare_commits_by_gen); |
| 251 | + min_generation = commit_graph_generation(sorted[0]); |
| 252 | + |
| 253 | + ALLOC_ARRAY(walk_start, walk_start_alloc); |
| 254 | + |
| 255 | + /* Mark all parents of the input as STALE */ |
| 256 | + for (i = 0; i < cnt; i++) { |
| 257 | + struct commit_list *parents; |
| 258 | + |
| 259 | + repo_parse_commit(r, array[i]); |
| 260 | + array[i]->object.flags |= RESULT; |
| 261 | + parents = array[i]->parents; |
| 262 | + |
| 263 | + while (parents) { |
| 264 | + repo_parse_commit(r, parents->item); |
| 265 | + if (!(parents->item->object.flags & STALE)) { |
| 266 | + parents->item->object.flags |= STALE; |
| 267 | + ALLOC_GROW(walk_start, walk_start_nr + 1, walk_start_alloc); |
| 268 | + walk_start[walk_start_nr++] = parents->item; |
| 269 | + } |
| 270 | + parents = parents->next; |
| 271 | + } |
| 272 | + } |
| 273 | + |
| 274 | + QSORT(walk_start, walk_start_nr, compare_commits_by_gen); |
| 275 | + |
| 276 | + /* remove STALE bit for now to allow walking through parents */ |
| 277 | + for (i = 0; i < walk_start_nr; i++) |
| 278 | + walk_start[i]->object.flags &= ~STALE; |
| 279 | + |
| 280 | + /* |
| 281 | + * Start walking from the highest generation. Hopefully, it will |
| 282 | + * find all other items during the first-parent walk, and we can |
| 283 | + * terminate early. Otherwise, we will do the same amount of work |
| 284 | + * as before. |
| 285 | + */ |
| 286 | + for (i = walk_start_nr - 1; i >= 0 && count_still_independent > 1; i--) { |
| 287 | + /* push the STALE bits up to min generation */ |
| 288 | + struct commit_list *stack = NULL; |
| 289 | + |
| 290 | + commit_list_insert(walk_start[i], &stack); |
| 291 | + walk_start[i]->object.flags |= STALE; |
| 292 | + |
| 293 | + while (stack) { |
| 294 | + struct commit_list *parents; |
| 295 | + struct commit *c = stack->item; |
| 296 | + |
| 297 | + repo_parse_commit(r, c); |
| 298 | + |
| 299 | + if (c->object.flags & RESULT) { |
| 300 | + c->object.flags &= ~RESULT; |
| 301 | + if (--count_still_independent <= 1) |
| 302 | + break; |
| 303 | + if (oideq(&c->object.oid, &sorted[min_gen_pos]->object.oid)) { |
| 304 | + while (min_gen_pos < cnt - 1 && |
| 305 | + (sorted[min_gen_pos]->object.flags & STALE)) |
| 306 | + min_gen_pos++; |
| 307 | + min_generation = commit_graph_generation(sorted[min_gen_pos]); |
| 308 | + } |
| 309 | + } |
| 310 | + |
| 311 | + if (commit_graph_generation(c) < min_generation) { |
| 312 | + pop_commit(&stack); |
| 313 | + continue; |
| 314 | + } |
| 315 | + |
| 316 | + parents = c->parents; |
| 317 | + while (parents) { |
| 318 | + if (!(parents->item->object.flags & STALE)) { |
| 319 | + parents->item->object.flags |= STALE; |
| 320 | + commit_list_insert(parents->item, &stack); |
| 321 | + break; |
| 322 | + } |
| 323 | + parents = parents->next; |
| 324 | + } |
| 325 | + |
| 326 | + /* pop if all parents have been visited already */ |
| 327 | + if (!parents) |
| 328 | + pop_commit(&stack); |
| 329 | + } |
| 330 | + free_commit_list(stack); |
| 331 | + } |
| 332 | + free(sorted); |
| 333 | + |
| 334 | + /* clear result */ |
| 335 | + for (i = 0; i < cnt; i++) |
| 336 | + array[i]->object.flags &= ~RESULT; |
| 337 | + |
| 338 | + /* rearrange array */ |
| 339 | + for (i = count_non_stale = 0; i < cnt; i++) { |
| 340 | + if (!(array[i]->object.flags & STALE)) |
| 341 | + array[count_non_stale++] = array[i]; |
| 342 | + } |
| 343 | + |
| 344 | + /* clear marks */ |
| 345 | + clear_commit_marks_many(walk_start_nr, walk_start, STALE); |
| 346 | + free(walk_start); |
| 347 | + |
| 348 | + return count_non_stale; |
| 349 | +} |
| 350 | + |
| 351 | +static int remove_redundant(struct repository *r, struct commit **array, int cnt) |
| 352 | +{ |
| 353 | + /* |
| 354 | + * Some commit in the array may be an ancestor of |
| 355 | + * another commit. Move the independent commits to the |
| 356 | + * beginning of 'array' and return their number. Callers |
| 357 | + * should not rely upon the contents of 'array' after |
| 358 | + * that number. |
| 359 | + */ |
| 360 | + if (generation_numbers_enabled(r)) { |
| 361 | + int i; |
| 362 | + |
| 363 | + /* |
| 364 | + * If we have a single commit with finite generation |
| 365 | + * number, then the _with_gen algorithm is preferred. |
| 366 | + */ |
| 367 | + for (i = 0; i < cnt; i++) { |
| 368 | + if (commit_graph_generation(array[i]) < GENERATION_NUMBER_INFINITY) |
| 369 | + return remove_redundant_with_gen(r, array, cnt); |
| 370 | + } |
| 371 | + } |
| 372 | + |
| 373 | + return remove_redundant_no_gen(r, array, cnt); |
| 374 | +} |
| 375 | + |
221 | 376 | static struct commit_list *get_merge_bases_many_0(struct repository *r,
|
222 | 377 | struct commit *one,
|
223 | 378 | int n,
|
@@ -561,21 +716,6 @@ int commit_contains(struct ref_filter *filter, struct commit *commit,
|
561 | 716 | return repo_is_descendant_of(the_repository, commit, list);
|
562 | 717 | }
|
563 | 718 |
|
564 |
| -static int compare_commits_by_gen(const void *_a, const void *_b) |
565 |
| -{ |
566 |
| - const struct commit *a = *(const struct commit * const *)_a; |
567 |
| - const struct commit *b = *(const struct commit * const *)_b; |
568 |
| - |
569 |
| - timestamp_t generation_a = commit_graph_generation(a); |
570 |
| - timestamp_t generation_b = commit_graph_generation(b); |
571 |
| - |
572 |
| - if (generation_a < generation_b) |
573 |
| - return -1; |
574 |
| - if (generation_a > generation_b) |
575 |
| - return 1; |
576 |
| - return 0; |
577 |
| -} |
578 |
| - |
579 | 719 | int can_all_from_reach_with_flag(struct object_array *from,
|
580 | 720 | unsigned int with_flag,
|
581 | 721 | unsigned int assign_flag,
|
|
0 commit comments